Mercurial > mplayer.hg
annotate vidix/dhahelperwin/dhahelper.c @ 27079:df448e1248b2
remove now useless vidixlib.h file
author | ben |
---|---|
date | Fri, 20 Jun 2008 20:16:34 +0000 |
parents | a1c020529cc0 |
children | 2391228b7ff0 |
rev | line source |
---|---|
26726
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
1 /* |
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
2 * direct hardware access under Windows NT/2000/XP |
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
3 * |
12057 | 4 * Copyright (c) 2004 Sascha Sommer <saschasommer@freenet.de>. |
24541 | 5 * Patched to compile with MinGW by Kevin Kofler: |
6 * Copyright (c) 2007 Kevin Kofler | |
12057 | 7 * |
23277 | 8 * This file is part of MPlayer. |
9 * | |
10 * MPlayer is free software; you can redistribute it and/or modify | |
12057 | 11 * it under the terms of the GNU General Public License as published by |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
23277 | 15 * MPlayer is distributed in the hope that it will be useful, |
12057 | 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
26726
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
20 * You should have received a copy of the GNU General Public License along |
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
21 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
a1c020529cc0
Use standard license header with standard formatting.
diego
parents:
24541
diff
changeset
|
23 */ |
12057 | 24 |
25 | |
24541 | 26 #if defined(_MSC_VER) |
12057 | 27 #include <ntddk.h> |
24541 | 28 #ifndef STDCALL |
29 #define STDCALL /* nothing */ | |
30 #endif | |
31 #elif defined(__MINGW32__) | |
32 #include <ddk/ntddk.h> | |
33 #define NO_SEH /* FIXME */ | |
34 #else | |
35 #error Unsupported compiler. This driver requires MSVC+DDK or MinGW to build. | |
36 #endif | |
37 | |
12057 | 38 #include "dhahelper.h" |
39 | |
40 #define OutputDebugString DbgPrint | |
41 | |
42 #define IOPM_SIZE 0x2000 | |
43 typedef char IOPM[IOPM_SIZE]; | |
44 static IOPM *pIOPM = NULL; | |
45 | |
46 | |
47 | |
48 typedef struct { | |
49 PMDL Mdl; | |
50 PVOID SystemVirtualAddress; | |
51 PVOID UserVirtualAddress; | |
52 ULONG PhysMemSizeInBytes; | |
53 }alloc_priv; | |
54 static alloc_priv* alloclist; | |
55 static unsigned int alloccount=0; | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
24541 | 63 static STDCALL NTSTATUS dhahelperdispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); |
64 static STDCALL void dhahelperunload(IN PDRIVER_OBJECT DriverObject); | |
65 static STDCALL NTSTATUS UnmapPhysicalMemory(PVOID UserVirtualAddress); | |
66 static STDCALL NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,ULONG PhysMemSizeInBytes,PVOID *PhysMemLin); | |
12057 | 67 |
24541 | 68 void STDCALL Ke386SetIoAccessMap(int, IOPM *); |
69 void STDCALL Ke386QueryIoAccessMap(int, IOPM *); | |
70 void STDCALL Ke386IoSetAccessProcess(PEPROCESS, int); | |
12057 | 71 |
72 | |
73 | |
74 | |
75 //entry point | |
24541 | 76 STDCALL NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath){ |
12057 | 77 UNICODE_STRING DeviceNameUnicodeString; |
78 UNICODE_STRING DeviceLinkUnicodeString; | |
79 NTSTATUS ntStatus; | |
80 PDEVICE_OBJECT DeviceObject = NULL; | |
81 | |
82 OutputDebugString ("dhahelper: entering DriverEntry"); | |
83 | |
84 RtlInitUnicodeString (&DeviceNameUnicodeString, L"\\Device\\DHAHELPER"); | |
85 | |
86 // Create an EXCLUSIVE device object (only 1 thread at a time | |
87 // can make requests to this device). | |
88 | |
89 ntStatus = IoCreateDevice(DriverObject,0,&DeviceNameUnicodeString,FILE_DEVICE_DHAHELPER,0,TRUE,&DeviceObject); | |
90 | |
91 if (NT_SUCCESS(ntStatus)){ | |
92 // Create dispatch points for device control, create, close. | |
93 DriverObject->MajorFunction[IRP_MJ_CREATE] = | |
94 DriverObject->MajorFunction[IRP_MJ_CLOSE] = | |
95 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dhahelperdispatch; | |
96 DriverObject->DriverUnload = dhahelperunload; | |
97 | |
98 // Create a symbolic link, e.g. a name that a Win32 app can specify | |
99 // to open the device. | |
100 | |
101 RtlInitUnicodeString (&DeviceLinkUnicodeString, L"\\DosDevices\\DHAHELPER"); | |
102 | |
103 ntStatus = IoCreateSymbolicLink(&DeviceLinkUnicodeString,&DeviceNameUnicodeString); | |
104 | |
105 if (!NT_SUCCESS(ntStatus)){ | |
106 // Symbolic link creation failed- note this & then delete the | |
107 // device object (it's useless if a Win32 app can't get at it). | |
108 OutputDebugString ("dhahelper: IoCreateSymbolicLink failed"); | |
109 IoDeleteDevice (DeviceObject); | |
110 } | |
111 } | |
112 else{ | |
113 OutputDebugString ("dhahelper: IoCreateDevice failed"); | |
114 } | |
115 OutputDebugString ("dhahelper: leaving DriverEntry"); | |
116 return ntStatus; | |
117 } | |
118 | |
119 | |
120 // Process the IRPs sent to this device | |
121 | |
24541 | 122 static STDCALL NTSTATUS dhahelperdispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp){ |
12057 | 123 PIO_STACK_LOCATION IrpStack; |
124 ULONG dwInputBufferLength; | |
125 ULONG dwOutputBufferLength; | |
126 ULONG dwIoControlCode; | |
127 PVOID pvIOBuffer; | |
128 NTSTATUS ntStatus; | |
129 dhahelper_t dhahelper_priv; | |
130 | |
131 OutputDebugString ("dhahelper: entering dhahelperdispatch"); | |
132 | |
133 // Init to default settings | |
134 | |
135 Irp->IoStatus.Status = STATUS_SUCCESS; | |
136 Irp->IoStatus.Information = 0; | |
137 | |
138 IrpStack = IoGetCurrentIrpStackLocation(Irp); | |
139 | |
140 // Get the pointer to the input/output buffer and it's length | |
141 | |
142 pvIOBuffer = Irp->AssociatedIrp.SystemBuffer; | |
143 dwInputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; | |
144 dwOutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; | |
145 | |
146 switch (IrpStack->MajorFunction){ | |
147 case IRP_MJ_CREATE: | |
148 OutputDebugString("dhahelper: IRP_MJ_CREATE"); | |
149 break; | |
150 case IRP_MJ_CLOSE: | |
151 OutputDebugString("dhahelper: IRP_MJ_CLOSE"); | |
152 break; | |
153 case IRP_MJ_DEVICE_CONTROL: | |
154 OutputDebugString("dhahelper: IRP_MJ_DEVICE_CONTROL"); | |
155 dwIoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; | |
156 switch (dwIoControlCode){ | |
157 case IOCTL_DHAHELPER_ENABLEDIRECTIO: | |
158 OutputDebugString("dhahelper: IOCTL_DHAHELPER_ENABLEDIRECTIO"); | |
159 pIOPM = MmAllocateNonCachedMemory(sizeof(IOPM)); | |
160 if (pIOPM){ | |
161 RtlZeroMemory(pIOPM, sizeof(IOPM)); | |
162 Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1); | |
163 Ke386SetIoAccessMap(1, pIOPM); | |
164 } | |
165 else Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; | |
166 break; | |
167 case IOCTL_DHAHELPER_DISABLEDIRECTIO: | |
168 OutputDebugString("dhahelper: IOCTL_DHAHELPER_DISABLEDIRECTIO"); | |
169 if (pIOPM){ | |
170 Ke386IoSetAccessProcess(PsGetCurrentProcess(), 0); | |
171 Ke386SetIoAccessMap(1, pIOPM); | |
172 MmFreeNonCachedMemory(pIOPM, sizeof(IOPM)); | |
173 pIOPM = NULL; | |
174 } | |
175 break; | |
176 case IOCTL_DHAHELPER_MAPPHYSTOLIN: | |
177 OutputDebugString("dhahelper: IOCTL_DHAHELPER_MAPPHYSTOLIN"); | |
178 if (dwInputBufferLength){ | |
179 memcpy (&dhahelper_priv, pvIOBuffer, dwInputBufferLength); | |
180 ntStatus = MapPhysicalMemoryToLinearSpace(dhahelper_priv.base,dhahelper_priv.size,&dhahelper_priv.ptr); | |
181 if (NT_SUCCESS(ntStatus)){ | |
182 memcpy (pvIOBuffer, &dhahelper_priv, dwInputBufferLength); | |
183 Irp->IoStatus.Information = dwInputBufferLength; | |
184 } | |
185 Irp->IoStatus.Status = ntStatus; | |
186 } | |
187 else Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; | |
188 break; | |
189 case IOCTL_DHAHELPER_UNMAPPHYSADDR: | |
190 OutputDebugString("dhahelper: IOCTL_DHAHELPER_UNMAPPHYSADDR"); | |
191 if (dwInputBufferLength){ | |
192 memcpy (&dhahelper_priv, pvIOBuffer, dwInputBufferLength); | |
193 ntStatus = UnmapPhysicalMemory(dhahelper_priv.ptr); | |
194 Irp->IoStatus.Status = ntStatus; | |
195 } | |
196 else | |
197 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; | |
198 break; | |
199 default: | |
200 OutputDebugString("dhahelper: unknown IRP_MJ_DEVICE_CONTROL"); | |
201 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; | |
202 break; | |
203 } | |
204 break; | |
205 } | |
206 | |
207 // DON'T get cute and try to use the status field of the irp in the | |
208 // return status. That IRP IS GONE as soon as you call IoCompleteRequest. | |
209 | |
210 ntStatus = Irp->IoStatus.Status; | |
211 | |
212 IoCompleteRequest (Irp, IO_NO_INCREMENT); | |
213 | |
214 // We never have pending operation so always return the status code. | |
215 | |
216 OutputDebugString("dhahelper: leaving dhahelperdispatch"); | |
217 | |
218 return ntStatus; | |
219 } | |
220 | |
221 // Delete the associated device and return | |
222 | |
24541 | 223 static STDCALL void dhahelperunload(IN PDRIVER_OBJECT DriverObject){ |
12057 | 224 UNICODE_STRING DeviceLinkUnicodeString; |
225 NTSTATUS ntStatus=STATUS_SUCCESS; | |
226 OutputDebugString ("dhahelper: entering dhahelperunload"); | |
227 OutputDebugString ("dhahelper: unmapping remaining memory"); | |
228 | |
229 while(alloccount && (ntStatus==STATUS_SUCCESS))ntStatus = UnmapPhysicalMemory(alloclist[alloccount-1].UserVirtualAddress); | |
230 RtlInitUnicodeString (&DeviceLinkUnicodeString, L"\\DosDevices\\DHAHELPER"); | |
231 ntStatus = IoDeleteSymbolicLink (&DeviceLinkUnicodeString); | |
232 | |
233 if (NT_SUCCESS(ntStatus)){ | |
234 IoDeleteDevice (DriverObject->DeviceObject); | |
235 } | |
236 else { | |
237 OutputDebugString ("dhahelper: IoDeleteSymbolicLink failed"); | |
238 } | |
239 OutputDebugString ("dhahelper: leaving dhahelperunload"); | |
240 } | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 /************************* memory mapping functions ******************************/ | |
248 //unlike the functions of other io helpers these functions allow to map adapter memory on windows xp | |
249 //even if it has alread been mapped by the original driver | |
250 //the technique used is described in | |
251 //http://support.microsoft.com/default.aspx?scid=kb;en-us;q189327 | |
252 //furthermore it keeps a list of mapped areas to free them when the driver gets unloaded | |
253 //I'm not sure what the limitations of ZwMapViewOfSection are but mapping 128MB videoram (that is probably already mapped by the gfxcard driver) | |
254 //won't work so it is generally a good idea to map only the memory you really need | |
255 | |
24541 | 256 static STDCALL NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,ULONG PhysMemSizeInBytes,PVOID *PhysMemLin){ |
12057 | 257 alloc_priv* alloclisttmp; |
258 PMDL Mdl=NULL; | |
259 PVOID SystemVirtualAddress=NULL; | |
260 PVOID UserVirtualAddress=NULL; | |
261 PHYSICAL_ADDRESS pStartPhysAddress; | |
262 OutputDebugString ("dhahelper: entering MapPhysicalMemoryToLinearSpace"); | |
263 | |
24541 | 264 #ifdef _WIN64 |
12057 | 265 pStartPhysAddress.QuadPart = (ULONGLONG)pPhysAddress; |
24541 | 266 #else |
267 pStartPhysAddress.QuadPart = (ULONGLONG)(ULONG)pPhysAddress; | |
268 #endif | |
269 #ifndef NO_SEH | |
12057 | 270 __try { |
24541 | 271 #endif |
12057 | 272 SystemVirtualAddress=MmMapIoSpace(pStartPhysAddress,PhysMemSizeInBytes, /*MmWriteCombined*/MmNonCached); |
273 if(!SystemVirtualAddress){ | |
274 OutputDebugString("dhahelper: MmMapIoSpace failed"); | |
275 return STATUS_INVALID_PARAMETER; | |
276 } | |
277 OutputDebugString("dhahelper: SystemVirtualAddress 0x%x",SystemVirtualAddress); | |
278 Mdl=IoAllocateMdl(SystemVirtualAddress, PhysMemSizeInBytes, FALSE, FALSE,NULL); | |
279 if(!Mdl){ | |
280 OutputDebugString("dhahelper: IoAllocateMdl failed"); | |
281 return STATUS_INSUFFICIENT_RESOURCES; | |
282 } | |
283 OutputDebugString("dhahelper: Mdl 0x%x",Mdl); | |
284 MmBuildMdlForNonPagedPool(Mdl); | |
24541 | 285 #ifdef _WIN64 |
286 UserVirtualAddress = (PVOID)(((ULONGLONG)PAGE_ALIGN(MmMapLockedPages(Mdl,UserMode))) + MmGetMdlByteOffset(Mdl)); | |
287 #else | |
12057 | 288 UserVirtualAddress = (PVOID)(((ULONG)PAGE_ALIGN(MmMapLockedPages(Mdl,UserMode))) + MmGetMdlByteOffset(Mdl)); |
24541 | 289 #endif |
12057 | 290 if(!UserVirtualAddress){ |
291 OutputDebugString("dhahelper: MmMapLockedPages failed"); | |
292 return STATUS_INSUFFICIENT_RESOURCES; | |
293 } | |
294 OutputDebugString("dhahelper: UserVirtualAddress 0x%x",UserVirtualAddress); | |
24541 | 295 #ifndef NO_SEH |
12057 | 296 }__except(EXCEPTION_EXECUTE_HANDLER){ |
297 NTSTATUS ntStatus; | |
298 ntStatus = GetExceptionCode(); | |
299 OutputDebugString("dhahelper: MapPhysicalMemoryToLinearSpace failed due to exception 0x%0x\n", ntStatus); | |
300 return ntStatus; | |
301 } | |
24541 | 302 #endif |
12057 | 303 |
304 | |
305 OutputDebugString("dhahelper: adding data to internal allocation list"); | |
306 alloclisttmp=MmAllocateNonCachedMemory((alloccount+1)*sizeof(alloc_priv)); | |
307 | |
308 | |
309 if(!alloclisttmp){ | |
310 OutputDebugString("dhahelper: not enough memory to create temporary allocation list"); | |
311 MmUnmapLockedPages(UserVirtualAddress, Mdl); | |
312 IoFreeMdl(Mdl); | |
313 return STATUS_INSUFFICIENT_RESOURCES; | |
314 } | |
315 if(alloccount){ | |
316 memcpy(alloclisttmp,alloclist,alloccount * sizeof(alloc_priv)); | |
317 MmFreeNonCachedMemory(alloclist,alloccount*sizeof(alloc_priv)); | |
318 } | |
319 alloclist=alloclisttmp; | |
320 alloclist[alloccount].Mdl=Mdl; | |
321 alloclist[alloccount].SystemVirtualAddress=SystemVirtualAddress; | |
322 alloclist[alloccount].UserVirtualAddress=UserVirtualAddress; | |
323 alloclist[alloccount].PhysMemSizeInBytes=PhysMemSizeInBytes; | |
324 ++alloccount; | |
325 | |
326 *PhysMemLin=UserVirtualAddress; | |
327 | |
328 OutputDebugString("dhahelper: leaving MapPhysicalMemoryToLinearSpace"); | |
329 return STATUS_SUCCESS; | |
330 } | |
331 | |
24541 | 332 static STDCALL NTSTATUS UnmapPhysicalMemory(PVOID UserVirtualAddress){ |
12057 | 333 unsigned int i; |
334 unsigned int x=0; | |
335 unsigned int alloccounttmp=alloccount; | |
336 OutputDebugString("dhahelper: entering UnmapPhysicalMemory to unmapp 0x%x",UserVirtualAddress); | |
337 if(!alloccount){ | |
338 OutputDebugString("dhahelper: UnmapPhysicalMemory: nothing todo -> leaving..."); | |
339 return STATUS_SUCCESS; | |
340 } | |
341 | |
342 for(i=0;i<alloccount;i++){ | |
343 if(alloclist[i].UserVirtualAddress!=UserVirtualAddress){ | |
344 if(x!=i){ | |
345 alloclist[x].Mdl=alloclist[i].Mdl; | |
346 alloclist[x].SystemVirtualAddress=alloclist[i].SystemVirtualAddress; | |
347 alloclist[x].UserVirtualAddress=alloclist[i].UserVirtualAddress; | |
348 alloclist[x].PhysMemSizeInBytes=alloclist[i].PhysMemSizeInBytes; | |
349 | |
350 } | |
351 x++; | |
352 } | |
353 else if(alloclist[i].UserVirtualAddress==UserVirtualAddress){ | |
354 if(x==i){ | |
24541 | 355 #ifndef NO_SEH |
12057 | 356 __try { |
24541 | 357 #endif |
12057 | 358 MmUnmapLockedPages(alloclist[x].UserVirtualAddress, alloclist[x].Mdl); |
359 IoFreeMdl(alloclist[x].Mdl); | |
360 MmUnmapIoSpace(alloclist[x].SystemVirtualAddress,alloclist[x].PhysMemSizeInBytes); | |
24541 | 361 #ifndef NO_SEH |
12057 | 362 }__except(EXCEPTION_EXECUTE_HANDLER){ |
363 NTSTATUS ntStatus; | |
364 ntStatus = GetExceptionCode(); | |
365 OutputDebugString("dhahelper: UnmapPhysicalMemory failed due to exception 0x%0x (Mdl 0x%x)\n", ntStatus,alloclist[x].Mdl); | |
366 return ntStatus; | |
367 } | |
24541 | 368 #endif |
12057 | 369 } |
370 alloccounttmp--; | |
371 } | |
372 | |
373 } | |
374 | |
375 if(alloccounttmp){ | |
376 alloc_priv* alloclisttmp; | |
377 alloclisttmp=MmAllocateNonCachedMemory(alloccounttmp*sizeof(alloc_priv)); | |
378 if(!alloclisttmp){ | |
379 OutputDebugString("dhahelper: not enough memory to create temporary allocation list"); | |
380 return STATUS_INSUFFICIENT_RESOURCES; | |
381 } | |
382 memcpy(alloclisttmp,alloclist,alloccounttmp * sizeof(alloc_priv)); | |
383 MmFreeNonCachedMemory(alloclist,alloccount*sizeof(alloc_priv)); | |
384 alloclist=alloclisttmp; | |
385 } | |
386 alloccount=alloccounttmp; | |
387 | |
388 OutputDebugString("dhahelper: leaving UnmapPhysicalMemory"); | |
389 return STATUS_SUCCESS; | |
390 } |