Merge 13159:13510 from trunk
[reactos.git] / reactos / drivers / video / videoprt / agp.c
1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002, 2003, 2004 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; see the file COPYING.LIB.
18 * If not, write to the Free Software Foundation,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id$
22 */
23
24 #include "videoprt.h"
25 #include <initguid.h>
26 #include <ddk/wdmguid.h>
27
28 /* PRIVATE FUNCTIONS **********************************************************/
29
30 STATIC NTSTATUS
31 IopInitiatePnpIrp(
32 PDEVICE_OBJECT DeviceObject,
33 PIO_STATUS_BLOCK IoStatusBlock,
34 ULONG MinorFunction,
35 PIO_STACK_LOCATION Stack OPTIONAL)
36 {
37 PDEVICE_OBJECT TopDeviceObject;
38 PIO_STACK_LOCATION IrpSp;
39 NTSTATUS Status;
40 KEVENT Event;
41 PIRP Irp;
42
43 /* Always call the top of the device stack */
44 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
45
46 KeInitializeEvent(
47 &Event,
48 NotificationEvent,
49 FALSE);
50
51 Irp = IoBuildSynchronousFsdRequest(
52 IRP_MJ_PNP,
53 TopDeviceObject,
54 NULL,
55 0,
56 NULL,
57 &Event,
58 IoStatusBlock);
59
60 /* PNP IRPs are always initialized with a status code of
61 STATUS_NOT_IMPLEMENTED */
62 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
63 Irp->IoStatus.Information = 0;
64
65 IrpSp = IoGetNextIrpStackLocation(Irp);
66 IrpSp->MinorFunction = MinorFunction;
67
68 if (Stack)
69 {
70 RtlMoveMemory(
71 &IrpSp->Parameters,
72 &Stack->Parameters,
73 sizeof(Stack->Parameters));
74 }
75
76 Status = IoCallDriver(TopDeviceObject, Irp);
77 if (Status == STATUS_PENDING)
78 {
79 KeWaitForSingleObject(
80 &Event,
81 Executive,
82 KernelMode,
83 FALSE,
84 NULL);
85 Status = IoStatusBlock->Status;
86 }
87
88 ObDereferenceObject(TopDeviceObject);
89
90 return Status;
91 }
92
93
94 BOOLEAN STDCALL
95 IntAgpCommitPhysical(
96 IN PVOID HwDeviceExtension,
97 IN PVOID PhysicalContext,
98 IN ULONG Pages,
99 IN ULONG Offset)
100 {
101 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
102 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
103 PHYSICAL_ADDRESS MappingAddr = {{0}};
104 PVIDEO_PORT_AGP_MAPPING AgpMapping;
105 NTSTATUS Status;
106
107 DPRINT("AgpCommitPhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n",
108 PhysicalContext, Pages, Offset);
109
110 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
111 AgpBusInterface = &DeviceExtension->AgpInterface;
112 AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext;
113
114 Status = AgpBusInterface->CommitMemory(AgpBusInterface->AgpContext,
115 AgpMapping->MapHandle, Pages, Offset,
116 NULL, &MappingAddr);
117
118 if (!NT_SUCCESS(Status))
119 {
120 DPRINT1("Warning: AgpBusInterface->CommitMemory failed (Status = 0x%x)\n",
121 Status);
122 }
123 return NT_SUCCESS(Status);
124 }
125
126 VOID STDCALL
127 IntAgpFreePhysical(
128 IN PVOID HwDeviceExtension,
129 IN PVOID PhysicalContext,
130 IN ULONG Pages,
131 IN ULONG Offset)
132 {
133 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
134 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
135 PVIDEO_PORT_AGP_MAPPING AgpMapping;
136 NTSTATUS Status;
137
138 DPRINT("AgpFreePhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n",
139 PhysicalContext, Pages, Offset);
140
141 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
142 AgpBusInterface = &DeviceExtension->AgpInterface;
143 AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext;
144
145 Status = AgpBusInterface->FreeMemory(AgpBusInterface->AgpContext,
146 AgpMapping->MapHandle, Pages, Offset);
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT1("Warning: AgpBusInterface->FreeMemory failed (Status = 0x%x)\n",
150 Status);
151 }
152 }
153
154 VOID STDCALL
155 IntAgpReleasePhysical(
156 IN PVOID HwDeviceExtension,
157 IN PVOID PhysicalContext)
158 {
159 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
160 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
161 PVIDEO_PORT_AGP_MAPPING AgpMapping;
162 NTSTATUS Status;
163
164 DPRINT("AgpReleasePhysical - PhysicalContext: 0x%x\n", PhysicalContext);
165
166 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
167 AgpBusInterface = &DeviceExtension->AgpInterface;
168 AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext;
169
170 /* Release memory */
171 Status = AgpBusInterface->ReleaseMemory(AgpBusInterface->AgpContext,
172 AgpMapping->MapHandle);
173 if (!NT_SUCCESS(Status))
174 {
175 DPRINT1("Warning: AgpBusInterface->ReleaseMemory failed (Status = 0x%x)\n",
176 Status);
177 }
178
179 /* Free resources */
180 ExFreePool(AgpMapping);
181 }
182
183 PHYSICAL_ADDRESS STDCALL
184 IntAgpReservePhysical(
185 IN PVOID HwDeviceExtension,
186 IN ULONG Pages,
187 IN VIDEO_PORT_CACHE_TYPE Caching,
188 OUT PVOID *PhysicalContext)
189 {
190 PHYSICAL_ADDRESS ZeroAddress = {{0}};
191 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
192 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
193 MEMORY_CACHING_TYPE MemCachingType;
194 PVIDEO_PORT_AGP_MAPPING AgpMapping;
195 NTSTATUS Status;
196
197 DPRINT("AgpReservePhysical - Pages: %d, Caching: 0x%x\n", Pages, Caching);
198
199 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
200 AgpBusInterface = &DeviceExtension->AgpInterface;
201
202 /* Translate memory caching type */
203 if (Caching == VpNonCached)
204 MemCachingType = MmNonCached;
205 else if (Caching == VpCached)
206 MemCachingType = MmCached;
207 else if (Caching == VpWriteCombined)
208 MemCachingType = MmWriteCombined;
209 else
210 {
211 DPRINT1("Invalid caching type %d!\n", Caching);
212 return ZeroAddress;
213 }
214
215 /* Allocate an AGP mapping structure */
216 AgpMapping = ExAllocatePoolWithTag(PagedPool,
217 sizeof(VIDEO_PORT_AGP_MAPPING),
218 TAG_VIDEO_PORT);
219 if (AgpMapping == NULL)
220 {
221 DPRINT1("Out of memory! Couldn't allocate AGP mapping structure!\n");
222 return ZeroAddress;
223 }
224 RtlZeroMemory(AgpMapping, sizeof(VIDEO_PORT_AGP_MAPPING));
225
226 /* Reserve memory for the AGP bus */
227 Status = AgpBusInterface->ReserveMemory(AgpBusInterface->AgpContext,
228 Pages,
229 MemCachingType,
230 &AgpMapping->MapHandle,
231 &AgpMapping->PhysicalAddress);
232 if (!NT_SUCCESS(Status) || AgpMapping->MapHandle == NULL)
233 {
234 ExFreePool(AgpMapping);
235 DPRINT1("Warning: AgpBusInterface->ReserveMemory failed (Status = 0x%x)\n",
236 Status);
237 return ZeroAddress;
238 }
239
240 /* Fill the rest of the AGP mapping */
241 AgpMapping->NumberOfPages = Pages;
242
243 *PhysicalContext = (PVOID)AgpMapping;
244 return AgpMapping->PhysicalAddress;
245 }
246
247
248 PVOID STDCALL
249 IntAgpCommitVirtual(
250 IN PVOID HwDeviceExtension,
251 IN PVOID VirtualContext,
252 IN ULONG Pages,
253 IN ULONG Offset)
254 {
255 PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping;
256 PVOID BaseAddress = NULL;
257 NTSTATUS Status;
258
259 DPRINT("AgpCommitVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n",
260 VirtualContext, Pages, Offset);
261
262 VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext;
263
264 /* I think the NT API provides no way of reserving a part of the address space
265 * and setting it up to map into a specified range of physical memory later.
266 * This means that we will have to release some of the reserved virtual memory
267 * and map the physical memory into it using MapViewOfSection.
268 *
269 * - blight (2004-12-21)
270 */
271
272 if (VirtualMapping->ProcessHandle == NULL)
273 {
274 /* FIXME: not implemented */
275 }
276 else /* ProcessHandle != NULL */
277 {
278 /* Release some virtual memory */
279 ULONG Size = Pages * PAGE_SIZE;
280 ULONG OffsetInBytes = Offset * PAGE_SIZE;
281 BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
282 OffsetInBytes);
283 PHYSICAL_ADDRESS PhysicalAddress = VirtualMapping->AgpMapping->PhysicalAddress;
284 PhysicalAddress.QuadPart += OffsetInBytes;
285
286 Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle,
287 &BaseAddress,
288 &Size, MEM_RELEASE);
289 if (!NT_SUCCESS(Status))
290 {
291 DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status);
292 return NULL;
293 }
294 ASSERT(Size == Pages * PAGE_SIZE);
295 ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
296 OffsetInBytes));
297
298 /* Map the physical memory into the released virtual memory area */
299 Status = IntVideoPortMapPhysicalMemory(VirtualMapping->ProcessHandle,
300 PhysicalAddress,
301 Size,
302 PAGE_READWRITE,
303 &BaseAddress);
304 if (!NT_SUCCESS(Status))
305 {
306 DPRINT1("Warning: IntVideoPortMapPhysicalMemory() failed: Status = 0x%x\n", Status);
307 /* Reserve the released virtual memory area again */
308 Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle,
309 &BaseAddress, 0, &Size, MEM_RESERVE,
310 PAGE_NOACCESS);
311 if (!NT_SUCCESS(Status))
312 {
313 DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status);
314 /* FIXME: What to do now?? */
315 ASSERT(0);
316 return NULL;
317 }
318 ASSERT(Size == Pages * PAGE_SIZE);
319 ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
320 OffsetInBytes));
321 return NULL;
322 }
323 ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
324 OffsetInBytes));
325 }
326
327 return BaseAddress;
328 }
329
330 VOID STDCALL
331 IntAgpFreeVirtual(
332 IN PVOID HwDeviceExtension,
333 IN PVOID VirtualContext,
334 IN ULONG Pages,
335 IN ULONG Offset)
336 {
337 PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping;
338 PVOID BaseAddress = NULL;
339 NTSTATUS Status;
340
341 DPRINT("AgpFreeVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n",
342 VirtualContext, Pages, Offset);
343
344 VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext;
345
346 if (VirtualMapping->ProcessHandle == NULL)
347 {
348 /* FIXME: not implemented */
349 }
350 else /* ProcessHandle != NULL */
351 {
352 /* Unmap the section view */
353 ULONG Size = Pages * PAGE_SIZE;
354 ULONG OffsetInBytes = Offset * PAGE_SIZE;
355 BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
356 OffsetInBytes);
357
358 Status = ZwUnmapViewOfSection(VirtualMapping->ProcessHandle, BaseAddress);
359 if (!NT_SUCCESS(Status))
360 {
361 DPRINT1("Warning: ZwUnmapViewOfSection() failed: Status = 0x%x\n", Status);
362 /* FIXME: What to do now?? */
363 ASSERT(0);
364 return;
365 }
366
367 /* And reserve the virtual memory area again */
368 Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle,
369 &BaseAddress, 0, &Size, MEM_RESERVE,
370 PAGE_NOACCESS);
371 if (!NT_SUCCESS(Status))
372 {
373 DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status);
374 /* FIXME: What to do now?? */
375 ASSERT(0);
376 return;
377 }
378 ASSERT(Size == Pages * PAGE_SIZE);
379 ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress +
380 OffsetInBytes));
381 }
382 }
383
384 VOID STDCALL
385 IntAgpReleaseVirtual(
386 IN PVOID HwDeviceExtension,
387 IN PVOID VirtualContext)
388 {
389 PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping;
390 NTSTATUS Status;
391
392 DPRINT("AgpReleaseVirtual - VirtualContext: 0x%x\n", VirtualContext);
393
394 VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext;
395
396 /* Release the virtual memory */
397 if (VirtualMapping->ProcessHandle == NULL)
398 {
399 /* FIXME: not implemented */
400 }
401 else /* ProcessHandle != NULL */
402 {
403 /* Release the allocated virtual memory */
404 ULONG Size = VirtualMapping->AgpMapping->NumberOfPages * PAGE_SIZE;
405 Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle,
406 &VirtualMapping->MappedAddress,
407 &Size, MEM_RELEASE);
408 if (!NT_SUCCESS(Status))
409 {
410 DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status);
411 }
412 }
413
414 /* Free resources */
415 ExFreePool(VirtualMapping);
416 }
417
418 PVOID STDCALL
419 IntAgpReserveVirtual(
420 IN PVOID HwDeviceExtension,
421 IN HANDLE ProcessHandle,
422 IN PVOID PhysicalContext,
423 OUT PVOID *VirtualContext)
424 {
425 PVIDEO_PORT_AGP_MAPPING AgpMapping;
426 PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping;
427 PVOID MappedAddress;
428 NTSTATUS Status;
429
430 DPRINT("AgpReserveVirtual - ProcessHandle: 0x%x PhysicalContext: 0x%x\n",
431 ProcessHandle, PhysicalContext);
432
433 AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext;
434
435 /* Allocate an AGP virtual mapping structure */
436 VirtualMapping = ExAllocatePoolWithTag(PagedPool,
437 sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING),
438 TAG_VIDEO_PORT);
439 if (VirtualMapping == NULL)
440 {
441 DPRINT1("Out of memory! Couldn't allocate AGP virtual mapping structure!\n");
442 return NULL;
443 }
444 RtlZeroMemory(VirtualMapping, sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING));
445
446 /* Reserve a virtual memory area for the physical pages. */
447 if (ProcessHandle == NULL)
448 {
449 /* FIXME: What to do in this case? */
450 ExFreePool(VirtualMapping);
451 return NULL;
452 }
453 else /* ProcessHandle != NULL */
454 {
455 /* Reserve memory for usermode */
456 ULONG Size = AgpMapping->NumberOfPages * PAGE_SIZE;
457 MappedAddress = NULL;
458 Status = ZwAllocateVirtualMemory(ProcessHandle, &MappedAddress, 0, &Size,
459 MEM_RESERVE, PAGE_NOACCESS);
460 if (!NT_SUCCESS(Status))
461 {
462 ExFreePool(VirtualMapping);
463 DPRINT("ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status);
464 return NULL;
465 }
466 }
467
468 /* Fill the AGP virtual mapping */
469 VirtualMapping->AgpMapping = AgpMapping;
470 VirtualMapping->ProcessHandle = ProcessHandle;
471 VirtualMapping->MappedAddress = MappedAddress;
472
473 *VirtualContext = (PVOID)VirtualMapping;
474 return MappedAddress;
475 }
476
477
478 BOOLEAN STDCALL
479 IntAgpSetRate(
480 IN PVOID HwDeviceExtension,
481 IN ULONG Rate)
482 {
483 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
484 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
485
486 DPRINT("AgpSetRate - Rate: %d\n", Rate);
487
488 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
489 AgpBusInterface = &DeviceExtension->AgpInterface;
490
491 return NT_SUCCESS(AgpBusInterface->SetRate(AgpBusInterface->AgpContext, Rate));
492 }
493
494
495 NTSTATUS STDCALL
496 IntAgpGetInterface(
497 IN PVOID HwDeviceExtension,
498 IN OUT PINTERFACE Interface)
499 {
500 IO_STATUS_BLOCK IoStatusBlock;
501 IO_STACK_LOCATION IoStack;
502 NTSTATUS Status;
503 PVIDEO_PORT_AGP_INTERFACE_2 AgpInterface;
504 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
505 PAGP_BUS_INTERFACE_STANDARD AgpBusInterface;
506
507 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
508 AgpBusInterface = &DeviceExtension->AgpInterface;
509 AgpInterface = (PVIDEO_PORT_AGP_INTERFACE_2)Interface;
510
511 ASSERT((Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_2 &&
512 Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE_2)) ||
513 (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1 &&
514 Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE)));
515
516 if (DeviceExtension->NextDeviceObject == NULL)
517 {
518 DPRINT("DeviceExtension->NextDeviceObject is NULL!\n");
519 return STATUS_UNSUCCESSFUL;
520 }
521
522 /* Query the interface from the AGP bus driver */
523 if (DeviceExtension->AgpInterface.Size == 0)
524 {
525 AgpBusInterface->Size = sizeof(AGP_BUS_INTERFACE_STANDARD);
526 if (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1)
527 AgpBusInterface->Version = AGP_BUS_INTERFACE_V1;
528 else /* if (InterfaceVersion == VIDEO_PORT_AGP_INTERFACE_VERSION_2) */
529 AgpBusInterface->Version = AGP_BUS_INTERFACE_V2;
530 IoStack.Parameters.QueryInterface.Size = AgpBusInterface->Size;
531 IoStack.Parameters.QueryInterface.Version = AgpBusInterface->Version;
532 IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)AgpBusInterface;
533 IoStack.Parameters.QueryInterface.InterfaceType =
534 &GUID_AGP_TARGET_BUS_INTERFACE_STANDARD;
535 Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject,
536 &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack);
537 if (!NT_SUCCESS(Status))
538 {
539 DPRINT("IopInitiatePnpIrp() failed! (Status 0x%x)\n", Status);
540 return Status;
541 }
542 DPRINT("Got AGP driver interface!\n");
543 }
544
545 /* FIXME: Not sure if we should wrap the reference/dereference functions */
546 AgpInterface->Context = AgpBusInterface->AgpContext;
547 AgpInterface->InterfaceReference = AgpBusInterface->InterfaceReference;
548 AgpInterface->InterfaceDereference = AgpBusInterface->InterfaceDereference;
549 AgpInterface->AgpReservePhysical = IntAgpReservePhysical;
550 AgpInterface->AgpReleasePhysical = IntAgpReleasePhysical;
551 AgpInterface->AgpCommitPhysical = IntAgpCommitPhysical;
552 AgpInterface->AgpFreePhysical = IntAgpFreePhysical;
553 AgpInterface->AgpReserveVirtual = IntAgpReserveVirtual;
554 AgpInterface->AgpReleaseVirtual = IntAgpReleaseVirtual;
555 AgpInterface->AgpCommitVirtual = IntAgpCommitVirtual;
556 AgpInterface->AgpFreeVirtual = IntAgpFreeVirtual;
557 AgpInterface->AgpAllocationLimit = 0x1000000; /* FIXME: using 16 MB for now */
558
559 if (AgpInterface->Version >= VIDEO_PORT_AGP_INTERFACE_VERSION_2)
560 {
561 AgpInterface->AgpSetRate = IntAgpSetRate;
562 }
563
564 return STATUS_SUCCESS;
565 }
566