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