summaryrefslogtreecommitdiff
path: root/miniport/qxl.c
diff options
context:
space:
mode:
Diffstat (limited to 'miniport/qxl.c')
-rw-r--r--miniport/qxl.c950
1 files changed, 950 insertions, 0 deletions
diff --git a/miniport/qxl.c b/miniport/qxl.c
new file mode 100644
index 0000000..c4d2888
--- /dev/null
+++ b/miniport/qxl.c
@@ -0,0 +1,950 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "os_dep.h"
+#include "qxl.h"
+#if (WINVER < 0x0501)
+#include "wdmhelper.h"
+#endif
+
+VP_STATUS FindAdapter(PVOID dev_extension,
+ PVOID reserved,
+ PWSTR arg_str,
+ PVIDEO_PORT_CONFIG_INFO conf_info,
+ PUCHAR again);
+
+BOOLEAN Initialize(PVOID dev_extension);
+
+VP_STATUS GetPowerState(PVOID dev_extension,
+ ULONG hw_id,
+ PVIDEO_POWER_MANAGEMENT state);
+
+VP_STATUS SetPowerState(PVOID dev_extension,
+ ULONG hw_wId,
+ PVIDEO_POWER_MANAGEMENT state);
+
+VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
+ IN PVIDEO_CHILD_ENUM_INFO enum_info,
+ OUT PVIDEO_CHILD_TYPE type,
+ OUT PUCHAR descriptor,
+ OUT PULONG uid,
+ OUT PULONG unused);
+
+BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet);
+
+BOOLEAN Interrupt(PVOID HwDeviceExtension);
+
+#if defined(ALLOC_PRAGMA)
+#pragma alloc_text(PAGE, DriverEntry)
+#pragma alloc_text(PAGE, FindAdapter)
+#pragma alloc_text(PAGE, Initialize)
+#pragma alloc_text(PAGE, GetPowerState)
+#pragma alloc_text(PAGE, SetPowerState)
+#pragma alloc_text(PAGE, GetChildDescriptor)
+#pragma alloc_text(PAGE, StartIO)
+#endif
+
+typedef struct QXLExtension {
+ PVOID io_base;
+ ULONG io_port;
+
+ QXLRom *rom;
+ ULONG rom_size;
+
+ PHYSICAL_ADDRESS ram_physical;
+ UINT8 *ram_start;
+ QXLRam *ram_header;
+ ULONG ram_size;
+
+ PHYSICAL_ADDRESS vram_physical;
+ ULONG vram_size;
+
+ ULONG n_modes;
+ PVIDEO_MODE_INFORMATION modes;
+
+ PEVENT display_event;
+ PEVENT cursor_event;
+ PEVENT sleep_event;
+
+} QXLExtension;
+
+#define QXL_ALLOC_TAG '_lxq'
+
+
+ULONG DriverEntry(PVOID context1, PVOID context2)
+{
+ VIDEO_HW_INITIALIZATION_DATA init_data;
+ ULONG ret;
+
+ PAGED_CODE();
+
+ DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+
+ VideoPortZeroMemory(&init_data, sizeof(VIDEO_HW_INITIALIZATION_DATA));
+ init_data.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
+ init_data.HwDeviceExtensionSize = sizeof(QXLExtension);
+
+ init_data.HwFindAdapter = FindAdapter;
+ init_data.HwInitialize = Initialize;
+ init_data.HwGetPowerState = GetPowerState;
+ init_data.HwSetPowerState = SetPowerState;
+ init_data.HwGetVideoChildDescriptor = GetChildDescriptor;
+ init_data.HwStartIO = StartIO;
+ init_data.HwInterrupt = Interrupt;
+
+ ret = VideoPortInitialize(context1, context2, &init_data, NULL);
+
+ if (ret != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: try W2K %u\n", __FUNCTION__, ret));
+ init_data.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
+ ret = VideoPortInitialize(context1, context2, &init_data, NULL);
+ }
+ DEBUG_PRINT((0, "%s: exit %u\n", __FUNCTION__, ret));
+ return ret;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitIO)
+#endif
+
+VP_STATUS InitIO(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+ PVOID io_base;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ if (range->RangeLength < QXL_IO_RANGE_SIZE
+ || !range->RangeInIoSpace) {
+ DEBUG_PRINT((0, "%s: bad io range\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+
+ io_base = VideoPortGetDeviceBase(dev, range->RangeStart, range->RangeLength,
+ range->RangeInIoSpace);
+
+ if (!io_base) {
+ DEBUG_PRINT((0, "%s: get io base failed\n", __FUNCTION__));
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ dev->io_base = io_base;
+ dev->io_port = range->RangeStart.LowPart;
+
+ DEBUG_PRINT((0, "%s: OK, io 0x%x size %lu\n", __FUNCTION__,
+ (ULONG)range->RangeStart.LowPart, range->RangeLength));
+
+ return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitRom)
+#endif
+
+VP_STATUS InitRom(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+ PVOID rom = NULL;
+ ULONG rom_size = range->RangeLength;
+ ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
+ VP_STATUS error;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ if (rom_size < sizeof(QXLRom) || range->RangeInIoSpace) {
+ DEBUG_PRINT((0, "%s: bad rom range\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+ if ((error = VideoPortMapMemory(dev, range->RangeStart,
+ &rom_size, &io_space,
+ &rom)) != NO_ERROR ) {
+ DEBUG_PRINT((0, "%s: map rom filed\n", __FUNCTION__));
+ return error;
+ }
+
+ if (rom_size < range->RangeLength) {
+ DEBUG_PRINT((0, "%s: short rom map\n", __FUNCTION__));
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+
+ if (((QXLRom*)rom)->magic != QXL_ROM_MAGIC) {
+ DEBUG_PRINT((0, "%s: bad rom magic\n", __FUNCTION__));
+ error = ERROR_INVALID_DATA;
+ goto err;
+ }
+
+ dev->rom = rom;
+ dev->rom_size = range->RangeLength;
+ DEBUG_PRINT((0, "%s OK: rom 0x%lx size %lu\n",
+ __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
+ return NO_ERROR;
+
+ err:
+ VideoPortUnmapMemory(dev, rom, NULL);
+ DEBUG_PRINT((0, "%s ERR\n", __FUNCTION__));
+ return error;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitRam)
+#endif
+
+VP_STATUS InitRam(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+ UINT8 *ram = NULL;
+ QXLRam *ram_header;
+ ULONG ram_size = range->RangeLength;
+ ULONG io_space = VIDEO_MEMORY_SPACE_MEMORY;
+ VP_STATUS error;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ if (ram_size < sizeof(QXLRam) + dev->rom->ram_header_offset || range->RangeInIoSpace) {
+ DEBUG_PRINT((0, "%s: bad ram range\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+
+ if (ram_size < dev->rom->pages_offset + (dev->rom->num_io_pages << PAGE_SHIFT) ) {
+ DEBUG_PRINT((0, "%s: bad ram size\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+
+ if ((error = VideoPortMapMemory(dev, range->RangeStart,
+ &ram_size, &io_space,
+ &ram)) != NO_ERROR ) {
+ DEBUG_PRINT((0, "%s: map ram filed\n", __FUNCTION__));
+ return error;
+ }
+
+ if (ram_size < range->RangeLength) {
+ DEBUG_PRINT((0, "%s: short ram map\n", __FUNCTION__));
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+ ram_header = (QXLRam *)(ram + dev->rom->ram_header_offset);
+ if (ram_header->magic != QXL_RAM_MAGIC) {
+ DEBUG_PRINT((0, "%s: bad ram magic\n", __FUNCTION__));
+ error = ERROR_INVALID_DATA;
+ goto err;
+ }
+
+ dev->ram_physical = range->RangeStart;
+ dev->ram_start = ram;
+ dev->ram_header = ram_header;
+ dev->ram_size = range->RangeLength;
+ DEBUG_PRINT((0, "%s OK: ram 0x%lx size %lu\n",
+ __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
+ return NO_ERROR;
+
+ err:
+ VideoPortUnmapMemory(dev, ram, NULL);
+ DEBUG_PRINT((0, "%s ERR\n", __FUNCTION__));
+ return error;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range);
+#pragma alloc_text(PAGE, InitVRAM)
+#endif
+
+VP_STATUS InitVRAM(QXLExtension *dev, PVIDEO_ACCESS_RANGE range)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ if (range->RangeLength == 0 || range->RangeInIoSpace) {
+ DEBUG_PRINT((0, "%s: bad mem range\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+
+ dev->vram_physical = range->RangeStart;
+ dev->vram_size = range->RangeLength;
+ DEBUG_PRINT((0, "%s: OK, vram 0x%lx size %lu\n",
+ __FUNCTION__, (ULONG)range->RangeStart.QuadPart, range->RangeLength));
+ return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
+ PVIDEO_ACCESS_RANGE ranges, int n_ranges);
+#pragma alloc_text(PAGE, Prob)
+#endif
+
+VP_STATUS Prob(QXLExtension *dev, VIDEO_PORT_CONFIG_INFO *conf_info,
+ PVIDEO_ACCESS_RANGE ranges, int n_ranges)
+{
+ PCI_COMMON_CONFIG pci_conf;
+ ULONG bus_data_size;
+ VP_STATUS error;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ bus_data_size = VideoPortGetBusData(dev,
+ PCIConfiguration,
+ 0,
+ &pci_conf,
+ 0,
+ sizeof(PCI_COMMON_CONFIG));
+
+ if (bus_data_size != sizeof(PCI_COMMON_CONFIG)) {
+ DEBUG_PRINT((0, "%s: GetBusData size %d expectes %d\n",
+ __FUNCTION__, bus_data_size, sizeof(PCI_COMMON_CONFIG)));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (pci_conf.VendorID != REDHAT_PCI_VENDOR_ID) {
+ DEBUG_PRINT((0, "%s: bad vendor id 0x%x expectes 0x%x\n",
+ __FUNCTION__, pci_conf.VendorID, REDHAT_PCI_VENDOR_ID));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (pci_conf.DeviceID != QXL_DEVICE_ID) {
+ DEBUG_PRINT((0, "%s: bad vendor id 0x%x expectes 0x%x\n",
+ __FUNCTION__, pci_conf.DeviceID, QXL_DEVICE_ID));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (pci_conf.RevisionID != QXL_REVISION) {
+ DEBUG_PRINT((0, "%s: bad revision 0x%x expectes 0x%x\n",
+ __FUNCTION__, pci_conf.RevisionID, QXL_REVISION));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ VideoPortZeroMemory(ranges, sizeof(VIDEO_ACCESS_RANGE) * n_ranges);
+ if ((error = VideoPortGetAccessRanges(dev, 0, NULL, n_ranges,
+ ranges, NULL, NULL,
+ NULL)) != NO_ERROR ) {
+ DEBUG_PRINT((0, "%s: get access ranges failed status %u\n", __FUNCTION__, error));
+ }
+
+ if (conf_info->BusInterruptLevel == 0 && conf_info->BusInterruptVector == 0) {
+ DEBUG_PRINT((0, "%s: no interrupt\n", __FUNCTION__));
+ error = ERROR_INVALID_DATA;
+ }
+
+#ifdef DBG
+ if (error == NO_ERROR) {
+ int i;
+
+ DEBUG_PRINT((0, "%s: interrupt: vector %lu level %lu mode %s\n",
+ __FUNCTION__,
+ conf_info->BusInterruptVector,
+ conf_info->BusInterruptLevel,
+ (conf_info->InterruptMode == LevelSensitive) ? "LevelSensitive" : "Latched"));
+
+ for (i = 0; i < n_ranges; i++) {
+ DEBUG_PRINT((0, "%s: range %d start 0x%lx length %lu space %lu\n", __FUNCTION__, i,
+ (ULONG)ranges[i].RangeStart.QuadPart,
+ ranges[i].RangeLength,
+ (ULONG)ranges[i].RangeInIoSpace));
+ }
+ }
+#endif
+
+ DEBUG_PRINT((0, "%s exit %lu\n", __FUNCTION__, error));
+ return error;
+}
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode);
+#pragma alloc_text(PAGE, SetVideoModeInfo)
+#endif
+
+VP_STATUS SetVideoModeInfo(PVIDEO_MODE_INFORMATION video_mode, QXLMode *qxl_mode)
+{
+ ULONG color_bits;
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s: x %u y %u bits %u stride %u orientation %u\n",
+ __FUNCTION__, qxl_mode->x_res, qxl_mode->y_res,
+ qxl_mode->bits, qxl_mode->stride, qxl_mode->orientation));
+
+ video_mode->Length = sizeof(VIDEO_MODE_INFORMATION);
+ video_mode->ModeIndex = qxl_mode->id;
+ video_mode->VisScreenWidth = qxl_mode->x_res;
+ video_mode->VisScreenHeight = qxl_mode->y_res;
+ video_mode->ScreenStride = qxl_mode->stride;
+ video_mode->NumberOfPlanes = 1;
+ video_mode->BitsPerPlane = qxl_mode->bits;
+ video_mode->Frequency = 100;
+ video_mode->XMillimeter = qxl_mode->x_mili;
+ video_mode->YMillimeter = qxl_mode->y_mili;
+ color_bits = (qxl_mode->bits == 16) ? 5 : 8;
+ video_mode->NumberRedBits = color_bits;
+ video_mode->NumberGreenBits = color_bits;
+ video_mode->NumberBlueBits = color_bits;
+
+ video_mode->BlueMask = (1 << color_bits) - 1;
+ video_mode->GreenMask = video_mode->BlueMask << color_bits;
+ video_mode->RedMask = video_mode->GreenMask << color_bits;
+
+ video_mode->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS;
+ video_mode->VideoMemoryBitmapWidth = qxl_mode->x_res;
+ video_mode->VideoMemoryBitmapHeight = qxl_mode->y_res;
+ video_mode->DriverSpecificAttributeFlags = qxl_mode->orientation;
+ DEBUG_PRINT((0, "%s OK\n", __FUNCTION__));
+ return NO_ERROR;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+VP_STATUS InitModes(QXLExtension *dev);
+#pragma alloc_text(PAGE, InitModes)
+#endif
+
+VP_STATUS InitModes(QXLExtension *dev)
+{
+ QXLRom *rom;
+ QXLModes *modes;
+ PVIDEO_MODE_INFORMATION modes_info;
+ ULONG n_modes;
+ ULONG i;
+ VP_STATUS error;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+ rom = dev->rom;
+ modes = (QXLModes *)((UCHAR*)rom + rom->modes_offset);
+ if (dev->rom_size < rom->modes_offset + sizeof(QXLModes) ||
+ (n_modes = modes->n_modes) == 0 || dev->rom_size <
+ rom->modes_offset + sizeof(QXLModes) + n_modes * sizeof(QXLMode)) {
+ DEBUG_PRINT((0, "%s: bad rom size\n", __FUNCTION__));
+ return ERROR_INVALID_DATA;
+ }
+
+#if (WINVER < 0x0501) //Win2K
+ error = VideoPortAllocateBuffer(dev, n_modes * sizeof(VIDEO_MODE_INFORMATION), &modes_info);
+
+ if(!modes_info || error != NO_ERROR) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+#else
+ if (!(modes_info = VideoPortAllocatePool(dev, VpPagedPool,
+ n_modes * sizeof(VIDEO_MODE_INFORMATION),
+ QXL_ALLOC_TAG))) {
+ DEBUG_PRINT((0, "%s: alloc mem failed\n", __FUNCTION__));
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+#endif
+ VideoPortZeroMemory(modes_info, sizeof(VIDEO_MODE_INFORMATION) * n_modes);
+ for (i = 0; i < n_modes; i++) {
+ error = SetVideoModeInfo(&modes_info[i], &modes->modes[i]);
+ if (error != NO_ERROR) {
+ VideoPortFreePool(dev, modes_info);
+ DEBUG_PRINT((0, "%s: set video mode failed\n", __FUNCTION__));
+ return error;
+ }
+ }
+ dev->n_modes = n_modes;
+ dev->modes = modes_info;
+ DEBUG_PRINT((0, "%s OK\n", __FUNCTION__));
+ return NO_ERROR;
+}
+
+#if defined(ALLOC_PRAGMA)
+void DevExternsionCleanup(QXLExtension *dev);
+#pragma alloc_text(PAGE, DevExternsionCleanup)
+#endif
+
+void DevExternsionCleanup(QXLExtension *dev)
+{
+ if (dev->sleep_event) {
+ VideoPortDeleteEvent(dev, dev->sleep_event);
+ }
+
+ if (dev->cursor_event) {
+ VideoPortDeleteEvent(dev, dev->cursor_event);
+ }
+
+ if (dev->display_event) {
+ VideoPortDeleteEvent(dev, dev->display_event);
+ }
+
+ if (dev->rom) {
+ VideoPortUnmapMemory(dev, dev->rom, NULL);
+ }
+
+ if (dev->ram_start) {
+ VideoPortUnmapMemory(dev, dev->ram_start, NULL);
+ }
+
+ if (dev->modes) {
+ VideoPortFreePool(dev, dev->modes);
+ }
+
+ VideoPortZeroMemory(dev, sizeof(QXLExtension));
+}
+
+VP_STATUS FindAdapter(PVOID dev_extension,
+ PVOID reserved,
+ PWSTR arg_str,
+ PVIDEO_PORT_CONFIG_INFO conf_info,
+ PUCHAR again)
+{
+ QXLExtension *dev_ext = dev_extension;
+ VP_STATUS status;
+ VIDEO_ACCESS_RANGE ranges[QXL_PCI_RANGES];
+ PEVENT display_event = NULL;
+ PEVENT cursor_event = NULL;
+ PEVENT sleep_event = NULL;
+#if (WINVER >= 0x0501)
+ VPOSVERSIONINFO sys_info;
+#endif
+
+ PAGED_CODE();
+
+ DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+
+#if (WINVER >= 0x0501)
+ VideoPortZeroMemory(&sys_info, sizeof(VPOSVERSIONINFO));
+ sys_info.Size = sizeof(VPOSVERSIONINFO);
+ if ((status = VideoPortGetVersion(dev_ext, &sys_info)) != NO_ERROR ||
+ sys_info.MajorVersion < 5 || (sys_info.MajorVersion == 5 && sys_info.MinorVersion < 1) ) {
+ DEBUG_PRINT((0, "%s: err not supported, status %lu major %lu minor %lu\n",
+ __FUNCTION__, status, sys_info.MajorVersion, sys_info.MinorVersion));
+ return ERROR_NOT_SUPPORTED;
+ }
+#endif
+
+ if (conf_info->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {
+ DEBUG_PRINT((0, "%s: err configInfo size\n", __FUNCTION__));
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (conf_info->AdapterInterfaceType != PCIBus) {
+ DEBUG_PRINT((0, "%s: not a PCI device %d\n",
+ __FUNCTION__, conf_info->AdapterInterfaceType));
+ return ERROR_DEV_NOT_EXIST;
+ }
+
+ if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &display_event)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: create display event failed %lu\n",
+ __FUNCTION__, status));
+ return status;
+ }
+
+ if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &cursor_event)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: create cursor event failed %lu\n",
+ __FUNCTION__, status));
+ VideoPortDeleteEvent(dev_ext, display_event);
+ return status;
+ }
+
+ if ((status = VideoPortCreateEvent(dev_ext, 0, NULL, &sleep_event)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: create sleep event failed %lu\n",
+ __FUNCTION__, status));
+ VideoPortDeleteEvent(dev_ext, display_event);
+ VideoPortDeleteEvent(dev_ext, cursor_event);
+ return status;
+ }
+
+ dev_ext->display_event = display_event;
+ dev_ext->cursor_event = cursor_event;
+ dev_ext->sleep_event = sleep_event;
+
+ if ((status = Prob(dev_ext, conf_info, ranges, QXL_PCI_RANGES)) != NO_ERROR ||
+ (status = InitIO(dev_ext, &ranges[QXL_IO_RANGE_INDEX])) != NO_ERROR ||
+ (status = InitRom(dev_ext, &ranges[QXL_ROM_RANGE_INDEX])) != NO_ERROR ||
+ (status = InitRam(dev_ext, &ranges[QXL_RAM_RANGE_INDEX])) != NO_ERROR ||
+ (status = InitVRAM(dev_ext, &ranges[QXL_VRAM_RANGE_INDEX])) != NO_ERROR ||
+ (status = InitModes(dev_ext)) != NO_ERROR ) {
+ DEBUG_PRINT((0, "%s: findAdapter failed\n", __FUNCTION__));
+ DevExternsionCleanup(dev_ext);
+ }
+
+ if (VideoPortSetRegistryParameters(dev_extension, L"QxlDeviceID",
+ &dev_ext->rom->id, sizeof(UINT32)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: write QXL ID failed\n", __FUNCTION__));
+ }
+
+ DEBUG_PRINT((0, "%s: exit %lu\n", __FUNCTION__, status));
+ return status;
+}
+
+
+#if defined(ALLOC_PRAGMA)
+void HWReset(QXLExtension *dev_ext);
+#pragma alloc_text(PAGE, HWReset)
+#endif
+
+void HWReset(QXLExtension *dev_ext)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_RESET, 0);
+ DEBUG_PRINT((0, "%s: done\n", __FUNCTION__));
+}
+
+BOOLEAN Initialize(PVOID dev_ext)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+ HWReset(dev_ext);
+ DEBUG_PRINT((0, "%s: done\n", __FUNCTION__));
+ return TRUE;
+}
+
+VP_STATUS GetPowerState(PVOID dev_extension,
+ ULONG hw_id,
+ PVIDEO_POWER_MANAGEMENT pm_stat)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
+
+ switch (hw_id) {
+ case DISPLAY_ADAPTER_HW_ID:
+ switch (pm_stat->PowerState) {
+ case VideoPowerOn:
+ case VideoPowerStandBy:
+ case VideoPowerSuspend:
+ case VideoPowerOff:
+ case VideoPowerShutdown:
+ case VideoPowerHibernate:
+ DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
+ return NO_ERROR;
+ }
+ break;
+ default:
+ DEBUG_PRINT((0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+ }
+ DEBUG_PRINT((0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
+ return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+}
+
+VP_STATUS SetPowerState(PVOID dev_extension,
+ ULONG hw_id,
+ PVIDEO_POWER_MANAGEMENT pm_stat)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s: %lu\n", __FUNCTION__, pm_stat->PowerState));
+
+ switch (hw_id) {
+ case DISPLAY_ADAPTER_HW_ID:
+ switch (pm_stat->PowerState) {
+ case VideoPowerOn:
+ case VideoPowerStandBy:
+ case VideoPowerSuspend:
+ case VideoPowerOff:
+ case VideoPowerShutdown:
+ case VideoPowerHibernate:
+ DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
+ return NO_ERROR;
+ }
+ break;
+ default:
+ DEBUG_PRINT((0, "%s: unexpected hw_id %lu\n", __FUNCTION__, hw_id));
+ }
+ DEBUG_PRINT((0, "%s: ERROR_DEVICE_REINITIALIZATION_NEEDED\n", __FUNCTION__));
+ return ERROR_DEVICE_REINITIALIZATION_NEEDED;
+}
+
+VP_STATUS GetChildDescriptor(IN PVOID dev_extension,
+ IN PVIDEO_CHILD_ENUM_INFO enum_info,
+ OUT PVIDEO_CHILD_TYPE type,
+ OUT PUCHAR descriptor,
+ OUT PULONG uid,
+ OUT PULONG unused)
+{
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s: enter\n", __FUNCTION__));
+
+ switch (enum_info->ChildIndex) {
+ case 0:
+ DEBUG_PRINT((0, "%s: ACPI id %u\n", __FUNCTION__, enum_info->ACPIHwId));
+ return ERROR_NO_MORE_DEVICES;
+ case 1:
+ DEBUG_PRINT((0, "%s: Monitor\n", __FUNCTION__));
+ /*
+ *pChildType = Monitor;
+ todo: handle EDID
+ return ERROR_MORE_DATA;
+ */
+ return ERROR_NO_MORE_DEVICES;
+ }
+ DEBUG_PRINT((0, "%s: ERROR_NO_MORE_DEVICES\n", __FUNCTION__));
+ return ERROR_NO_MORE_DEVICES;
+}
+
+#if defined(ALLOC_PRAGMA)
+PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode);
+#pragma alloc_text(PAGE, FindMode)
+#endif
+
+#define IsValidMode(dev, mode) (FindMode(dev, mode) != NULL)
+
+PVIDEO_MODE_INFORMATION FindMode(QXLExtension *dev_ext, ULONG mode)
+{
+ VIDEO_MODE_INFORMATION *inf;
+ VIDEO_MODE_INFORMATION *end;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ inf = dev_ext->modes;
+ end = inf + dev_ext->n_modes;
+ for (; inf < end; inf++) {
+ if (inf->ModeIndex == mode) {
+ DEBUG_PRINT((0, "%s: OK mode %lu res %lu-%lu orientation %lu\n", __FUNCTION__,
+ mode, inf->VisScreenWidth, inf->VisScreenHeight,
+ inf->DriverSpecificAttributeFlags ));
+ return inf;
+ }
+ }
+ DEBUG_PRINT((0, "%s: mod info not found\n", __FUNCTION__));
+ return NULL;
+}
+
+BOOLEAN StartIO(PVOID dev_extension, PVIDEO_REQUEST_PACKET packet)
+{
+ QXLExtension *dev_ext = dev_extension;
+ VP_STATUS error;
+
+ PAGED_CODE();
+ DEBUG_PRINT((0, "%s\n", __FUNCTION__));
+
+ switch (packet->IoControlCode) {
+ case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES\n", __FUNCTION__));
+ if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+ sizeof(VIDEO_NUM_MODES))) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+ ((PVIDEO_NUM_MODES)packet->OutputBuffer)->NumModes = dev_ext->n_modes;
+ ((PVIDEO_NUM_MODES)packet->OutputBuffer)->ModeInformationLength =
+ sizeof(VIDEO_MODE_INFORMATION);
+ break;
+ case IOCTL_VIDEO_QUERY_AVAIL_MODES: {
+ VIDEO_MODE_INFORMATION *inf;
+ VIDEO_MODE_INFORMATION *end;
+ VIDEO_MODE_INFORMATION *out;
+
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_AVAIL_MODES\n", __FUNCTION__));
+ if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+ dev_ext->n_modes * sizeof(VIDEO_MODE_INFORMATION))) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+ out = packet->OutputBuffer;
+ inf = dev_ext->modes;
+ end = inf + dev_ext->n_modes;
+ for ( ;inf < end; out++, inf++) {
+ *out = *inf;
+ }
+ }
+ break;
+ case IOCTL_VIDEO_SET_CURRENT_MODE: {
+ ULONG request_mode;
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_SET_CURRENT_MODE\n", __FUNCTION__));
+ if (packet->InputBufferLength < sizeof(VIDEO_MODE)) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+ request_mode = ((PVIDEO_MODE)packet->InputBuffer)->RequestedMode;
+ DEBUG_PRINT((0, "%s: mode %u\n", __FUNCTION__, request_mode));
+ if (!IsValidMode(dev_ext, request_mode)) {
+ error = ERROR_INVALID_PARAMETER;
+ goto err;
+ }
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_SET_MODE,
+ (UCHAR)request_mode);
+ dev_ext->ram_header->int_mask = ~0;
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+ }
+ break;
+ case IOCTL_VIDEO_QUERY_CURRENT_MODE: {
+ PVIDEO_MODE_INFORMATION inf;
+
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_QUERY_CURRENT_MODE\n", __FUNCTION__));
+
+ if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+ sizeof(VIDEO_MODE_INFORMATION))) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+
+ if ((inf = FindMode(dev_ext, dev_ext->rom->mode)) == NULL) {
+ DEBUG_PRINT((0, "%s: mod info not found\n", __FUNCTION__));
+ error = ERROR_INVALID_DATA;
+ goto err;
+ }
+ *(PVIDEO_MODE_INFORMATION)packet->OutputBuffer = *inf;
+ }
+ break;
+ case IOCTL_VIDEO_MAP_VIDEO_MEMORY: {
+ PVIDEO_MEMORY_INFORMATION mem_info;
+ ULONG fb_io_space;
+
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_MAP_VIDEO_MEMORY\n", __FUNCTION__));
+
+ if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+ sizeof(VIDEO_MEMORY_INFORMATION)) ||
+ ( packet->InputBufferLength < sizeof(VIDEO_MEMORY) ) ) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+ mem_info = packet->OutputBuffer;
+
+ mem_info->VideoRamBase =
+ ((PVIDEO_MEMORY)(packet->InputBuffer))->RequestedVirtualAddress;
+ ASSERT(mem_info->VideoRamBase == NULL);
+ mem_info->VideoRamLength = dev_ext->vram_size;
+ fb_io_space = VIDEO_MEMORY_SPACE_MEMORY;
+
+ if ((error = VideoPortMapMemory(dev_ext, dev_ext->vram_physical,
+ &mem_info->VideoRamLength,
+ &fb_io_space, &mem_info->VideoRamBase)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: map filed\n", __FUNCTION__));
+ goto err;
+ }
+ DEBUG_PRINT((0, "%s: vram size %lu ret size %lu fb vaddr 0x%lx\n",
+ __FUNCTION__,
+ dev_ext->vram_size,
+ mem_info->VideoRamLength,
+ mem_info->VideoRamBase));
+ if (mem_info->VideoRamLength < dev_ext->vram_size) {
+ DEBUG_PRINT((0, "%s: fb shrink\n", __FUNCTION__));
+ VideoPortUnmapMemory(dev_ext, mem_info->VideoRamBase, NULL);
+ mem_info->VideoRamBase = NULL;
+ mem_info->VideoRamLength = 0;
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto err;
+ }
+ mem_info->FrameBufferBase = mem_info->VideoRamBase;
+ mem_info->FrameBufferLength = mem_info->VideoRamLength;
+#ifdef DBG
+ DEBUG_PRINT((0, "%s: zap\n", __FUNCTION__));
+ VideoPortZeroMemory(mem_info->VideoRamBase, mem_info->VideoRamLength);
+ DEBUG_PRINT((0, "%s: zap done\n", __FUNCTION__));
+#endif
+ }
+ break;
+ case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: {
+ PVOID addr;
+
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY\n", __FUNCTION__));
+
+ if (packet->InputBufferLength < sizeof(VIDEO_MEMORY)) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+ addr = ((PVIDEO_MEMORY)(packet->InputBuffer))->RequestedVirtualAddress;
+ if ((error = VideoPortUnmapMemory(dev_ext, addr, NULL)) != NO_ERROR) {
+ DEBUG_PRINT((0, "%s: unmap failed\n", __FUNCTION__));
+ }
+ }
+ break;
+ case IOCTL_VIDEO_RESET_DEVICE:
+ DEBUG_PRINT((0, "%s: IOCTL_VIDEO_RESET_DEVICE\n", __FUNCTION__));
+ HWReset(dev_ext);
+ break;
+ case IOCTL_QXL_GET_INFO: {
+ QXLDriverInfo *driver_info;
+ DEBUG_PRINT((0, "%s: IOCTL_QXL_GET_INFO\n", __FUNCTION__));
+
+ if (packet->OutputBufferLength < (packet->StatusBlock->Information =
+ sizeof(QXLDriverInfo))) {
+ error = ERROR_INSUFFICIENT_BUFFER;
+ goto err;
+ }
+
+ driver_info = packet->OutputBuffer;
+ driver_info->version = QXL_DRIVER_INFO_VERSION;
+ driver_info->display_event = dev_ext->display_event;
+ driver_info->cursor_event = dev_ext->cursor_event;
+ driver_info->sleep_event = dev_ext->sleep_event;
+ driver_info->cmd_ring = &dev_ext->ram_header->cmd_ring;
+ driver_info->cursor_ring = &dev_ext->ram_header->cursor_ring;
+ driver_info->release_ring = &dev_ext->ram_header->release_ring;
+ driver_info->notify_cmd_port = dev_ext->io_port + QXL_IO_NOTIFY_CMD;
+ driver_info->notify_cursor_port = dev_ext->io_port + QXL_IO_NOTIFY_CURSOR;
+ driver_info->notify_oom_port = dev_ext->io_port + QXL_IO_NOTIFY_OOM;
+ driver_info->log_port = dev_ext->io_port + QXL_IO_LOG;
+ driver_info->log_buf = dev_ext->ram_header->log_buf;
+
+ driver_info->draw_area = dev_ext->ram_start + dev_ext->rom->draw_area_offset;
+ driver_info->draw_area_size = dev_ext->rom->draw_area_size;
+ driver_info->update_id = &dev_ext->rom->update_id;
+ driver_info->mm_clock = &dev_ext->rom->mm_clock;
+ driver_info->compression_level = &dev_ext->rom->compression_level;
+ driver_info->log_level = &dev_ext->rom->log_level;
+ driver_info->update_area_port = dev_ext->io_port + QXL_IO_UPDATE_AREA;
+ driver_info->update_area = &dev_ext->ram_header->update_area;
+
+ driver_info->num_io_pages = dev_ext->rom->num_io_pages;
+ driver_info->io_pages_virt = dev_ext->ram_start + dev_ext->rom->pages_offset;
+ driver_info->io_pages_phys = dev_ext->ram_physical.QuadPart +
+ dev_ext->rom->pages_offset;
+#if (WINVER < 0x0501)
+ driver_info->WaitForEvent = QXLWaitForEvent;
+#endif
+ }
+ break;
+ default:
+ DEBUG_PRINT((0, "%s: invalid command 0x%lx\n", __FUNCTION__, packet->IoControlCode));
+ error = ERROR_INVALID_FUNCTION;
+ goto err;
+ }
+ packet->StatusBlock->Status = NO_ERROR;
+ DEBUG_PRINT((0, "%s: OK\n", __FUNCTION__));
+ return TRUE;
+ err:
+ packet->StatusBlock->Information = 0;
+ packet->StatusBlock->Status = error;
+ DEBUG_PRINT((0, "%s: ERR\n", __FUNCTION__));
+ return TRUE;
+}
+
+VOID InterruptCallback(PVOID dev_extension, PVOID Context)
+{
+ QXLExtension *dev_ext = dev_extension;
+ UINT32 pending = VideoPortInterlockedExchange(&dev_ext->ram_header->int_pending, 0);
+
+ if (pending & QXL_INTERRUPT_DISPLAY) {
+ VideoPortSetEvent(dev_ext, dev_ext->display_event);
+ } if (pending & QXL_INTERRUPT_CURSOR) {
+ VideoPortSetEvent(dev_ext, dev_ext->cursor_event);
+ }
+
+ dev_ext->ram_header->int_mask = ~0;
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+}
+
+BOOLEAN Interrupt(PVOID dev_extension)
+{
+ QXLExtension *dev_ext = dev_extension;
+
+ if (!(dev_ext->ram_header->int_pending & dev_ext->ram_header->int_mask)) {
+ return FALSE;
+ }
+ dev_ext->ram_header->int_mask = 0;
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+
+ if (!VideoPortQueueDpc(dev_extension, InterruptCallback, NULL)) {
+ VideoPortLogError(dev_extension, NULL, E_UNEXPECTED, QXLERR_INT_DELIVERY);
+ dev_ext->ram_header->int_mask = ~0;
+ VideoPortWritePortUchar((PUCHAR)dev_ext->io_base + QXL_IO_UPDATE_IRQ, 0);
+ }
+ return TRUE;
+}