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