From e89e30c90cbb96fa605d6b3f75907b096fc31aec Mon Sep 17 00:00:00 2001 From: faust3 Date: Tue, 23 Mar 2004 10:41:04 +0000 Subject: Windows XP support git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@12058 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libdha/dhahelperwin/MAKEFILE | 7 + libdha/dhahelperwin/SOURCES | 6 + libdha/dhahelperwin/dhahelper.c | 359 ++++++++++++++++++++++++++++++++++++++++ libdha/dhahelperwin/dhahelper.h | 50 ++++++ libdha/dhahelperwin/dhasetup.c | 53 ++++++ 5 files changed, 475 insertions(+) create mode 100644 libdha/dhahelperwin/MAKEFILE create mode 100644 libdha/dhahelperwin/SOURCES create mode 100644 libdha/dhahelperwin/dhahelper.c create mode 100644 libdha/dhahelperwin/dhahelper.h create mode 100644 libdha/dhahelperwin/dhasetup.c (limited to 'libdha') diff --git a/libdha/dhahelperwin/MAKEFILE b/libdha/dhahelperwin/MAKEFILE new file mode 100644 index 0000000000..58189757d6 --- /dev/null +++ b/libdha/dhahelperwin/MAKEFILE @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/libdha/dhahelperwin/SOURCES b/libdha/dhahelperwin/SOURCES new file mode 100644 index 0000000000..e44aa06971 --- /dev/null +++ b/libdha/dhahelperwin/SOURCES @@ -0,0 +1,6 @@ +TARGETNAME=dhahelper +TARGETPATH=. +TARGETTYPE=DRIVER +NTDEBUG=ntsd + +SOURCES= dhahelper.c diff --git a/libdha/dhahelperwin/dhahelper.c b/libdha/dhahelperwin/dhahelper.c new file mode 100644 index 0000000000..48e7b8cb1a --- /dev/null +++ b/libdha/dhahelperwin/dhahelper.c @@ -0,0 +1,359 @@ +/****************************************************************************** + * dhahelper.c: direct hardware access under Windows NT/2000/XP + * Copyright (c) 2004 Sascha Sommer . + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * + *****************************************************************************/ + + +#include +#include "dhahelper.h" + +#define OutputDebugString DbgPrint + +#define IOPM_SIZE 0x2000 +typedef char IOPM[IOPM_SIZE]; +static IOPM *pIOPM = NULL; + + + +typedef struct { + PMDL Mdl; + PVOID SystemVirtualAddress; + PVOID UserVirtualAddress; + ULONG PhysMemSizeInBytes; +}alloc_priv; +static alloc_priv* alloclist; +static unsigned int alloccount=0; + + + + + + + +static NTSTATUS dhahelperdispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); +static void dhahelperunload(IN PDRIVER_OBJECT DriverObject); +static NTSTATUS UnmapPhysicalMemory(PVOID UserVirtualAddress); +static NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,ULONG PhysMemSizeInBytes,PVOID *PhysMemLin); + +void Ke386SetIoAccessMap(int, IOPM *); +void Ke386QueryIoAccessMap(int, IOPM *); +void Ke386IoSetAccessProcess(PEPROCESS, int); + + + + +//entry point +NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath){ + UNICODE_STRING DeviceNameUnicodeString; + UNICODE_STRING DeviceLinkUnicodeString; + NTSTATUS ntStatus; + PDEVICE_OBJECT DeviceObject = NULL; + + OutputDebugString ("dhahelper: entering DriverEntry"); + + RtlInitUnicodeString (&DeviceNameUnicodeString, L"\\Device\\DHAHELPER"); + + // Create an EXCLUSIVE device object (only 1 thread at a time + // can make requests to this device). + + ntStatus = IoCreateDevice(DriverObject,0,&DeviceNameUnicodeString,FILE_DEVICE_DHAHELPER,0,TRUE,&DeviceObject); + + if (NT_SUCCESS(ntStatus)){ + // Create dispatch points for device control, create, close. + DriverObject->MajorFunction[IRP_MJ_CREATE] = + DriverObject->MajorFunction[IRP_MJ_CLOSE] = + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dhahelperdispatch; + DriverObject->DriverUnload = dhahelperunload; + + // Create a symbolic link, e.g. a name that a Win32 app can specify + // to open the device. + + RtlInitUnicodeString (&DeviceLinkUnicodeString, L"\\DosDevices\\DHAHELPER"); + + ntStatus = IoCreateSymbolicLink(&DeviceLinkUnicodeString,&DeviceNameUnicodeString); + + if (!NT_SUCCESS(ntStatus)){ + // Symbolic link creation failed- note this & then delete the + // device object (it's useless if a Win32 app can't get at it). + OutputDebugString ("dhahelper: IoCreateSymbolicLink failed"); + IoDeleteDevice (DeviceObject); + } + } + else{ + OutputDebugString ("dhahelper: IoCreateDevice failed"); + } + OutputDebugString ("dhahelper: leaving DriverEntry"); + return ntStatus; +} + + +// Process the IRPs sent to this device + +static NTSTATUS dhahelperdispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp){ + PIO_STACK_LOCATION IrpStack; + ULONG dwInputBufferLength; + ULONG dwOutputBufferLength; + ULONG dwIoControlCode; + PVOID pvIOBuffer; + NTSTATUS ntStatus; + dhahelper_t dhahelper_priv; + + OutputDebugString ("dhahelper: entering dhahelperdispatch"); + + // Init to default settings + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IrpStack = IoGetCurrentIrpStackLocation(Irp); + + // Get the pointer to the input/output buffer and it's length + + pvIOBuffer = Irp->AssociatedIrp.SystemBuffer; + dwInputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; + dwOutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; + + switch (IrpStack->MajorFunction){ + case IRP_MJ_CREATE: + OutputDebugString("dhahelper: IRP_MJ_CREATE"); + break; + case IRP_MJ_CLOSE: + OutputDebugString("dhahelper: IRP_MJ_CLOSE"); + break; + case IRP_MJ_DEVICE_CONTROL: + OutputDebugString("dhahelper: IRP_MJ_DEVICE_CONTROL"); + dwIoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; + switch (dwIoControlCode){ + case IOCTL_DHAHELPER_ENABLEDIRECTIO: + OutputDebugString("dhahelper: IOCTL_DHAHELPER_ENABLEDIRECTIO"); + pIOPM = MmAllocateNonCachedMemory(sizeof(IOPM)); + if (pIOPM){ + RtlZeroMemory(pIOPM, sizeof(IOPM)); + Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1); + Ke386SetIoAccessMap(1, pIOPM); + } + else Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + break; + case IOCTL_DHAHELPER_DISABLEDIRECTIO: + OutputDebugString("dhahelper: IOCTL_DHAHELPER_DISABLEDIRECTIO"); + if (pIOPM){ + Ke386IoSetAccessProcess(PsGetCurrentProcess(), 0); + Ke386SetIoAccessMap(1, pIOPM); + MmFreeNonCachedMemory(pIOPM, sizeof(IOPM)); + pIOPM = NULL; + } + break; + case IOCTL_DHAHELPER_MAPPHYSTOLIN: + OutputDebugString("dhahelper: IOCTL_DHAHELPER_MAPPHYSTOLIN"); + if (dwInputBufferLength){ + memcpy (&dhahelper_priv, pvIOBuffer, dwInputBufferLength); + ntStatus = MapPhysicalMemoryToLinearSpace(dhahelper_priv.base,dhahelper_priv.size,&dhahelper_priv.ptr); + if (NT_SUCCESS(ntStatus)){ + memcpy (pvIOBuffer, &dhahelper_priv, dwInputBufferLength); + Irp->IoStatus.Information = dwInputBufferLength; + } + Irp->IoStatus.Status = ntStatus; + } + else Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + case IOCTL_DHAHELPER_UNMAPPHYSADDR: + OutputDebugString("dhahelper: IOCTL_DHAHELPER_UNMAPPHYSADDR"); + if (dwInputBufferLength){ + memcpy (&dhahelper_priv, pvIOBuffer, dwInputBufferLength); + ntStatus = UnmapPhysicalMemory(dhahelper_priv.ptr); + Irp->IoStatus.Status = ntStatus; + } + else + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + default: + OutputDebugString("dhahelper: unknown IRP_MJ_DEVICE_CONTROL"); + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + break; + } + break; + } + + // DON'T get cute and try to use the status field of the irp in the + // return status. That IRP IS GONE as soon as you call IoCompleteRequest. + + ntStatus = Irp->IoStatus.Status; + + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + // We never have pending operation so always return the status code. + + OutputDebugString("dhahelper: leaving dhahelperdispatch"); + + return ntStatus; +} + +// Delete the associated device and return + +static void dhahelperunload(IN PDRIVER_OBJECT DriverObject){ + UNICODE_STRING DeviceLinkUnicodeString; + NTSTATUS ntStatus=STATUS_SUCCESS; + OutputDebugString ("dhahelper: entering dhahelperunload"); + OutputDebugString ("dhahelper: unmapping remaining memory"); + + while(alloccount && (ntStatus==STATUS_SUCCESS))ntStatus = UnmapPhysicalMemory(alloclist[alloccount-1].UserVirtualAddress); + RtlInitUnicodeString (&DeviceLinkUnicodeString, L"\\DosDevices\\DHAHELPER"); + ntStatus = IoDeleteSymbolicLink (&DeviceLinkUnicodeString); + + if (NT_SUCCESS(ntStatus)){ + IoDeleteDevice (DriverObject->DeviceObject); + } + else { + OutputDebugString ("dhahelper: IoDeleteSymbolicLink failed"); + } + OutputDebugString ("dhahelper: leaving dhahelperunload"); +} + + + + + + +/************************* memory mapping functions ******************************/ +//unlike the functions of other io helpers these functions allow to map adapter memory on windows xp +//even if it has alread been mapped by the original driver +//the technique used is described in +//http://support.microsoft.com/default.aspx?scid=kb;en-us;q189327 +//furthermore it keeps a list of mapped areas to free them when the driver gets unloaded +//I'm not sure what the limitations of ZwMapViewOfSection are but mapping 128MB videoram (that is probably already mapped by the gfxcard driver) +//won't work so it is generally a good idea to map only the memory you really need + +static NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,ULONG PhysMemSizeInBytes,PVOID *PhysMemLin){ + alloc_priv* alloclisttmp; + PMDL Mdl=NULL; + PVOID SystemVirtualAddress=NULL; + PVOID UserVirtualAddress=NULL; + PHYSICAL_ADDRESS pStartPhysAddress; + OutputDebugString ("dhahelper: entering MapPhysicalMemoryToLinearSpace"); + + pStartPhysAddress.QuadPart = (ULONGLONG)pPhysAddress; + __try { + SystemVirtualAddress=MmMapIoSpace(pStartPhysAddress,PhysMemSizeInBytes, /*MmWriteCombined*/MmNonCached); + if(!SystemVirtualAddress){ + OutputDebugString("dhahelper: MmMapIoSpace failed"); + return STATUS_INVALID_PARAMETER; + } + OutputDebugString("dhahelper: SystemVirtualAddress 0x%x",SystemVirtualAddress); + Mdl=IoAllocateMdl(SystemVirtualAddress, PhysMemSizeInBytes, FALSE, FALSE,NULL); + if(!Mdl){ + OutputDebugString("dhahelper: IoAllocateMdl failed"); + return STATUS_INSUFFICIENT_RESOURCES; + } + OutputDebugString("dhahelper: Mdl 0x%x",Mdl); + MmBuildMdlForNonPagedPool(Mdl); + UserVirtualAddress = (PVOID)(((ULONG)PAGE_ALIGN(MmMapLockedPages(Mdl,UserMode))) + MmGetMdlByteOffset(Mdl)); + if(!UserVirtualAddress){ + OutputDebugString("dhahelper: MmMapLockedPages failed"); + return STATUS_INSUFFICIENT_RESOURCES; + } + OutputDebugString("dhahelper: UserVirtualAddress 0x%x",UserVirtualAddress); + }__except(EXCEPTION_EXECUTE_HANDLER){ + NTSTATUS ntStatus; + ntStatus = GetExceptionCode(); + OutputDebugString("dhahelper: MapPhysicalMemoryToLinearSpace failed due to exception 0x%0x\n", ntStatus); + return ntStatus; + } + + + OutputDebugString("dhahelper: adding data to internal allocation list"); + alloclisttmp=MmAllocateNonCachedMemory((alloccount+1)*sizeof(alloc_priv)); + + + if(!alloclisttmp){ + OutputDebugString("dhahelper: not enough memory to create temporary allocation list"); + MmUnmapLockedPages(UserVirtualAddress, Mdl); + IoFreeMdl(Mdl); + return STATUS_INSUFFICIENT_RESOURCES; + } + if(alloccount){ + memcpy(alloclisttmp,alloclist,alloccount * sizeof(alloc_priv)); + MmFreeNonCachedMemory(alloclist,alloccount*sizeof(alloc_priv)); + } + alloclist=alloclisttmp; + alloclist[alloccount].Mdl=Mdl; + alloclist[alloccount].SystemVirtualAddress=SystemVirtualAddress; + alloclist[alloccount].UserVirtualAddress=UserVirtualAddress; + alloclist[alloccount].PhysMemSizeInBytes=PhysMemSizeInBytes; + ++alloccount; + + *PhysMemLin=UserVirtualAddress; + + OutputDebugString("dhahelper: leaving MapPhysicalMemoryToLinearSpace"); + return STATUS_SUCCESS; +} + +static NTSTATUS UnmapPhysicalMemory(PVOID UserVirtualAddress){ + unsigned int i; + unsigned int x=0; + unsigned int alloccounttmp=alloccount; + OutputDebugString("dhahelper: entering UnmapPhysicalMemory to unmapp 0x%x",UserVirtualAddress); + if(!alloccount){ + OutputDebugString("dhahelper: UnmapPhysicalMemory: nothing todo -> leaving..."); + return STATUS_SUCCESS; + } + + for(i=0;i +#include + +int main(int argc,char* argv[]){ + SC_HANDLE hSCManager; + SC_HANDLE hService; + printf("dhasetup (c) 2004 Sascha Sommer\n"); + if(argc==1){ + printf("usage:\n"); + printf("dhasetup install - copys dhahelper.sys from the current dir to windows/system32/drivers and configures it to start at system start\n"); + printf("dhasetup remove - removes the dhahelper util\n"); + return 0; + } + hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if(!strcmp(argv[1],"install")){ + printf("installing dhahelper\n"); + CopyFile("dhahelper.sys","c:\\windows\\System32\\drivers\\dhahelper.sys",FALSE); + // Install the driver + hService = CreateService(hSCManager, + "DHAHELPER", + "DHAHELPER", + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_SYSTEM_START, + SERVICE_ERROR_NORMAL, + "c:\\windows\\System32\\drivers\\dhahelper.sys", + NULL, + NULL, + NULL, + NULL, + NULL); + } + else if(!strcmp(argv[1],"remove")){ + SERVICE_STATUS ServiceStatus; + printf("removing dhahelper\n"); + hService = OpenService(hSCManager, "DHAHELPER", SERVICE_ALL_ACCESS); + ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); + DeleteService(hService); + DeleteFile("c:\\windows\\System32\\drivers\\dhahelper.sys"); + } + else { + printf("unknown parameter: %s\n",argv[1]); + } + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + printf("please reboot to let the changes take effect\n"); + return 0; +} -- cgit v1.2.3