mirror of
https://github.com/Wack0/entii-for-workcubes.git
synced 2025-12-19 09:50:51 -05:00
cafegx2drv: Initial commit
Only supports single display mode for now. Uses NT-provided flat framebuffer GDI driver.
This commit is contained in:
109
cafegx2drv/Makefile
Normal file
109
cafegx2drv/Makefile
Normal file
@@ -0,0 +1,109 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# Clear the implicit built in rules
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
|
||||
|
||||
include $(CURRENT_DIRECTORY)/../pe_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(patsubst %drv,%,$(notdir $(CURDIR)))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
DATA := data
|
||||
INCLUDES :=
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -O1 $(MACHDEP) $(INCLUDE) -D_NTDRIVER_
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
CPPFLAGS = $(INCLUDE) -D_NTDRIVER_
|
||||
|
||||
|
||||
DEFFILES := $(foreach dir,$(CURRENT_DIRECTORY)/$(SOURCES),$(wildcard $(dir)/*.def))
|
||||
ifeq ($(SUBST_PATH), 1)
|
||||
DEFS := $(foreach def,$(DEFFILES),-DEF:$(subst \,\\,$(shell $(PATH_CONVERT) $(def))))
|
||||
else
|
||||
DEFS := $(foreach def,$(DEFFILES),-DEF:$(shell $(PATH_CONVERT) $(def)))
|
||||
endif
|
||||
LDFLAGS = -DRIVER -DLL $(DEFS) -SECTION:INIT,d -NODEFAULTLIB -ALIGN:0x20 -ENTRY:DriverEntry -BASE:0x10000 -SUBSYSTEM:NATIVE,3.50 -VERSION:3.50 -OSVERSION:3.50
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIR := $(CURRENT_DIRECTORY)/../lib
|
||||
HALLIB := $(CURRENT_DIRECTORY)/../halartx/halartx.lib
|
||||
LIBS := $(LIBDIR)/NTOSKRNL.LIB $(LIBDIR)/VIDEOPRT.LIB $(HALLIB)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# automatically build a list of object files for our project
|
||||
#---------------------------------------------------------------------------------
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
ASMFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.asm)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
RCFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.rc)))
|
||||
|
||||
export OFILES_BIN := $(addsuffix .obj,$(BINFILES))
|
||||
export OFILES_SOURCES := $(CPPFILES:.cpp=.obj) $(CFILES:.c=.obj) $(ASMFILES:.asm=.obj) $(SFILES:.s=.obj)
|
||||
export RESFILES := $(RCFILES:.rc=.res)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
|
||||
|
||||
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(OUTPUT).sys $(OUTPUT).dbg
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.obj=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).sys: $(OFILES) $(RESFILES)
|
||||
|
||||
$(OFILES_SOURCES) : $(HFILES)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
256
cafegx2drv/source/cafegx2.c
Normal file
256
cafegx2drv/source/cafegx2.c
Normal file
@@ -0,0 +1,256 @@
|
||||
// NT driver for using the flat GX2 framebuffer.
|
||||
// The GX2 is set up to use 8in64 swapping.
|
||||
// This combined with the endian swap elsewhere means the GPU does effective accesses with MSR_LE bitswizzling!
|
||||
// Therefore we can just provide a flat framebuffer to NT.
|
||||
// TODO:
|
||||
// - support other display resolutions (is letterboxing required or can the registers for that just be changed?)
|
||||
// - support other colour depths
|
||||
// - support letterboxed 640x480 on the gamepad framebuffer
|
||||
|
||||
#define DEVL 1
|
||||
#include <ntddk.h>
|
||||
#include <hal.h>
|
||||
#include <halppc.h>
|
||||
#include <arc.h>
|
||||
#include <miniport.h>
|
||||
#include <ntstatus.h>
|
||||
#include <devioctl.h>
|
||||
#include <ntddvdeo.h>
|
||||
#define VIDEOPORT_API __declspec(dllimport)
|
||||
#define _NTOSDEF_ 1 // we want internal video.h, because we basically are
|
||||
#include <video.h>
|
||||
#include <winerror.h>
|
||||
#define KIPCR 0xffffd000
|
||||
|
||||
extern ULONG NtBuildNumber;
|
||||
|
||||
#include "runtime.h"
|
||||
|
||||
#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))
|
||||
|
||||
#define MS_TO_TIMEOUT(ms) ((ms) * 10000)
|
||||
|
||||
// Define hardware device extension.
|
||||
typedef struct _DEVICE_EXTENSION {
|
||||
FRAME_BUFFER PhysicalFrameBuffer;
|
||||
ULONG OriginalFrameBuffer;
|
||||
ULONG FrameBufferOffset;
|
||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||||
|
||||
static VIDEO_MODE_INFORMATION s_VideoMode = {0};
|
||||
|
||||
VP_STATUS FbFindAdapter(PVOID HwDeviceExtension, PVOID HwContext, PWSTR ArgumentString, PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again) {
|
||||
PDEVICE_EXTENSION Extension = (PDEVICE_EXTENSION)HwDeviceExtension;
|
||||
|
||||
if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
// Check that the runtime block is present and sane.
|
||||
if (SYSTEM_BLOCK->Length < (sizeof(SYSTEM_PARAMETER_BLOCK) + sizeof(PVOID))) return ERROR_DEV_NOT_EXIST;
|
||||
if ((ULONG)RUNTIME_BLOCK < 0x80000000) return ERROR_DEV_NOT_EXIST;
|
||||
if ((ULONG)RUNTIME_BLOCK >= 0x90000000) return ERROR_DEV_NOT_EXIST;
|
||||
|
||||
// System must be Cafe
|
||||
if (RUNTIME_BLOCK[RUNTIME_SYSTEM_TYPE] < ARTX_SYSTEM_LATTE) return ERROR_DEV_NOT_EXIST;
|
||||
|
||||
// Grab the framebuffer config and check that it's not NULL and sane.
|
||||
PFRAME_BUFFER FbConfig = RUNTIME_BLOCK[RUNTIME_FRAME_BUFFER];
|
||||
if ((ULONG)FbConfig == 0) return ERROR_DEV_NOT_EXIST;
|
||||
if ((ULONG)FbConfig < 0x80000000) return ERROR_DEV_NOT_EXIST;
|
||||
if ((ULONG)FbConfig > 0x90000000) return ERROR_DEV_NOT_EXIST;
|
||||
|
||||
|
||||
// Zero out emulator parameters.
|
||||
ConfigInfo->NumEmulatorAccessEntries = 0;
|
||||
ConfigInfo->EmulatorAccessEntries = NULL;
|
||||
ConfigInfo->EmulatorAccessEntriesContext = 0;
|
||||
ConfigInfo->VdmPhysicalVideoMemoryAddress.QuadPart = 0;
|
||||
ConfigInfo->VdmPhysicalVideoMemoryLength = 0;
|
||||
ConfigInfo->HardwareStateSize = 0;
|
||||
|
||||
// Set frame buffer information.
|
||||
RtlCopyMemory(&Extension->PhysicalFrameBuffer, FbConfig, sizeof(*FbConfig));
|
||||
ULONG Height = FbConfig->Height + 1;
|
||||
Extension->OriginalFrameBuffer = Extension->PhysicalFrameBuffer.PointerArc;
|
||||
|
||||
// If the frame buffer physical address and length is not aligned to 64k,
|
||||
// we need to fix a bug in NT.
|
||||
ULONG FbAlign = (Extension->OriginalFrameBuffer & 0xffff);
|
||||
Extension->FrameBufferOffset = FbAlign;
|
||||
|
||||
// Initialise the video mode.
|
||||
s_VideoMode.Length = sizeof(s_VideoMode);
|
||||
s_VideoMode.ModeIndex = 0;
|
||||
s_VideoMode.VisScreenWidth = Extension->PhysicalFrameBuffer.Width;
|
||||
s_VideoMode.VisScreenHeight = Extension->PhysicalFrameBuffer.Height;
|
||||
s_VideoMode.ScreenStride = Extension->PhysicalFrameBuffer.Stride;
|
||||
s_VideoMode.NumberOfPlanes = 1;
|
||||
s_VideoMode.BitsPerPlane = 32;
|
||||
s_VideoMode.Frequency = 60;
|
||||
// todo: Is this correct?
|
||||
s_VideoMode.XMillimeter = 320;
|
||||
s_VideoMode.YMillimeter = 240;
|
||||
s_VideoMode.NumberRedBits = 8;
|
||||
s_VideoMode.NumberGreenBits = 8;
|
||||
s_VideoMode.NumberBlueBits = 8;
|
||||
s_VideoMode.RedMask = 0x00ff0000;
|
||||
s_VideoMode.GreenMask = 0x0000ff00;
|
||||
s_VideoMode.BlueMask = 0x000000ff;
|
||||
s_VideoMode.AttributeFlags = VIDEO_MODE_GRAPHICS;
|
||||
|
||||
// We are done. Only one GX2 device exists.
|
||||
*Again = FALSE;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
BOOLEAN FbInitialise(PVOID HwDeviceExtension) {
|
||||
PDEVICE_EXTENSION Extension = (PDEVICE_EXTENSION)HwDeviceExtension;
|
||||
// Nothing needs to be done.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VP_STATUS FbStartIoImpl(PDEVICE_EXTENSION Extension, PVIDEO_REQUEST_PACKET RequestPacket) {
|
||||
switch (RequestPacket->IoControlCode) {
|
||||
case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
|
||||
{
|
||||
// Map the framebuffer into a process.
|
||||
|
||||
// Check buffer lengths.
|
||||
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
// Grab the input buffer.
|
||||
PVIDEO_SHARE_MEMORY ShareMemory = (PVIDEO_SHARE_MEMORY) RequestPacket->InputBuffer;
|
||||
|
||||
// Ensure what the caller wants is actually inside the framebuffer.
|
||||
ULONG MaximumLength = Extension->PhysicalFrameBuffer.Length;
|
||||
if (ShareMemory->ViewOffset > MaximumLength) return ERROR_INVALID_PARAMETER;
|
||||
if ((ShareMemory->ViewOffset + ShareMemory->ViewSize) > MaximumLength) return ERROR_INVALID_PARAMETER;
|
||||
|
||||
RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
|
||||
|
||||
PVOID VirtualAddress = ShareMemory->ProcessHandle; // you're right, win32k shouldn't exist
|
||||
ULONG ViewSize = ShareMemory->ViewSize + Extension->FrameBufferOffset;
|
||||
|
||||
// grab the physaddr of the framebuffer
|
||||
PHYSICAL_ADDRESS FrameBufferPhys;
|
||||
FrameBufferPhys.QuadPart = 0;
|
||||
FrameBufferPhys.LowPart = Extension->OriginalFrameBuffer;
|
||||
ULONG InIoSpace = FALSE;
|
||||
|
||||
VP_STATUS Status = VideoPortMapMemory(Extension, FrameBufferPhys, &ViewSize, &InIoSpace, &VirtualAddress);
|
||||
|
||||
PVIDEO_SHARE_MEMORY_INFORMATION Information = (PVIDEO_SHARE_MEMORY_INFORMATION) RequestPacket->OutputBuffer;
|
||||
|
||||
Information->SharedViewOffset = ShareMemory->ViewOffset;
|
||||
Information->VirtualAddress = VirtualAddress;
|
||||
Information->SharedViewSize = ViewSize;
|
||||
return Status;
|
||||
}
|
||||
break;
|
||||
case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
|
||||
{
|
||||
// Unmaps a previously mapped framebuffer.
|
||||
if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
PVIDEO_SHARE_MEMORY SharedMem = RequestPacket->InputBuffer;
|
||||
return VideoPortUnmapMemory(Extension, SharedMem->RequestedVirtualAddress, SharedMem->ProcessHandle);
|
||||
}
|
||||
break;
|
||||
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
|
||||
{
|
||||
// Maps the entire framebuffer into the caller's address space.
|
||||
|
||||
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
RequestPacket->StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
|
||||
|
||||
PVIDEO_MEMORY_INFORMATION MemInfo = (PVIDEO_MEMORY_INFORMATION) RequestPacket->OutputBuffer;
|
||||
PVIDEO_MEMORY Mem = (PVIDEO_MEMORY) RequestPacket->InputBuffer;
|
||||
|
||||
MemInfo->VideoRamBase = Mem->RequestedVirtualAddress;
|
||||
ULONG MaximumLength = Extension->PhysicalFrameBuffer.Length + Extension->FrameBufferOffset;
|
||||
MemInfo->VideoRamLength = MaximumLength;
|
||||
ULONG InIoSpace = FALSE;
|
||||
PHYSICAL_ADDRESS FrameBufferPhys;
|
||||
FrameBufferPhys.QuadPart = 0;
|
||||
FrameBufferPhys.LowPart = Extension->OriginalFrameBuffer;
|
||||
VP_STATUS Status = VideoPortMapMemory(Extension, FrameBufferPhys, &MemInfo->VideoRamLength, &InIoSpace, &MemInfo->VideoRamBase);
|
||||
MemInfo->FrameBufferBase = MemInfo->VideoRamBase;
|
||||
MemInfo->FrameBufferLength = MemInfo->VideoRamLength;
|
||||
return Status;
|
||||
}
|
||||
break;
|
||||
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
|
||||
{
|
||||
// Unmaps the framebuffer from the caller's address space.
|
||||
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
PVIDEO_MEMORY Mem = (PVIDEO_MEMORY)RequestPacket->InputBuffer;
|
||||
return VideoPortUnmapMemory(Extension, Mem->RequestedVirtualAddress, 0);
|
||||
}
|
||||
break;
|
||||
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
|
||||
// Gets the current video mode.
|
||||
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
|
||||
// Returns information about available video modes (array of VIDEO_MODE_INFORMATION), of which there is exactly one.
|
||||
// Thus for Open Firmware frame buffer, implementation is same as QUERY_CURRENT_MODE.
|
||||
{
|
||||
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
RequestPacket->StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
|
||||
RtlCopyMemory(RequestPacket->OutputBuffer, &s_VideoMode, sizeof(s_VideoMode));
|
||||
return NO_ERROR;
|
||||
}
|
||||
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
|
||||
{
|
||||
// Returns number of valid mode and size of each structure returned.
|
||||
if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
RequestPacket->StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
|
||||
PVIDEO_NUM_MODES NumModes = (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer;
|
||||
NumModes->NumModes = 1;
|
||||
NumModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
|
||||
return NO_ERROR;
|
||||
}
|
||||
case IOCTL_VIDEO_SET_CURRENT_MODE:
|
||||
{
|
||||
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) return ERROR_INSUFFICIENT_BUFFER;
|
||||
PVIDEO_MODE Mode = (PVIDEO_MODE)RequestPacket->InputBuffer;
|
||||
if (Mode->RequestedMode >= 1) return ERROR_INVALID_PARAMETER;
|
||||
// Only a single video mode available, so, no operation.
|
||||
return NO_ERROR;
|
||||
}
|
||||
case IOCTL_VIDEO_RESET_DEVICE:
|
||||
{
|
||||
// Reset device. No operation for now.
|
||||
return NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
BOOLEAN FbStartIo(PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket) {
|
||||
PDEVICE_EXTENSION Extension = (PDEVICE_EXTENSION)HwDeviceExtension;
|
||||
RequestPacket->StatusBlock->Status = FbStartIoImpl(Extension, RequestPacket);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS DriverEntry(PVOID DriverObject, PVOID RegistryPath) {
|
||||
VIDEO_HW_INITIALIZATION_DATA InitData;
|
||||
RtlZeroMemory(&InitData, sizeof(InitData));
|
||||
|
||||
InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
|
||||
|
||||
InitData.HwFindAdapter = FbFindAdapter;
|
||||
InitData.HwInitialize = FbInitialise;
|
||||
InitData.HwStartIO = FbStartIo;
|
||||
|
||||
InitData.HwDeviceExtensionSize = sizeof(DEVICE_EXTENSION);
|
||||
|
||||
// Internal does not work here.
|
||||
// Our HAL(s) configure VMEBus to be equal to Internal, nothing else uses it.
|
||||
InitData.AdapterInterfaceType = VMEBus;
|
||||
NTSTATUS Status = VideoPortInitialize(DriverObject, RegistryPath, &InitData, NULL);
|
||||
return Status;
|
||||
}
|
||||
11
cafegx2drv/source/cafegx2.rc
Normal file
11
cafegx2drv/source/cafegx2.rc
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <ntverp.h>
|
||||
|
||||
#define VER_FILETYPE VFT_DRV
|
||||
#define VER_FILESUBTYPE VFT2_DRV_DISPLAY
|
||||
#define VER_FILEDESCRIPTION_STR "Cafe GX2 Frame Buffer Miniport Driver"
|
||||
#define VER_INTERNALNAME_STR "cafegx2.sys"
|
||||
#define VER_ORIGINALFILENAME_STR "cafegx2.sys"
|
||||
|
||||
#include "common.ver"
|
||||
Reference in New Issue
Block a user