3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: hal/x86/adapter.c (from ntoskrnl/io/adapter.c)
6 * PURPOSE: DMA handling
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Vizzini (vizzini@plasmic.com)
11 * 18-Oct-2003 Vizzini DMA support modifications
14 /* INCLUDES *****************************************************************/
20 /* Hmm, needed for KDBG := 1. Why? */
21 extern POBJECT_TYPE IMPORTED IoAdapterObjectType
;
22 #undef KeGetCurrentIrql
24 /* FUNCTIONS *****************************************************************/
26 /* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
30 HalAllocateAdapterChannel(
31 PADAPTER_OBJECT AdapterObject
,
32 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
33 ULONG NumberOfMapRegisters
,
34 PDRIVER_CONTROL ExecutionRoutine
)
36 * FUNCTION: Sets up an ADAPTER_OBJECT with map registers
38 * - AdapterObject: pointer to an ADAPTER_OBJECT to set up
39 * - WaitContextBlock: Context block to be used with ExecutionRoutine
40 * - NumberOfMapRegisters: number of map registers requested
41 * - ExecutionRoutine: callback to call when map registers are allocated
43 * STATUS_INSUFFICIENT_RESOURCES if map registers cannot be allocated
44 * STATUS_SUCCESS in all other cases, including if the callbacak had
45 * to be queued for later delivery
47 * - the ADAPTER_OBJECT struct is undocumented; please make copious
48 * notes in hal.h if anything is changed or improved since there is
49 * no other documentation for this data structure
51 * - it's possible that some of this code is in the wrong place
52 * - there are many unhandled cases
55 LARGE_INTEGER MinAddress
;
56 LARGE_INTEGER MaxAddress
;
57 LARGE_INTEGER BoundryAddressMultiple
;
58 IO_ALLOCATION_ACTION Retval
;
60 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
63 FIXME: return STATUS_INSUFFICIENT_RESOURCES if the NumberOfMapRegisters
64 requested is larger than the value returned by IoGetDmaAdapter.
67 /* set up the wait context block in case we can't run right away */
68 WaitContextBlock
->DeviceRoutine
= ExecutionRoutine
;
69 WaitContextBlock
->NumberOfMapRegisters
= NumberOfMapRegisters
;
71 /* returns true if queued, else returns false and sets the queue to busy */
72 if(KeInsertDeviceQueue(&AdapterObject
->ChannelWaitQueue
, &WaitContextBlock
->WaitQueueEntry
))
73 return STATUS_SUCCESS
;
75 /* 24-bit max address due to 16-bit dma controllers */
76 MinAddress
.QuadPart
= 0x0000000;
77 MaxAddress
.QuadPart
= 0x1000000;
78 BoundryAddressMultiple
.QuadPart
= 0;
80 /* why 64K alignment? */
82 * X86 lacks map registers, so for now, we allocate a contiguous
83 * block of physical memory <16MB and copy all DMA buffers into
84 * that. This can be optimized.
86 * FIXME: We propably shouldn't allocate the memory here for common
87 * buffer transfers. See a comment in IoMapTransfer about common buffer
90 AdapterObject
->MapRegisterBase
= MmAllocateContiguousAlignedMemory(
91 NumberOfMapRegisters
* PAGE_SIZE
,
94 BoundryAddressMultiple
,
98 if(!AdapterObject
->MapRegisterBase
)
99 return STATUS_INSUFFICIENT_RESOURCES
;
101 AdapterObject
->CommittedMapRegisters
= NumberOfMapRegisters
;
103 /* call the client's AdapterControl callback with its map registers and context */
104 Retval
= ExecutionRoutine(WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
105 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
108 * KeepObject: don't free any resources; the ADAPTER_OBJECT is still in use
109 * and the caller will call IoFreeAdapterChannel later
111 * DeallocateObject: Deallocate the map registers and release the ADAPTER_OBJECT
112 * so someone else can use it
114 * DeallocateObjectKeepRegisters: release the ADAPTER_OBJECT but hang on to
115 * the map registers. The client will later call IoFreeMapRegisters.
117 * NOTE - IoFreeAdapterChannel runs the queue, so it must be called
118 * unless the adapter object is not to be freed.
120 if( Retval
== DeallocateObject
)
121 IoFreeAdapterChannel(AdapterObject
);
122 else if(Retval
== DeallocateObjectKeepRegisters
)
124 /* don't free the allocated map registers - this is what IoFreeAdapterChannel checks */
125 AdapterObject
->CommittedMapRegisters
= 0;
126 IoFreeAdapterChannel(AdapterObject
);
130 * if we don't call IoFreeAdapterChannel, the next device won't get de-queued,
131 * which is what we want.
134 return STATUS_SUCCESS
;
140 IN PADAPTER_OBJECT AdapterObject
,
141 IN ULONG SizeOfMapBuffers
)
143 * FUNCTION: Allocate initial, or additional, map buffers for IO adapters.
145 * AdapterObject: DMA adapter to allocate buffers for.
146 * SizeOfMapBuffers: Size of the map buffers to allocate
148 * - Needs to be tested...
151 //ULONG PagesToAllocate = BYTES_TO_PAGES(SizeOfMapBuffers);
153 /* TODO: Allocation */
158 PADAPTER_OBJECT STDCALL
159 HalpAllocateAdapterEx(
160 ULONG NumberOfMapRegisters
,
162 BOOLEAN Dma32BitAddresses
)
164 * FUNCTION: Allocates an ADAPTER_OBJECT, optionally creates the Master Adapter.
166 * - NumberOfMapRegisters: Number of map registers to allocate
167 * - IsMaster: Wether this is a Master Device or not
168 * - Dma32BitAddresses: Wether 32-bit Addresses are supported
170 * - Pointer to Adapter Object, or NULL if failure.
172 * - Some stuff is unhandled/incomplete
175 OBJECT_ATTRIBUTES ObjectAttributes
;
179 ULONG AllowedMapRegisters
= 64;
180 PADAPTER_OBJECT AdapterObject
;
183 /* Allocate the Master Adapter if we haven't already
184 but make sure we're not asked to do it now, and also check if we need it */
185 if ((MasterAdapter
== NULL
) && (!IsMaster
) && (NumberOfMapRegisters
)) {
187 /* Allocate and Save */
188 DPRINT("Allocating the Master Adapter Object\n");
189 MasterAdapter
= HalpAllocateAdapterEx(NumberOfMapRegisters
,
193 /* Cancel on Failure */
194 DPRINT("Checking if Master Adapter was allocated properly\n");
195 if (!MasterAdapter
) return NULL
;
198 /* Initialize the Object Attributes for the Adapter Object */
199 InitializeObjectAttributes(&ObjectAttributes
,
205 /* Check if this is the Master Adapter, in which case we need to allocate the bitmap */
207 /* Size due to the Bitmap + Bytes in the Bitmap Buffer (8 bytes, 64 bits)*/
208 BitmapSize
= sizeof(RTL_BITMAP
) + (AllowedMapRegisters
+ 7) / 8;
210 /* We will put the Bitmap Buffer after the Adapter Object for simplicity */
211 ObjectSize
= sizeof(ADAPTER_OBJECT
) + BitmapSize
;
213 ObjectSize
= sizeof(ADAPTER_OBJECT
);
216 /* Create and Allocate the Object */
217 DPRINT("Creating the Object\n");
218 Status
= ObCreateObject(KernelMode
,
226 (PVOID
)&AdapterObject
);
228 if (!NT_SUCCESS(Status
)) return NULL
;
230 /* Add a Reference */
231 DPRINT("Referencing the Object\n");
232 Status
= ObReferenceObjectByPointer(AdapterObject
,
233 FILE_READ_DATA
| FILE_WRITE_DATA
,
237 if (!NT_SUCCESS(Status
)) return NULL
;
239 /* It's a Valid Object, so now we can play with the memory */
240 RtlZeroMemory(AdapterObject
, sizeof(ADAPTER_OBJECT
));
242 /* Insert it into the Object Table */
243 DPRINT("Inserting the Object\n");
244 Status
= ObInsertObject(AdapterObject
,
246 FILE_READ_DATA
| FILE_WRITE_DATA
,
251 if (!NT_SUCCESS(Status
)) return NULL
;
253 /* We don't want the handle */
256 /* Set up the Adapter Object fields */
257 AdapterObject
->MapRegistersPerChannel
= 1;
259 /* Set the Master if needed (master only needed if we use Map Registers) */
260 if (NumberOfMapRegisters
) AdapterObject
->MasterAdapter
= MasterAdapter
;
262 /* Initalize the Channel Wait queue, which every adapter has */
263 DPRINT("Initializing the Device Queue of the Object\n");
264 KeInitializeDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
266 /* Initialize the SpinLock, Queue and Bitmap, which are kept in the Master Adapter only */
269 DPRINT("Initializing the Master Adapter Stuff\n");
270 KeInitializeSpinLock(&AdapterObject
->SpinLock
);
271 InitializeListHead(&AdapterObject
->AdapterQueue
);
273 /* As said previously, we put them here for simplicity */
274 AdapterObject
->MapRegisters
= (PVOID
)(AdapterObject
+ 1);
277 RtlInitializeBitMap(AdapterObject
->MapRegisters
,
278 (PULONG
)(AdapterObject
->MapRegisters
+ 1),
279 AllowedMapRegisters
);
281 /* Reset the Bitmap */
282 RtlSetAllBits(AdapterObject
->MapRegisters
);
283 AdapterObject
->NumberOfMapRegisters
= 0;
284 AdapterObject
->CommittedMapRegisters
= 0;
286 /* Allocate Memory for the Map Registers */
287 AdapterObject
->MapRegisterBase
= ExAllocatePool(NonPagedPool
,
288 AllowedMapRegisters
* sizeof(DWORD
));
291 RtlZeroMemory(AdapterObject
->MapRegisterBase
, AllowedMapRegisters
* sizeof(DWORD
));
293 /* Allocate the contigous memory */
294 DPRINT("Allocating Buffers\n");
295 HalpGrowMapBuffers(AdapterObject
, 0x1000000);
298 DPRINT("Adapter Object allocated\n");
299 return AdapterObject
;
304 IoFlushAdapterBuffers (
305 PADAPTER_OBJECT AdapterObject
,
307 PVOID MapRegisterBase
,
310 BOOLEAN WriteToDevice
)
312 * FUNCTION: flush any data remaining in the dma controller's memory into the host memory
314 * AdapterObject: the adapter object to flush
315 * Mdl: original MDL to flush data into
316 * MapRegisterBase: map register base that was just used by IoMapTransfer, etc
317 * CurrentVa: offset into Mdl to be flushed into, same as was passed to IoMapTransfer
318 * Length: length of the buffer to be flushed into
319 * WriteToDevice: True if it's a write, False if it's a read
323 * - This copies data from the map register-backed buffer to the user's target buffer.
324 * Data is not in the user buffer until this is called.
325 * - This is only meaningful on a read operation. Return immediately for a write.
328 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
330 /* this can happen if the card supports scatter/gather */
334 /* mask out (disable) the dma channel */
335 if (AdapterObject
->AdapterNumber
== 1) {
337 /* Set this for Ease */
338 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
341 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
343 /* Set this for Ease */
344 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
347 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, (AdapterObject
->ChannelNumber
- 4) | DMA_SETMASK
);
354 (PVOID
)((DWORD
)MmGetSystemAddressForMdl( Mdl
) + (DWORD
)CurrentVa
- (DWORD
)MmGetMdlVirtualAddress( Mdl
)),
355 MapRegisterBase
, Length
);
362 IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject
)
364 * FUNCTION: frees DMA resources allocated by IoAllocateAdapterChannel
366 * AdapterObject: Adapter object with resources to free
368 * - This function releases the DMA adapter and optionally the map registers
369 * - After releasing the adapter, it checks the adapter's queue and runs
370 * each queued device object in series until the queue is empty
371 * - This is the only way the device queue is emptied.
374 LARGE_INTEGER MaxAddress
;
375 LARGE_INTEGER MinAddress
;
376 LARGE_INTEGER BoundryAddressMultiple
;
377 PWAIT_CONTEXT_BLOCK WaitContextBlock
;
378 IO_ALLOCATION_ACTION Retval
;
382 /* To keep map registers, call here with the following set to 0 */
383 if(AdapterObject
->CommittedMapRegisters
)
384 IoFreeMapRegisters(AdapterObject
, AdapterObject
->MapRegisterBase
, AdapterObject
->CommittedMapRegisters
);
386 if(!(WaitContextBlock
= (PWAIT_CONTEXT_BLOCK
)KeRemoveDeviceQueue(&AdapterObject
->ChannelWaitQueue
)))
390 * the following should really be done elsewhere since this
391 * function really can't return an error code. FIXME.
394 /* 24-bit max address due to 16-bit dma controllers */
395 MinAddress
.QuadPart
= 0x0000000;
396 MaxAddress
.QuadPart
= 0x1000000;
397 BoundryAddressMultiple
.QuadPart
= 0;
399 AdapterObject
->MapRegisterBase
= MmAllocateContiguousAlignedMemory(
400 WaitContextBlock
->NumberOfMapRegisters
* PAGE_SIZE
,
403 BoundryAddressMultiple
,
407 if(!AdapterObject
->MapRegisterBase
)
410 /* call the adapter control routine */
411 Retval
= ((PDRIVER_CONTROL
)WaitContextBlock
->DeviceRoutine
)(WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
412 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
414 if(Retval
== KeepObject
)
416 /* we're done until the caller manually calls IoFreeAdapterChannel */
419 else if(Retval
== DeallocateObjectKeepRegisters
)
421 /* hide the map registers so they aren't deallocated next time around */
422 AdapterObject
->CommittedMapRegisters
= 0;
430 IN PADAPTER_OBJECT AdapterObject
,
431 IN PVOID MapRegisterBase
,
432 IN ULONG NumberOfMapRegisters
)
434 * FUNCTION: free map registers reserved by the system for a DMA
436 * AdapterObject: dma adapter to free map registers on
437 * MapRegisterBase: hadle to map registers to free
438 * NumberOfRegisters: number of map registers to be freed
440 * - XXX real windows has a funky interdependence between IoFreeMapRegisters
441 * and IoFreeAdapterChannel
443 * - needs to be improved to use a real map register implementation
446 if( AdapterObject
->CommittedMapRegisters
)
448 MmFreeContiguousMemory(AdapterObject
->MapRegisterBase
);
449 AdapterObject
->MapRegisterBase
= 0;
454 PHYSICAL_ADDRESS STDCALL
456 IN PADAPTER_OBJECT AdapterObject
,
458 IN PVOID MapRegisterBase
,
460 IN OUT PULONG Length
,
461 IN BOOLEAN WriteToDevice
)
463 * FUNCTION: map a dma for transfer and do the dma if it's a slave
465 * AdapterObject: adapter object to do the dma on. busmaster may pass NULL.
466 * Mdl: locked-down user buffer to DMA in to or out of
467 * MapRegisterBase: handle to map registers to use for this dma. allways NULL
469 * CurrentVa: index into Mdl to transfer into/out of
470 * Length: length of transfer in/out. Only modified on out when doing s/g.
471 * WriteToDevice: TRUE if it's an output dma, FALSE otherwise
473 * If a busmaster: A logical address that can be used to program a dma controller
474 * Otherwise: nothing meaningful
476 * - This function does a copyover to contiguous memory <16MB
477 * - If it's a slave transfer, this function actually performs it.
479 * - If the controller supports scatter/gather, the copyover should not happen
482 PHYSICAL_ADDRESS Address
;
484 ULONG LengthShift
= 0;
486 Address
.QuadPart
= 0;
488 /* Isa System (slave) DMA? */
489 if (MapRegisterBase
&& !AdapterObject
->MasterDevice
)
491 KeAcquireSpinLock(&AdapterObject
->SpinLock
, &OldIrql
);
494 * FIXME: Handle case when doing common-buffer System DMA. In this case,
495 * the buffer described by MDL is already phys. contiguous and below
496 * 16 mega. Driver makes a one-shot call to IoMapTransfer during init.
497 * to program controller with the common-buffer.
499 * UPDATE: Common buffer support is in place, but it's not done in a
500 * clean way. We use the buffer passed by the MDL in case that the
501 * adapter object is marked as auto initialize. I'm not sure if this
502 * is correct and if not, how to do it properly. Note that it's also
503 * possible to allocate the common buffer with different adapter object
504 * and IoMapTransfer must still work in this case. Eventually this should
505 * be cleaned up somehow or at least this comment modified to reflect
507 * -- Filip Navara, 19/07/2004
510 /* if it is a write to the device, copy the caller buffer to the low buffer */
511 if (WriteToDevice
&& !AdapterObject
->AdapterMode
.AutoInitialize
)
513 memcpy(MapRegisterBase
,
514 (char*)MmGetSystemAddressForMdl(Mdl
) + ((ULONG
)CurrentVa
- (ULONG
)MmGetMdlVirtualAddress(Mdl
)),
518 /* Writer Adapter Mode, transfer type */
519 AdapterObject
->AdapterMode
.TransferType
= (WriteToDevice
? WRITE_TRANSFER
: READ_TRANSFER
);
521 /* program up the dma controller, and return */
522 if (!AdapterObject
->AdapterMode
.AutoInitialize
) {
523 Address
= MmGetPhysicalAddress( MapRegisterBase
);
525 Address
= MmGetPhysicalAddress( CurrentVa
);
528 /* 16-bit DMA has a shifted length */
529 if (AdapterObject
->Width16Bits
) {
533 /* Make the Transfer */
534 if (AdapterObject
->AdapterNumber
== 1) {
536 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
; /* For Writing Less Code */
538 /* Mask the Channel */
539 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
542 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
545 WRITE_PORT_UCHAR(&DmaControl1
->Mode
, AdapterObject
->AdapterModeByte
);
547 /* Set the Page Register */
548 WRITE_PORT_UCHAR(AdapterObject
->PagePort
, (UCHAR
)(Address
.u
.LowPart
>> 16));
550 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
551 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
552 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
555 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
556 (UCHAR
)((*Length
>> LengthShift
) - 1));
557 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
558 (UCHAR
)(((*Length
>> LengthShift
) - 1) >> 8));
560 /* Unmask the Channel */
561 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
563 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
; /* For Writing Less Code */
565 /* Mask the Channel */
566 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
569 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
572 WRITE_PORT_UCHAR(&DmaControl2
->Mode
, AdapterObject
->AdapterModeByte
);
574 /* Set the Page Register */
575 WRITE_PORT_UCHAR(AdapterObject
->PagePort
, (UCHAR
)(Address
.u
.LowPart
>> 16));
577 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
578 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
579 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
582 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
583 (UCHAR
)((*Length
>> LengthShift
) - 1));
584 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
585 (UCHAR
)(((*Length
>> LengthShift
) - 1) >> 8));
587 /* Unmask the Channel */
588 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
591 /* Release Spinlock */
592 KeReleaseSpinLock(&AdapterObject
->SpinLock
, OldIrql
);
595 NOTE: Return value should be ignored when doing System DMA.
596 Maybe return some more obvious invalid address here (thou returning
597 MapRegisterBase is also wrong;-)to catch invalid use?
599 Address
.QuadPart
= (ULONG
)MapRegisterBase
;
605 Busmaster with s/g support?
606 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
607 being NULL is used to detect a s/g busmaster.
609 if ((!AdapterObject
&& !MapRegisterBase
) ||
610 (AdapterObject
&& AdapterObject
->MasterDevice
&& AdapterObject
->ScatterGather
))
613 Just return the passed VA's corresponding phys. address.
614 Update length to the number of phys. contiguous bytes found.
618 ULONG MdlPageIndex
, PhysContiguousLen
;
621 MdlPages
= (PULONG
)(Mdl
+ 1);
623 /* Get VA's corresponding mdl phys. page index */
624 MdlPageIndex
= ((ULONG
)CurrentVa
- (ULONG
)Mdl
->StartVa
) / PAGE_SIZE
;
626 /* Get phys. page containing the VA */
627 PhysAddress
= MdlPages
[MdlPageIndex
];
629 PhysContiguousLen
= PAGE_SIZE
- BYTE_OFFSET(CurrentVa
);
631 /* VA to map may span several contiguous phys. pages (unlikely) */
632 while (PhysContiguousLen
< *Length
&&
633 MdlPages
[MdlPageIndex
++] + PAGE_SIZE
== MdlPages
[MdlPageIndex
])
636 Note that allways adding PAGE_SIZE may make PhysContiguousLen greater
637 than Length if buffer doesn't end on page boundary. Take this
638 into consideration below.
640 PhysContiguousLen
+= PAGE_SIZE
;
643 if (PhysContiguousLen
< *Length
)
645 *Length
= PhysContiguousLen
;
648 //add offset to phys. page address
649 Address
.QuadPart
= PhysAddress
+ BYTE_OFFSET(CurrentVa
);
655 Busmaster without s/g support?
656 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
657 not being NULL is used to detect a non s/g busmaster.
659 if ((!AdapterObject
&& MapRegisterBase
) ||
660 (AdapterObject
&& AdapterObject
->MasterDevice
&& !AdapterObject
->ScatterGather
))
663 NOTE: Busmasters doing common-buffer DMA shouldn't call IoMapTransfer, but I don't
664 know if it's illegal... Maybe figure out what to do in this case...
669 memcpy(MapRegisterBase
,
670 (char*)MmGetSystemAddressForMdl(Mdl
) + ((ULONG
)CurrentVa
- (ULONG
)MmGetMdlVirtualAddress(Mdl
)),
674 return MmGetPhysicalAddress(MapRegisterBase
);
677 DPRINT("IoMapTransfer: Unsupported operation\n");