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 *****************************************************************/
16 #include <ddk/ntddk.h>
17 #include <ddk/iotypes.h>
18 #include <internal/ob.h>
19 #include <internal/ps.h>
21 #include <internal/debug.h>
24 /* Hmm, needed for KDBG := 1. Why? */
25 #undef KeGetCurrentIrql
27 /* FUNCTIONS *****************************************************************/
29 /* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
33 HalAllocateAdapterChannel(
34 PADAPTER_OBJECT AdapterObject
,
35 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
36 ULONG NumberOfMapRegisters
,
37 PDRIVER_CONTROL ExecutionRoutine
)
39 * FUNCTION: Sets up an ADAPTER_OBJECT with map registers
41 * - AdapterObject: pointer to an ADAPTER_OBJECT to set up
42 * - WaitContextBlock: Context block to be used with ExecutionRoutine
43 * - NumberOfMapRegisters: number of map registers requested
44 * - ExecutionRoutine: callback to call when map registers are allocated
46 * STATUS_INSUFFICIENT_RESOURCES if map registers cannot be allocated
47 * STATUS_SUCCESS in all other cases, including if the callbacak had
48 * to be queued for later delivery
50 * - the ADAPTER_OBJECT struct is undocumented; please make copious
51 * notes in hal.h if anything is changed or improved since there is
52 * no other documentation for this data structure
54 * - it's possible that some of this code is in the wrong place
55 * - there are many unhandled cases
58 LARGE_INTEGER MinAddress
;
59 LARGE_INTEGER MaxAddress
;
60 LARGE_INTEGER BoundryAddressMultiple
;
61 IO_ALLOCATION_ACTION Retval
;
63 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
66 FIXME: return STATUS_INSUFFICIENT_RESOURCES if the NumberOfMapRegisters
67 requested is larger than the value returned by IoGetDmaAdapter.
70 /* set up the wait context block in case we can't run right away */
71 WaitContextBlock
->DeviceRoutine
= ExecutionRoutine
;
72 WaitContextBlock
->NumberOfMapRegisters
= NumberOfMapRegisters
;
74 /* returns true if queued, else returns false and sets the queue to busy */
75 if(KeInsertDeviceQueue(&AdapterObject
->ChannelWaitQueue
, &WaitContextBlock
->WaitQueueEntry
))
76 return STATUS_SUCCESS
;
78 /* 24-bit max address due to 16-bit dma controllers */
79 MinAddress
.QuadPart
= 0x0000000;
80 MaxAddress
.QuadPart
= 0x1000000;
81 BoundryAddressMultiple
.QuadPart
= 0;
83 /* why 64K alignment? */
85 * X86 lacks map registers, so for now, we allocate a contiguous
86 * block of physical memory <16MB and copy all DMA buffers into
87 * that. This can be optimized.
89 * FIXME: We propably shouldn't allocate the memory here for common
90 * buffer transfers. See a comment in IoMapTransfer about common buffer
93 AdapterObject
->MapRegisterBase
= MmAllocateContiguousAlignedMemory(
94 NumberOfMapRegisters
* PAGE_SIZE
,
97 BoundryAddressMultiple
,
101 if(!AdapterObject
->MapRegisterBase
)
102 return STATUS_INSUFFICIENT_RESOURCES
;
104 AdapterObject
->CommittedMapRegisters
= NumberOfMapRegisters
;
106 /* call the client's AdapterControl callback with its map registers and context */
107 Retval
= ExecutionRoutine(WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
108 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
111 * KeepObject: don't free any resources; the ADAPTER_OBJECT is still in use
112 * and the caller will call IoFreeAdapterChannel later
114 * DeallocateObject: Deallocate the map registers and release the ADAPTER_OBJECT
115 * so someone else can use it
117 * DeallocateObjectKeepRegisters: release the ADAPTER_OBJECT but hang on to
118 * the map registers. The client will later call IoFreeMapRegisters.
120 * NOTE - IoFreeAdapterChannel runs the queue, so it must be called
121 * unless the adapter object is not to be freed.
123 if( Retval
== DeallocateObject
)
124 IoFreeAdapterChannel(AdapterObject
);
125 else if(Retval
== DeallocateObjectKeepRegisters
)
127 /* don't free the allocated map registers - this is what IoFreeAdapterChannel checks */
128 AdapterObject
->CommittedMapRegisters
= 0;
129 IoFreeAdapterChannel(AdapterObject
);
133 * if we don't call IoFreeAdapterChannel, the next device won't get de-queued,
134 * which is what we want.
137 return STATUS_SUCCESS
;
143 IN PADAPTER_OBJECT AdapterObject
,
144 IN ULONG SizeOfMapBuffers
)
146 * FUNCTION: Allocate initial, or additional, map buffers for IO adapters.
148 * AdapterObject: DMA adapter to allocate buffers for.
149 * SizeOfMapBuffers: Size of the map buffers to allocate
151 * - Needs to be tested...
154 //ULONG PagesToAllocate = BYTES_TO_PAGES(SizeOfMapBuffers);
156 /* TODO: Allocation */
161 PADAPTER_OBJECT STDCALL
162 HalpAllocateAdapterEx(
163 ULONG NumberOfMapRegisters
,
165 BOOLEAN Dma32BitAddresses
)
167 * FUNCTION: Allocates an ADAPTER_OBJECT, optionally creates the Master Adapter.
169 * - NumberOfMapRegisters: Number of map registers to allocate
170 * - IsMaster: Wether this is a Master Device or not
171 * - Dma32BitAddresses: Wether 32-bit Addresses are supported
173 * - Pointer to Adapter Object, or NULL if failure.
175 * - Some stuff is unhandled/incomplete
178 OBJECT_ATTRIBUTES ObjectAttributes
;
182 ULONG AllowedMapRegisters
= 64;
183 PADAPTER_OBJECT AdapterObject
;
186 /* Allocate the Master Adapter if we haven't already
187 but make sure we're not asked to do it now, and also check if we need it */
188 if ((MasterAdapter
== NULL
) && (!IsMaster
) && (NumberOfMapRegisters
)) {
190 /* Allocate and Save */
191 DPRINT("Allocating the Master Adapter Object\n");
192 MasterAdapter
= HalpAllocateAdapterEx(NumberOfMapRegisters
,
196 /* Cancel on Failure */
197 DPRINT("Checking if Master Adapter was allocated properly\n");
198 if (!MasterAdapter
) return NULL
;
201 /* Initialize the Object Attributes for the Adapter Object */
202 InitializeObjectAttributes(&ObjectAttributes
,
208 /* Check if this is the Master Adapter, in which case we need to allocate the bitmap */
210 /* Size due to the Bitmap + Bytes in the Bitmap Buffer (8 bytes, 64 bits)*/
211 BitmapSize
= sizeof(RTL_BITMAP
) + (AllowedMapRegisters
+ 7) / 8;
213 /* We will put the Bitmap Buffer after the Adapter Object for simplicity */
214 ObjectSize
= sizeof(ADAPTER_OBJECT
) + BitmapSize
;
216 ObjectSize
= sizeof(ADAPTER_OBJECT
);
219 /* Create and Allocate the Object */
220 DPRINT("Creating the Object\n");
221 Status
= ObCreateObject(KernelMode
,
229 (PVOID
)&AdapterObject
);
231 if (!NT_SUCCESS(Status
)) return NULL
;
233 /* Add a Reference */
234 DPRINT("Referencing the Object\n");
235 Status
= ObReferenceObjectByPointer(AdapterObject
,
236 FILE_READ_DATA
| FILE_WRITE_DATA
,
240 if (!NT_SUCCESS(Status
)) return NULL
;
242 /* It's a Valid Object, so now we can play with the memory */
243 RtlZeroMemory(AdapterObject
, sizeof(ADAPTER_OBJECT
));
245 /* Insert it into the Object Table */
246 DPRINT("Inserting the Object\n");
247 Status
= ObInsertObject(AdapterObject
,
249 FILE_READ_DATA
| FILE_WRITE_DATA
,
254 if (!NT_SUCCESS(Status
)) return NULL
;
256 /* We don't want the handle */
259 /* Set up the Adapter Object fields */
260 AdapterObject
->MapRegistersPerChannel
= 1;
262 /* Set the Master if needed (master only needed if we use Map Registers) */
263 if (NumberOfMapRegisters
) AdapterObject
->MasterAdapter
= MasterAdapter
;
265 /* Initalize the Channel Wait queue, which every adapter has */
266 DPRINT("Initializing the Device Queue of the Object\n");
267 KeInitializeDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
269 /* Initialize the SpinLock, Queue and Bitmap, which are kept in the Master Adapter only */
272 DPRINT("Initializing the Master Adapter Stuff\n");
273 KeInitializeSpinLock(&AdapterObject
->SpinLock
);
274 InitializeListHead(&AdapterObject
->AdapterQueue
);
276 /* As said previously, we put them here for simplicity */
277 AdapterObject
->MapRegisters
= (PVOID
)(AdapterObject
+ 1);
280 RtlInitializeBitMap(AdapterObject
->MapRegisters
,
281 (PULONG
)(AdapterObject
->MapRegisters
+ 1),
282 AllowedMapRegisters
);
284 /* Reset the Bitmap */
285 RtlSetAllBits(AdapterObject
->MapRegisters
);
286 AdapterObject
->NumberOfMapRegisters
= 0;
287 AdapterObject
->CommittedMapRegisters
= 0;
289 /* Allocate Memory for the Map Registers */
290 AdapterObject
->MapRegisterBase
= ExAllocatePool(NonPagedPool
,
291 AllowedMapRegisters
* sizeof(DWORD
));
294 RtlZeroMemory(AdapterObject
->MapRegisterBase
, AllowedMapRegisters
* sizeof(DWORD
));
296 /* Allocate the contigous memory */
297 DPRINT("Allocating Buffers\n");
298 HalpGrowMapBuffers(AdapterObject
, 0x1000000);
301 DPRINT("Adapter Object allocated\n");
302 return AdapterObject
;
307 IoFlushAdapterBuffers (
308 PADAPTER_OBJECT AdapterObject
,
310 PVOID MapRegisterBase
,
313 BOOLEAN WriteToDevice
)
315 * FUNCTION: flush any data remaining in the dma controller's memory into the host memory
317 * AdapterObject: the adapter object to flush
318 * Mdl: original MDL to flush data into
319 * MapRegisterBase: map register base that was just used by IoMapTransfer, etc
320 * CurrentVa: offset into Mdl to be flushed into, same as was passed to IoMapTransfer
321 * Length: length of the buffer to be flushed into
322 * WriteToDevice: True if it's a write, False if it's a read
326 * - This copies data from the map register-backed buffer to the user's target buffer.
327 * Data is not in the user buffer until this is called.
328 * - This is only meaningful on a read operation. Return immediately for a write.
331 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
333 /* this can happen if the card supports scatter/gather */
337 /* mask out (disable) the dma channel */
338 if (AdapterObject
->AdapterNumber
== 1) {
340 /* Set this for Ease */
341 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
344 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
346 /* Set this for Ease */
347 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
350 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, (AdapterObject
->ChannelNumber
- 4) | DMA_SETMASK
);
357 (PVOID
)((DWORD
)MmGetSystemAddressForMdl( Mdl
) + (DWORD
)CurrentVa
- (DWORD
)MmGetMdlVirtualAddress( Mdl
)),
358 MapRegisterBase
, Length
);
365 IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject
)
367 * FUNCTION: frees DMA resources allocated by IoAllocateAdapterChannel
369 * AdapterObject: Adapter object with resources to free
371 * - This function releases the DMA adapter and optionally the map registers
372 * - After releasing the adapter, it checks the adapter's queue and runs
373 * each queued device object in series until the queue is empty
374 * - This is the only way the device queue is emptied.
377 LARGE_INTEGER MaxAddress
;
378 LARGE_INTEGER MinAddress
;
379 LARGE_INTEGER BoundryAddressMultiple
;
380 PWAIT_CONTEXT_BLOCK WaitContextBlock
;
381 IO_ALLOCATION_ACTION Retval
;
385 /* To keep map registers, call here with the following set to 0 */
386 if(AdapterObject
->CommittedMapRegisters
)
387 IoFreeMapRegisters(AdapterObject
, AdapterObject
->MapRegisterBase
, AdapterObject
->CommittedMapRegisters
);
389 if(!(WaitContextBlock
= (PWAIT_CONTEXT_BLOCK
)KeRemoveDeviceQueue(&AdapterObject
->ChannelWaitQueue
)))
393 * the following should really be done elsewhere since this
394 * function really can't return an error code. FIXME.
397 /* 24-bit max address due to 16-bit dma controllers */
398 MinAddress
.QuadPart
= 0x0000000;
399 MaxAddress
.QuadPart
= 0x1000000;
400 BoundryAddressMultiple
.QuadPart
= 0;
402 AdapterObject
->MapRegisterBase
= MmAllocateContiguousAlignedMemory(
403 WaitContextBlock
->NumberOfMapRegisters
* PAGE_SIZE
,
406 BoundryAddressMultiple
,
410 if(!AdapterObject
->MapRegisterBase
)
413 /* call the adapter control routine */
414 Retval
= ((PDRIVER_CONTROL
)WaitContextBlock
->DeviceRoutine
)(WaitContextBlock
->DeviceObject
, WaitContextBlock
->CurrentIrp
,
415 AdapterObject
->MapRegisterBase
, WaitContextBlock
->DeviceContext
);
417 if(Retval
== KeepObject
)
419 /* we're done until the caller manually calls IoFreeAdapterChannel */
422 else if(Retval
== DeallocateObjectKeepRegisters
)
424 /* hide the map registers so they aren't deallocated next time around */
425 AdapterObject
->CommittedMapRegisters
= 0;
433 IN PADAPTER_OBJECT AdapterObject
,
434 IN PVOID MapRegisterBase
,
435 IN ULONG NumberOfMapRegisters
)
437 * FUNCTION: free map registers reserved by the system for a DMA
439 * AdapterObject: dma adapter to free map registers on
440 * MapRegisterBase: hadle to map registers to free
441 * NumberOfRegisters: number of map registers to be freed
443 * - XXX real windows has a funky interdependence between IoFreeMapRegisters
444 * and IoFreeAdapterChannel
446 * - needs to be improved to use a real map register implementation
449 if( AdapterObject
->CommittedMapRegisters
)
451 MmFreeContiguousMemory(AdapterObject
->MapRegisterBase
);
452 AdapterObject
->MapRegisterBase
= 0;
457 PHYSICAL_ADDRESS STDCALL
459 IN PADAPTER_OBJECT AdapterObject
,
461 IN PVOID MapRegisterBase
,
463 IN OUT PULONG Length
,
464 IN BOOLEAN WriteToDevice
)
466 * FUNCTION: map a dma for transfer and do the dma if it's a slave
468 * AdapterObject: adapter object to do the dma on. busmaster may pass NULL.
469 * Mdl: locked-down user buffer to DMA in to or out of
470 * MapRegisterBase: handle to map registers to use for this dma. allways NULL
472 * CurrentVa: index into Mdl to transfer into/out of
473 * Length: length of transfer in/out. Only modified on out when doing s/g.
474 * WriteToDevice: TRUE if it's an output dma, FALSE otherwise
476 * If a busmaster: A logical address that can be used to program a dma controller
477 * Otherwise: nothing meaningful
479 * - This function does a copyover to contiguous memory <16MB
480 * - If it's a slave transfer, this function actually performs it.
482 * - If the controller supports scatter/gather, the copyover should not happen
485 PHYSICAL_ADDRESS Address
;
487 ULONG LengthShift
= 0;
489 Address
.QuadPart
= 0;
491 /* Isa System (slave) DMA? */
492 if (MapRegisterBase
&& !AdapterObject
->MasterDevice
)
494 KeAcquireSpinLock(&AdapterObject
->SpinLock
, &OldIrql
);
497 * FIXME: Handle case when doing common-buffer System DMA. In this case,
498 * the buffer described by MDL is already phys. contiguous and below
499 * 16 mega. Driver makes a one-shot call to IoMapTransfer during init.
500 * to program controller with the common-buffer.
502 * UPDATE: Common buffer support is in place, but it's not done in a
503 * clean way. We use the buffer passed by the MDL in case that the
504 * adapter object is marked as auto initialize. I'm not sure if this
505 * is correct and if not, how to do it properly. Note that it's also
506 * possible to allocate the common buffer with different adapter object
507 * and IoMapTransfer must still work in this case. Eventually this should
508 * be cleaned up somehow or at least this comment modified to reflect
510 * -- Filip Navara, 19/07/2004
513 /* if it is a write to the device, copy the caller buffer to the low buffer */
514 if (WriteToDevice
&& !AdapterObject
->AdapterMode
.AutoInitialize
)
516 memcpy(MapRegisterBase
,
517 (char*)MmGetSystemAddressForMdl(Mdl
) + ((ULONG
)CurrentVa
- (ULONG
)MmGetMdlVirtualAddress(Mdl
)),
521 /* Writer Adapter Mode, transfer type */
522 AdapterObject
->AdapterMode
.TransferType
= (WriteToDevice
? WRITE_TRANSFER
: READ_TRANSFER
);
524 /* program up the dma controller, and return */
525 if (!AdapterObject
->AdapterMode
.AutoInitialize
) {
526 Address
= MmGetPhysicalAddress( MapRegisterBase
);
528 Address
= MmGetPhysicalAddress( CurrentVa
);
531 /* 16-bit DMA has a shifted length */
532 if (AdapterObject
->Width16Bits
) {
536 /* Make the Transfer */
537 if (AdapterObject
->AdapterNumber
== 1) {
539 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
; /* For Writing Less Code */
541 /* Mask the Channel */
542 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
545 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
548 WRITE_PORT_UCHAR(&DmaControl1
->Mode
, AdapterObject
->AdapterModeByte
);
550 /* Set the Page Register */
551 WRITE_PORT_UCHAR(AdapterObject
->PagePort
, (UCHAR
)(Address
.u
.LowPart
>> 16));
553 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
554 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
555 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
558 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
559 (UCHAR
)((*Length
>> LengthShift
) - 1));
560 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
561 (UCHAR
)(((*Length
>> LengthShift
) - 1) >> 8));
563 /* Unmask the Channel */
564 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
566 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
; /* For Writing Less Code */
568 /* Mask the Channel */
569 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_SETMASK
);
572 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
575 WRITE_PORT_UCHAR(&DmaControl2
->Mode
, AdapterObject
->AdapterModeByte
);
577 /* Set the Page Register */
578 WRITE_PORT_UCHAR(AdapterObject
->PagePort
, (UCHAR
)(Address
.u
.LowPart
>> 16));
580 /* Set the Offset Register (apparently always 0 for us if I trust the previous comment) */
581 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
582 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
, 0);
585 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
586 (UCHAR
)((*Length
>> LengthShift
) - 1));
587 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
588 (UCHAR
)(((*Length
>> LengthShift
) - 1) >> 8));
590 /* Unmask the Channel */
591 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
594 /* Release Spinlock */
595 KeReleaseSpinLock(&AdapterObject
->SpinLock
, OldIrql
);
598 NOTE: Return value should be ignored when doing System DMA.
599 Maybe return some more obvious invalid address here (thou returning
600 MapRegisterBase is also wrong;-)to catch invalid use?
602 Address
.QuadPart
= (ULONG
)MapRegisterBase
;
608 Busmaster with s/g support?
609 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
610 being NULL is used to detect a s/g busmaster.
612 if ((!AdapterObject
&& !MapRegisterBase
) ||
613 (AdapterObject
&& AdapterObject
->MasterDevice
&& AdapterObject
->ScatterGather
))
616 Just return the passed VA's corresponding phys. address.
617 Update length to the number of phys. contiguous bytes found.
621 ULONG MdlPageIndex
, PhysContiguousLen
;
624 MdlPages
= (PULONG
)(Mdl
+ 1);
626 /* Get VA's corresponding mdl phys. page index */
627 MdlPageIndex
= ((ULONG
)CurrentVa
- (ULONG
)Mdl
->StartVa
) / PAGE_SIZE
;
629 /* Get phys. page containing the VA */
630 PhysAddress
= MdlPages
[MdlPageIndex
];
632 PhysContiguousLen
= PAGE_SIZE
- BYTE_OFFSET(CurrentVa
);
634 /* VA to map may span several contiguous phys. pages (unlikely) */
635 while (PhysContiguousLen
< *Length
&&
636 MdlPages
[MdlPageIndex
++] + PAGE_SIZE
== MdlPages
[MdlPageIndex
])
639 Note that allways adding PAGE_SIZE may make PhysContiguousLen greater
640 than Length if buffer doesn't end on page boundary. Take this
641 into consideration below.
643 PhysContiguousLen
+= PAGE_SIZE
;
646 if (PhysContiguousLen
< *Length
)
648 *Length
= PhysContiguousLen
;
651 //add offset to phys. page address
652 Address
.QuadPart
= PhysAddress
+ BYTE_OFFSET(CurrentVa
);
658 Busmaster without s/g support?
659 NOTE: old docs allowed busmasters to pass a NULL Adapter. In this case, MapRegisterBase
660 not being NULL is used to detect a non s/g busmaster.
662 if ((!AdapterObject
&& MapRegisterBase
) ||
663 (AdapterObject
&& AdapterObject
->MasterDevice
&& !AdapterObject
->ScatterGather
))
666 NOTE: Busmasters doing common-buffer DMA shouldn't call IoMapTransfer, but I don't
667 know if it's illegal... Maybe figure out what to do in this case...
672 memcpy(MapRegisterBase
,
673 (char*)MmGetSystemAddressForMdl(Mdl
) + ((ULONG
)CurrentVa
- (ULONG
)MmGetMdlVirtualAddress(Mdl
)),
677 return MmGetPhysicalAddress(MapRegisterBase
);
680 DPRINT("IoMapTransfer: Unsupported operation\n");