3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/hal/x86/dma.c
6 * PURPOSE: DMA functions
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Filip Navara (navaraf@reactos.com)
14 * @page DMA Implementation Notes
20 * Abstract encapsulation of physically contiguous buffer that resides
21 * in memory accessible by both the DMA device / controller and the system.
22 * The map registers are allocated and distributed on demand and are
25 * The actual use of map registers is to allow transfers from/to buffer
26 * located in physical memory at address inaccessible by the DMA device /
27 * controller directly. For such transfers the map register buffers
28 * are used as intermediate data storage.
32 * A container for map registers (typically corresponding to one physical
33 * bus connection type). There can be master adapters for 24-bit address
34 * ranges, 32-bit address ranges, etc. Every time a new DMA adapter is
35 * created it's associated with a corresponding master adapter that
36 * is used for any map register allocation requests.
38 * - Bus-master / Slave DMA
40 * Slave DMA is term used for DMA transfers done by the system (E)ISA
41 * controller as opposed to transfers mastered by the device itself
44 * For slave DMA special care is taken to actually access the system
45 * controller and handle the transfers. The relevant code is in
46 * HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers
51 * - Allocation of map registers
53 * Initial set of map registers is allocated on the system start to
54 * ensure that low memory won't get filled up later. Additional map
55 * registers are allocated as needed by HalpGrowMapBuffers. This
56 * routine is called on two places:
58 * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that
59 * more map registers will probably be needed.
60 * - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker
61 * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly)
62 * when no more map registers are free.
64 * Note that even if no more map registers can be allocated it's not
65 * the end of the world. The adapters waiting for free map registers
66 * are queued in the master adapter's queue and once one driver hands
67 * back it's map registers (using IoFreeMapRegisters or indirectly using
68 * the execution routine callback in IoAllocateAdapterChannel) the
69 * queue gets processed and the map registers are reassigned.
72 /* INCLUDES *****************************************************************/
80 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
81 #pragma alloc_text(INIT, HalpInitDma)
84 #define MAX_SG_ELEMENTS 0x10
87 static KEVENT HalpDmaLock
;
88 static LIST_ENTRY HalpDmaAdapterList
;
89 static PADAPTER_OBJECT HalpEisaAdapter
[8];
91 static BOOLEAN HalpEisaDma
;
93 static PADAPTER_OBJECT HalpMasterAdapter
;
96 static const ULONG_PTR HalpEisaPortPage
[8] = {
97 FIELD_OFFSET(DMA_PAGE
, Channel0
),
98 FIELD_OFFSET(DMA_PAGE
, Channel1
),
99 FIELD_OFFSET(DMA_PAGE
, Channel2
),
100 FIELD_OFFSET(DMA_PAGE
, Channel3
),
102 FIELD_OFFSET(DMA_PAGE
, Channel5
),
103 FIELD_OFFSET(DMA_PAGE
, Channel6
),
104 FIELD_OFFSET(DMA_PAGE
, Channel7
)
108 static DMA_OPERATIONS HalpDmaOperations
= {
109 sizeof(DMA_OPERATIONS
),
110 (PPUT_DMA_ADAPTER
)HalPutDmaAdapter
,
111 (PALLOCATE_COMMON_BUFFER
)HalAllocateCommonBuffer
,
112 (PFREE_COMMON_BUFFER
)HalFreeCommonBuffer
,
113 NULL
, /* Initialized in HalpInitDma() */
114 NULL
, /* Initialized in HalpInitDma() */
115 NULL
, /* Initialized in HalpInitDma() */
116 NULL
, /* Initialized in HalpInitDma() */
117 NULL
, /* Initialized in HalpInitDma() */
118 (PGET_DMA_ALIGNMENT
)HalpDmaGetDmaAlignment
,
119 (PREAD_DMA_COUNTER
)HalReadDmaCounter
,
120 /* FIXME: Implement the S/G funtions. */
121 (PGET_SCATTER_GATHER_LIST
)HalGetScatterGatherList
,
122 (PPUT_SCATTER_GATHER_LIST
)HalPutScatterGatherList
,
123 NULL
/*(PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize*/,
124 NULL
/*(PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList*/,
125 NULL
/*(PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList*/
129 #define MAX_MAP_REGISTERS 64
131 #define TAG_DMA ' AMD'
133 /* FUNCTIONS *****************************************************************/
141 * Initialize the DMA Operation table
143 HalpDmaOperations
.AllocateAdapterChannel
= (PALLOCATE_ADAPTER_CHANNEL
)IoAllocateAdapterChannel
;
144 HalpDmaOperations
.FlushAdapterBuffers
= (PFLUSH_ADAPTER_BUFFERS
)IoFlushAdapterBuffers
;
145 HalpDmaOperations
.FreeAdapterChannel
= (PFREE_ADAPTER_CHANNEL
)IoFreeAdapterChannel
;
146 HalpDmaOperations
.FreeMapRegisters
= (PFREE_MAP_REGISTERS
)IoFreeMapRegisters
;
147 HalpDmaOperations
.MapTransfer
= (PMAP_TRANSFER
)IoMapTransfer
;
150 * Check if Extended DMA is available. We're just going to do a random
153 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
.Channel2
), 0x2A);
154 if (READ_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
.Channel2
)) == 0x2A)
156 DPRINT1("Machine supports EISA DMA. Bus type: %lu\n", HalpBusType
);
161 * Intialize all the global variables and allocate master adapter with
164 InitializeListHead(&HalpDmaAdapterList
);
165 KeInitializeEvent(&HalpDmaLock
, NotificationEvent
, TRUE
);
166 HalpMasterAdapter
= HalpDmaAllocateMasterAdapter();
169 * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's
170 * used by IoGetDmaAdapter in the kernel.
172 HalGetDmaAdapter
= HalpGetDmaAdapter
;
177 * @name HalpGetAdapterMaximumPhysicalAddress
179 * Get the maximum physical address acceptable by the device represented
180 * by the passed DMA adapter.
184 HalpGetAdapterMaximumPhysicalAddress(IN PADAPTER_OBJECT AdapterObject
)
186 PHYSICAL_ADDRESS HighestAddress
;
188 if (AdapterObject
->MasterDevice
)
190 if (AdapterObject
->Dma64BitAddresses
)
192 HighestAddress
.QuadPart
= 0xFFFFFFFFFFFFFFFFULL
;
193 return HighestAddress
;
195 else if (AdapterObject
->Dma32BitAddresses
)
197 HighestAddress
.QuadPart
= 0xFFFFFFFF;
198 return HighestAddress
;
202 HighestAddress
.QuadPart
= 0xFFFFFF;
203 return HighestAddress
;
208 * @name HalpGrowMapBuffers
210 * Allocate initial, or additional, map buffers for DMA master adapter.
212 * @param MasterAdapter
213 * DMA master adapter to allocate buffers for.
214 * @param SizeOfMapBuffers
215 * Size of the map buffers to allocate (not including the size
216 * already allocated).
220 HalpGrowMapBuffers(IN PADAPTER_OBJECT AdapterObject
,
221 IN ULONG SizeOfMapBuffers
)
223 PVOID VirtualAddress
;
224 PHYSICAL_ADDRESS PhysicalAddress
;
225 PHYSICAL_ADDRESS HighestAcceptableAddress
;
226 PHYSICAL_ADDRESS LowestAcceptableAddress
;
227 PHYSICAL_ADDRESS BoundryAddressMultiple
;
229 ULONG MapRegisterCount
;
231 /* Check if enough map register slots are available. */
232 MapRegisterCount
= BYTES_TO_PAGES(SizeOfMapBuffers
);
233 if (MapRegisterCount
+ AdapterObject
->NumberOfMapRegisters
> MAX_MAP_REGISTERS
)
235 DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n",
236 AdapterObject
->NumberOfMapRegisters
,
243 * Allocate memory for the new map registers. For 32-bit adapters we use
244 * two passes in order not to waste scare resource (low memory).
246 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
247 LowestAcceptableAddress
.HighPart
= 0;
248 LowestAcceptableAddress
.LowPart
= HighestAcceptableAddress
.LowPart
== 0xFFFFFFFF ? 0x1000000 : 0;
249 BoundryAddressMultiple
.QuadPart
= 0;
251 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(MapRegisterCount
<< PAGE_SHIFT
,
252 LowestAcceptableAddress
,
253 HighestAcceptableAddress
,
254 BoundryAddressMultiple
,
256 if (!(VirtualAddress
) && (LowestAcceptableAddress
.LowPart
))
258 LowestAcceptableAddress
.LowPart
= 0;
259 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(MapRegisterCount
<< PAGE_SHIFT
,
260 LowestAcceptableAddress
,
261 HighestAcceptableAddress
,
262 BoundryAddressMultiple
,
266 if (!VirtualAddress
) return FALSE
;
268 PhysicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
271 * All the following must be done with the master adapter lock held
272 * to prevent corruption.
274 KeAcquireSpinLock(&AdapterObject
->SpinLock
, &OldIrql
);
277 * Setup map register entries for the buffer allocated. Each entry has
278 * a virtual and physical address and corresponds to PAGE_SIZE large
281 if (MapRegisterCount
> 0)
283 PROS_MAP_REGISTER_ENTRY CurrentEntry
, PreviousEntry
;
285 CurrentEntry
= AdapterObject
->MapRegisterBase
+ AdapterObject
->NumberOfMapRegisters
;
289 * Leave one entry free for every non-contiguous memory region
290 * in the map register bitmap. This ensures that we can search
291 * using RtlFindClearBits for contiguous map register regions.
293 * Also for non-EISA DMA leave one free entry for every 64Kb
294 * break, because the DMA controller can handle only coniguous
297 if (CurrentEntry
!= AdapterObject
->MapRegisterBase
)
299 PreviousEntry
= CurrentEntry
- 1;
300 if ((PreviousEntry
->PhysicalAddress
.LowPart
+ PAGE_SIZE
) == PhysicalAddress
.LowPart
)
304 if ((PreviousEntry
->PhysicalAddress
.LowPart
^ PhysicalAddress
.LowPart
) & 0xFFFF0000)
307 AdapterObject
->NumberOfMapRegisters
++;
314 AdapterObject
->NumberOfMapRegisters
++;
318 RtlClearBit(AdapterObject
->MapRegisters
,
319 (ULONG
)(CurrentEntry
- AdapterObject
->MapRegisterBase
));
320 CurrentEntry
->VirtualAddress
= VirtualAddress
;
321 CurrentEntry
->PhysicalAddress
= PhysicalAddress
;
323 PhysicalAddress
.LowPart
+= PAGE_SIZE
;
324 VirtualAddress
= (PVOID
)((ULONG_PTR
)VirtualAddress
+ PAGE_SIZE
);
327 AdapterObject
->NumberOfMapRegisters
++;
329 } while (MapRegisterCount
);
332 KeReleaseSpinLock(&AdapterObject
->SpinLock
, OldIrql
);
338 * @name HalpDmaAllocateMasterAdapter
340 * Helper routine to allocate and initialize master adapter object and it's
341 * associated map register buffers.
347 HalpDmaAllocateMasterAdapter(VOID
)
349 PADAPTER_OBJECT MasterAdapter
;
350 ULONG Size
, SizeOfBitmap
;
352 SizeOfBitmap
= MAX_MAP_REGISTERS
;
353 Size
= sizeof(ADAPTER_OBJECT
);
354 Size
+= sizeof(RTL_BITMAP
);
355 Size
+= (SizeOfBitmap
+ 7) >> 3;
357 MasterAdapter
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_DMA
);
358 if (!MasterAdapter
) return NULL
;
360 RtlZeroMemory(MasterAdapter
, Size
);
362 KeInitializeSpinLock(&MasterAdapter
->SpinLock
);
363 InitializeListHead(&MasterAdapter
->AdapterQueue
);
365 MasterAdapter
->MapRegisters
= (PVOID
)(MasterAdapter
+ 1);
366 RtlInitializeBitMap(MasterAdapter
->MapRegisters
,
367 (PULONG
)(MasterAdapter
->MapRegisters
+ 1),
369 RtlSetAllBits(MasterAdapter
->MapRegisters
);
370 MasterAdapter
->NumberOfMapRegisters
= 0;
371 MasterAdapter
->CommittedMapRegisters
= 0;
373 MasterAdapter
->MapRegisterBase
= ExAllocatePoolWithTag(NonPagedPool
,
375 sizeof(ROS_MAP_REGISTER_ENTRY
),
377 if (!MasterAdapter
->MapRegisterBase
)
379 ExFreePool(MasterAdapter
);
383 RtlZeroMemory(MasterAdapter
->MapRegisterBase
,
384 SizeOfBitmap
* sizeof(ROS_MAP_REGISTER_ENTRY
));
385 if (!HalpGrowMapBuffers(MasterAdapter
, 0x10000))
387 ExFreePool(MasterAdapter
);
391 return MasterAdapter
;
395 * @name HalpDmaAllocateChildAdapter
397 * Helper routine of HalGetAdapter. Allocate child adapter object and
398 * fill out some basic fields.
404 HalpDmaAllocateChildAdapter(IN ULONG NumberOfMapRegisters
,
405 IN PDEVICE_DESCRIPTION DeviceDescription
)
407 PADAPTER_OBJECT AdapterObject
;
408 OBJECT_ATTRIBUTES ObjectAttributes
;
412 InitializeObjectAttributes(&ObjectAttributes
,
414 OBJ_KERNEL_HANDLE
| OBJ_PERMANENT
,
418 Status
= ObCreateObject(KernelMode
,
423 sizeof(ADAPTER_OBJECT
),
426 (PVOID
)&AdapterObject
);
427 if (!NT_SUCCESS(Status
)) return NULL
;
429 Status
= ObReferenceObjectByPointer(AdapterObject
,
430 FILE_READ_DATA
| FILE_WRITE_DATA
,
433 if (!NT_SUCCESS(Status
)) return NULL
;
435 RtlZeroMemory(AdapterObject
, sizeof(ADAPTER_OBJECT
));
437 Status
= ObInsertObject(AdapterObject
,
439 FILE_READ_DATA
| FILE_WRITE_DATA
,
443 if (!NT_SUCCESS(Status
)) return NULL
;
447 AdapterObject
->DmaHeader
.Version
= (USHORT
)DeviceDescription
->Version
;
448 AdapterObject
->DmaHeader
.Size
= sizeof(ADAPTER_OBJECT
);
449 AdapterObject
->DmaHeader
.DmaOperations
= &HalpDmaOperations
;
450 AdapterObject
->MapRegistersPerChannel
= 1;
451 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
452 AdapterObject
->ChannelNumber
= 0xFF;
453 AdapterObject
->MasterAdapter
= HalpMasterAdapter
;
454 KeInitializeDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
456 return AdapterObject
;
461 * @name HalpDmaInitializeEisaAdapter
463 * Setup DMA modes and extended modes for (E)ISA DMA adapter object.
467 HalpDmaInitializeEisaAdapter(IN PADAPTER_OBJECT AdapterObject
,
468 IN PDEVICE_DESCRIPTION DeviceDescription
)
471 DMA_MODE DmaMode
= {{0 }};
472 DMA_EXTENDED_MODE ExtendedMode
= {{ 0 }};
475 Controller
= (DeviceDescription
->DmaChannel
& 4) ? 2 : 1;
479 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController1
);
483 AdapterBaseVa
= (PVOID
)FIELD_OFFSET(EISA_CONTROL
, DmaController2
);
486 AdapterObject
->AdapterNumber
= Controller
;
487 AdapterObject
->ChannelNumber
= (UCHAR
)(DeviceDescription
->DmaChannel
& 3);
488 AdapterObject
->PagePort
= (PUCHAR
)HalpEisaPortPage
[DeviceDescription
->DmaChannel
];
489 AdapterObject
->Width16Bits
= FALSE
;
490 AdapterObject
->AdapterBaseVa
= AdapterBaseVa
;
494 ExtendedMode
.ChannelNumber
= AdapterObject
->ChannelNumber
;
496 switch (DeviceDescription
->DmaSpeed
)
498 case Compatible
: ExtendedMode
.TimingMode
= COMPATIBLE_TIMING
; break;
499 case TypeA
: ExtendedMode
.TimingMode
= TYPE_A_TIMING
; break;
500 case TypeB
: ExtendedMode
.TimingMode
= TYPE_B_TIMING
; break;
501 case TypeC
: ExtendedMode
.TimingMode
= BURST_TIMING
; break;
506 switch (DeviceDescription
->DmaWidth
)
508 case Width8Bits
: ExtendedMode
.TransferSize
= B_8BITS
; break;
509 case Width16Bits
: ExtendedMode
.TransferSize
= B_16BITS
; break;
510 case Width32Bits
: ExtendedMode
.TransferSize
= B_32BITS
; break;
517 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode1
),
522 WRITE_PORT_UCHAR((PUCHAR
)FIELD_OFFSET(EISA_CONTROL
, DmaExtendedMode2
),
529 * Validate setup for non-busmaster DMA adapter. Secondary controller
530 * supports only 16-bit transfers and main controller supports only
531 * 8-bit transfers. Anything else is invalid.
533 if (!DeviceDescription
->Master
)
535 if ((Controller
== 2) && (DeviceDescription
->DmaWidth
== Width16Bits
))
537 AdapterObject
->Width16Bits
= TRUE
;
539 else if ((Controller
!= 1) || (DeviceDescription
->DmaWidth
!= Width8Bits
))
546 DmaMode
.Channel
= AdapterObject
->ChannelNumber
;
547 DmaMode
.AutoInitialize
= DeviceDescription
->AutoInitialize
;
550 * Set the DMA request mode.
552 * For (E)ISA bus master devices just unmask (enable) the DMA channel
553 * and set it to cascade mode. Otherwise just select the right one
554 * bases on the passed device description.
556 if (DeviceDescription
->Master
)
558 DmaMode
.RequestMode
= CASCADE_REQUEST_MODE
;
561 /* Set the Request Data */
562 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
563 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->Mode
, DmaMode
.Byte
);
565 /* Unmask DMA Channel */
566 WRITE_PORT_UCHAR(&((PDMA1_CONTROL
)AdapterBaseVa
)->SingleMask
,
567 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
571 /* Set the Request Data */
572 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->Mode
, DmaMode
.Byte
);
574 /* Unmask DMA Channel */
575 WRITE_PORT_UCHAR(&((PDMA2_CONTROL
)AdapterBaseVa
)->SingleMask
,
576 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
581 if (DeviceDescription
->DemandMode
)
583 DmaMode
.RequestMode
= DEMAND_REQUEST_MODE
;
587 DmaMode
.RequestMode
= SINGLE_REQUEST_MODE
;
591 AdapterObject
->AdapterMode
= DmaMode
;
598 * @name HalGetAdapter
600 * Allocate an adapter object for DMA device.
602 * @param DeviceDescription
603 * Structure describing the attributes of the device.
604 * @param NumberOfMapRegisters
605 * On return filled with the maximum number of map registers the
606 * device driver can allocate for DMA transfer operations.
608 * @return The DMA adapter on success, NULL otherwise.
614 HalGetAdapter(IN PDEVICE_DESCRIPTION DeviceDescription
,
615 OUT PULONG NumberOfMapRegisters
)
617 PADAPTER_OBJECT AdapterObject
= NULL
;
622 /* Validate parameters in device description */
623 if (DeviceDescription
->Version
> DEVICE_DESCRIPTION_VERSION2
) return NULL
;
626 * See if we're going to use ISA/EISA DMA adapter. These adapters are
627 * special since they're reused.
629 * Also note that we check for channel number since there are only 8 DMA
630 * channels on ISA, so any request above this requires new adapter.
632 if (((DeviceDescription
->InterfaceType
== Eisa
) ||
633 (DeviceDescription
->InterfaceType
== Isa
)) || !(DeviceDescription
->Master
))
635 if (((DeviceDescription
->InterfaceType
== Isa
) ||
636 (DeviceDescription
->InterfaceType
== Eisa
)) &&
637 (DeviceDescription
->DmaChannel
>= 8))
652 * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
653 * for cascading the controllers and it's not available for software use.
655 if ((EisaAdapter
) && (DeviceDescription
->DmaChannel
== 4)) return NULL
;
658 * Calculate the number of map registers.
660 * - For EISA and PCI scatter/gather no map registers are needed.
661 * - For ISA slave scatter/gather one map register is needed.
662 * - For all other cases the number of map registers depends on
663 * DeviceDescription->MaximumLength.
665 MaximumLength
= DeviceDescription
->MaximumLength
& MAXLONG
;
666 if ((DeviceDescription
->ScatterGather
) &&
667 ((DeviceDescription
->InterfaceType
== Eisa
) ||
668 (DeviceDescription
->InterfaceType
== PCIBus
)))
672 else if ((DeviceDescription
->ScatterGather
) && !(DeviceDescription
->Master
))
679 * In the equation below the additional map register added by
680 * the "+1" accounts for the case when a transfer does not start
681 * at a page-aligned address.
683 MapRegisters
= BYTES_TO_PAGES(MaximumLength
) + 1;
684 if (MapRegisters
> 16) MapRegisters
= 16;
688 * Acquire the DMA lock that is used to protect adapter lists and
689 * EISA adapter array.
691 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
, FALSE
, NULL
);
694 * Now we must get ahold of the adapter object. For first eight ISA/EISA
695 * channels there are static adapter objects that are reused and updated
696 * on succesive HalGetAdapter calls. In other cases a new adapter object
697 * is always created and it's to the DMA adapter list (HalpDmaAdapterList).
701 AdapterObject
= HalpEisaAdapter
[DeviceDescription
->DmaChannel
];
704 if ((AdapterObject
->NeedsMapRegisters
) &&
705 (MapRegisters
> AdapterObject
->MapRegistersPerChannel
))
707 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
712 if (AdapterObject
== NULL
)
714 AdapterObject
= HalpDmaAllocateChildAdapter(MapRegisters
, DeviceDescription
);
715 if (AdapterObject
== NULL
)
717 KeSetEvent(&HalpDmaLock
, 0, 0);
723 HalpEisaAdapter
[DeviceDescription
->DmaChannel
] = AdapterObject
;
726 if (MapRegisters
> 0)
728 AdapterObject
->NeedsMapRegisters
= TRUE
;
729 AdapterObject
->MapRegistersPerChannel
= MapRegisters
;
733 AdapterObject
->NeedsMapRegisters
= FALSE
;
734 if (DeviceDescription
->Master
)
736 AdapterObject
->MapRegistersPerChannel
= BYTES_TO_PAGES(MaximumLength
) + 1;
740 AdapterObject
->MapRegistersPerChannel
= 1;
745 if (!EisaAdapter
) InsertTailList(&HalpDmaAdapterList
, &AdapterObject
->AdapterList
);
748 * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
749 * no longer be touched, so we don't need it.
751 KeSetEvent(&HalpDmaLock
, 0, 0);
754 * Setup the values in the adapter object that are common for all
757 if (DeviceDescription
->Version
>= DEVICE_DESCRIPTION_VERSION1
)
759 AdapterObject
->IgnoreCount
= DeviceDescription
->IgnoreCount
;
763 AdapterObject
->IgnoreCount
= 0;
766 AdapterObject
->Dma32BitAddresses
= DeviceDescription
->Dma32BitAddresses
;
767 AdapterObject
->Dma64BitAddresses
= DeviceDescription
->Dma64BitAddresses
;
768 AdapterObject
->ScatterGather
= DeviceDescription
->ScatterGather
;
769 AdapterObject
->MasterDevice
= DeviceDescription
->Master
;
770 *NumberOfMapRegisters
= AdapterObject
->MapRegistersPerChannel
;
773 * For non-(E)ISA adapters we have already done all the work. On the
774 * other hand for (E)ISA adapters we must still setup the DMA modes
775 * and prepare the controller.
779 if (!HalpDmaInitializeEisaAdapter(AdapterObject
, DeviceDescription
))
781 ObDereferenceObject(AdapterObject
);
786 return AdapterObject
;
790 * @name HalpGetDmaAdapter
792 * Internal routine to allocate PnP DMA adapter object. It's exported through
793 * HalDispatchTable and used by IoGetDmaAdapter.
799 HalpGetDmaAdapter(IN PVOID Context
,
800 IN PDEVICE_DESCRIPTION DeviceDescription
,
801 OUT PULONG NumberOfMapRegisters
)
803 return &HalGetAdapter(DeviceDescription
, NumberOfMapRegisters
)->DmaHeader
;
807 * @name HalPutDmaAdapter
809 * Internal routine to free DMA adapter and resources for reuse. It's exported
810 * using the DMA_OPERATIONS interface by HalGetAdapter.
816 HalPutDmaAdapter(IN PADAPTER_OBJECT AdapterObject
)
818 if (AdapterObject
->ChannelNumber
== 0xFF)
820 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
, FALSE
, NULL
);
821 RemoveEntryList(&AdapterObject
->AdapterList
);
822 KeSetEvent(&HalpDmaLock
, 0, 0);
825 ObDereferenceObject(AdapterObject
);
829 * @name HalAllocateCommonBuffer
831 * Allocates memory that is visible to both the processor(s) and the DMA
834 * @param AdapterObject
835 * Adapter object representing the bus master or system dma controller.
837 * Number of bytes to allocate.
838 * @param LogicalAddress
839 * Logical address the driver can use to access the buffer.
840 * @param CacheEnabled
841 * Specifies if the memory can be cached.
843 * @return The base virtual address of the memory allocated or NULL on failure.
846 * On real NT x86 systems the CacheEnabled parameter is ignored, we honour
847 * it. If it proves to cause problems change it.
849 * @see HalFreeCommonBuffer
855 HalAllocateCommonBuffer(IN PADAPTER_OBJECT AdapterObject
,
857 IN PPHYSICAL_ADDRESS LogicalAddress
,
858 IN BOOLEAN CacheEnabled
)
860 PHYSICAL_ADDRESS LowestAcceptableAddress
;
861 PHYSICAL_ADDRESS HighestAcceptableAddress
;
862 PHYSICAL_ADDRESS BoundryAddressMultiple
;
863 PVOID VirtualAddress
;
865 LowestAcceptableAddress
.QuadPart
= 0;
866 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
867 BoundryAddressMultiple
.QuadPart
= 0;
870 * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
871 * slave DMA devices the 64Kb boundary mustn't be crossed since the
872 * controller wouldn't be able to handle it.
874 if (AdapterObject
->MasterDevice
)
876 BoundryAddressMultiple
.HighPart
= 1;
880 BoundryAddressMultiple
.LowPart
= 0x10000;
883 VirtualAddress
= MmAllocateContiguousMemorySpecifyCache(Length
,
884 LowestAcceptableAddress
,
885 HighestAcceptableAddress
,
886 BoundryAddressMultiple
,
887 CacheEnabled
? MmCached
:
889 if (VirtualAddress
== NULL
) return NULL
;
891 *LogicalAddress
= MmGetPhysicalAddress(VirtualAddress
);
893 return VirtualAddress
;
897 * @name HalFreeCommonBuffer
899 * Free common buffer allocated with HalAllocateCommonBuffer.
901 * @see HalAllocateCommonBuffer
907 HalFreeCommonBuffer(IN PADAPTER_OBJECT AdapterObject
,
909 IN PHYSICAL_ADDRESS LogicalAddress
,
910 IN PVOID VirtualAddress
,
911 IN BOOLEAN CacheEnabled
)
913 MmFreeContiguousMemorySpecifyCache(VirtualAddress
,
915 CacheEnabled
? MmCached
: MmNonCached
);
918 typedef struct _SCATTER_GATHER_CONTEXT
{
919 PADAPTER_OBJECT AdapterObject
;
923 PDRIVER_LIST_CONTROL AdapterListControlRoutine
;
924 PVOID AdapterListControlContext
, MapRegisterBase
;
925 ULONG MapRegisterCount
;
926 BOOLEAN WriteToDevice
;
927 WAIT_CONTEXT_BLOCK Wcb
;
928 } SCATTER_GATHER_CONTEXT
, *PSCATTER_GATHER_CONTEXT
;
933 HalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject
,
935 IN PVOID MapRegisterBase
,
938 PSCATTER_GATHER_CONTEXT AdapterControlContext
= Context
;
939 PADAPTER_OBJECT AdapterObject
= AdapterControlContext
->AdapterObject
;
940 PSCATTER_GATHER_LIST ScatterGatherList
;
941 SCATTER_GATHER_ELEMENT TempElements
[MAX_SG_ELEMENTS
];
942 ULONG ElementCount
= 0, RemainingLength
= AdapterControlContext
->Length
;
943 PUCHAR CurrentVa
= AdapterControlContext
->CurrentVa
;
945 /* Store the map register base for later in HalPutScatterGatherList */
946 AdapterControlContext
->MapRegisterBase
= MapRegisterBase
;
948 while (RemainingLength
> 0 && ElementCount
< MAX_SG_ELEMENTS
)
950 TempElements
[ElementCount
].Length
= RemainingLength
;
951 TempElements
[ElementCount
].Reserved
= 0;
952 TempElements
[ElementCount
].Address
= IoMapTransfer(AdapterObject
,
953 AdapterControlContext
->Mdl
,
955 CurrentVa
+ (AdapterControlContext
->Length
- RemainingLength
),
956 &TempElements
[ElementCount
].Length
,
957 AdapterControlContext
->WriteToDevice
);
958 if (TempElements
[ElementCount
].Length
== 0)
961 DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n",
962 TempElements
[ElementCount
].Address
.QuadPart
,
963 TempElements
[ElementCount
].Length
);
965 ASSERT(TempElements
[ElementCount
].Length
<= RemainingLength
);
966 RemainingLength
-= TempElements
[ElementCount
].Length
;
970 if (RemainingLength
> 0)
972 DPRINT1("Scatter/gather list construction failed!\n");
973 return DeallocateObject
;
976 ScatterGatherList
= ExAllocatePoolWithTag(NonPagedPool
,
977 sizeof(SCATTER_GATHER_LIST
) + sizeof(SCATTER_GATHER_ELEMENT
) * ElementCount
,
979 ASSERT(ScatterGatherList
);
981 ScatterGatherList
->NumberOfElements
= ElementCount
;
982 ScatterGatherList
->Reserved
= (ULONG_PTR
)AdapterControlContext
;
983 RtlCopyMemory(ScatterGatherList
->Elements
,
985 sizeof(SCATTER_GATHER_ELEMENT
) * ElementCount
);
987 DPRINT("Initiating S/G DMA with %d element(s)\n", ElementCount
);
989 AdapterControlContext
->AdapterListControlRoutine(DeviceObject
,
992 AdapterControlContext
->AdapterListControlContext
);
994 return DeallocateObjectKeepRegisters
;
998 * @name HalGetScatterGatherList
1000 * Creates a scatter-gather list to be using in scatter/gather DMA
1002 * @param AdapterObject
1003 * Adapter object representing the bus master or system dma controller.
1004 * @param DeviceObject
1005 * The device target for DMA.
1007 * The MDL that describes the buffer to be mapped.
1009 * The current VA in the buffer to be mapped for transfer.
1011 * Specifies the length of data in bytes to be mapped.
1012 * @param ExecutionRoutine
1013 * A caller supplied AdapterListControl routine to be called when DMA is available.
1015 * Context passed to the AdapterListControl routine.
1016 * @param WriteToDevice
1017 * Indicates direction of DMA operation.
1019 * @return The status of the operation.
1021 * @see HalPutScatterGatherList
1027 HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject
,
1028 IN PDEVICE_OBJECT DeviceObject
,
1032 IN PDRIVER_LIST_CONTROL ExecutionRoutine
,
1034 IN BOOLEAN WriteToDevice
)
1036 PSCATTER_GATHER_CONTEXT AdapterControlContext
;
1038 AdapterControlContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(SCATTER_GATHER_CONTEXT
), TAG_DMA
);
1039 if (!AdapterControlContext
) return STATUS_INSUFFICIENT_RESOURCES
;
1041 AdapterControlContext
->AdapterObject
= AdapterObject
;
1042 AdapterControlContext
->Mdl
= Mdl
;
1043 AdapterControlContext
->CurrentVa
= CurrentVa
;
1044 AdapterControlContext
->Length
= Length
;
1045 AdapterControlContext
->MapRegisterCount
= PAGE_ROUND_UP(Length
) >> PAGE_SHIFT
;
1046 AdapterControlContext
->AdapterListControlRoutine
= ExecutionRoutine
;
1047 AdapterControlContext
->AdapterListControlContext
= Context
;
1048 AdapterControlContext
->WriteToDevice
= WriteToDevice
;
1050 AdapterControlContext
->Wcb
.DeviceObject
= DeviceObject
;
1051 AdapterControlContext
->Wcb
.DeviceContext
= AdapterControlContext
;
1052 AdapterControlContext
->Wcb
.CurrentIrp
= DeviceObject
->CurrentIrp
;
1054 return HalAllocateAdapterChannel(AdapterObject
,
1055 &AdapterControlContext
->Wcb
,
1056 AdapterControlContext
->MapRegisterCount
,
1057 HalpScatterGatherAdapterControl
);
1061 * @name HalPutScatterGatherList
1063 * Frees a scatter-gather list allocated from HalGetScatterGatherList
1065 * @param AdapterObject
1066 * Adapter object representing the bus master or system dma controller.
1067 * @param ScatterGather
1068 * The scatter/gather list to be freed.
1069 * @param WriteToDevice
1070 * Indicates direction of DMA operation.
1074 * @see HalGetScatterGatherList
1080 HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject
,
1081 IN PSCATTER_GATHER_LIST ScatterGather
,
1082 IN BOOLEAN WriteToDevice
)
1084 PSCATTER_GATHER_CONTEXT AdapterControlContext
= (PSCATTER_GATHER_CONTEXT
)ScatterGather
->Reserved
;
1087 for (i
= 0; i
< ScatterGather
->NumberOfElements
; i
++)
1089 IoFlushAdapterBuffers(AdapterObject
,
1090 AdapterControlContext
->Mdl
,
1091 AdapterControlContext
->MapRegisterBase
,
1092 AdapterControlContext
->CurrentVa
,
1093 ScatterGather
->Elements
[i
].Length
,
1094 AdapterControlContext
->WriteToDevice
);
1095 AdapterControlContext
->CurrentVa
+= ScatterGather
->Elements
[i
].Length
;
1098 IoFreeMapRegisters(AdapterObject
,
1099 AdapterControlContext
->MapRegisterBase
,
1100 AdapterControlContext
->MapRegisterCount
);
1102 DPRINT("S/G DMA has finished!\n");
1104 ExFreePoolWithTag(AdapterControlContext
, TAG_DMA
);
1105 ExFreePoolWithTag(ScatterGather
, TAG_DMA
);
1110 * @name HalpDmaGetDmaAlignment
1112 * Internal routine to return the DMA alignment requirement. It's exported
1113 * using the DMA_OPERATIONS interface by HalGetAdapter.
1115 * @see HalGetAdapter
1119 HalpDmaGetDmaAlignment(IN PADAPTER_OBJECT AdapterObject
)
1125 * @name HalReadDmaCounter
1127 * Read DMA operation progress counter.
1133 HalReadDmaCounter(IN PADAPTER_OBJECT AdapterObject
)
1136 ULONG Count
, OldCount
;
1138 ASSERT(!AdapterObject
->MasterDevice
);
1141 * Acquire the master adapter lock since we're going to mess with the
1142 * system DMA controller registers and we really don't want anyone
1143 * to do the same at the same time.
1145 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
1147 /* Send the request to the specific controller. */
1148 if (AdapterObject
->AdapterNumber
== 1)
1150 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1158 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
1161 Count
= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
1162 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
1163 Count
|= READ_PORT_UCHAR(&DmaControl1
->DmaAddressCount
1164 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
1165 } while (0xffff00 & (OldCount
^ Count
));
1169 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1177 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
1180 Count
= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
1181 [AdapterObject
->ChannelNumber
].DmaBaseCount
);
1182 Count
|= READ_PORT_UCHAR(&DmaControl2
->DmaAddressCount
1183 [AdapterObject
->ChannelNumber
].DmaBaseCount
) << 8;
1184 } while (0xffff00 & (OldCount
^ Count
));
1187 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
1191 if (AdapterObject
->Width16Bits
) Count
*= 2;
1198 * @name HalpGrowMapBufferWorker
1200 * Helper routine of HalAllocateAdapterChannel for allocating map registers
1201 * at PASSIVE_LEVEL in work item.
1205 HalpGrowMapBufferWorker(IN PVOID DeferredContext
)
1207 PGROW_WORK_ITEM WorkItem
= (PGROW_WORK_ITEM
)DeferredContext
;
1212 * Try to allocate new map registers for the adapter.
1214 * NOTE: The NT implementation actually tries to allocate more map
1215 * registers than needed as an optimization.
1217 KeWaitForSingleObject(&HalpDmaLock
, Executive
, KernelMode
, FALSE
, NULL
);
1218 Succeeded
= HalpGrowMapBuffers(WorkItem
->AdapterObject
->MasterAdapter
,
1219 WorkItem
->NumberOfMapRegisters
<< PAGE_SHIFT
);
1220 KeSetEvent(&HalpDmaLock
, 0, 0);
1225 * Flush the adapter queue now that new map registers are ready. The
1226 * easiest way to do that is to call IoFreeMapRegisters to not free
1227 * any registers. Note that we use the magic (PVOID)2 map register
1228 * base to bypass the parameter checking.
1230 OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1231 IoFreeMapRegisters(WorkItem
->AdapterObject
, (PVOID
)2, 0);
1232 KfLowerIrql(OldIrql
);
1235 ExFreePool(WorkItem
);
1239 * @name HalAllocateAdapterChannel
1241 * Setup map registers for an adapter object.
1243 * @param AdapterObject
1244 * Pointer to an ADAPTER_OBJECT to set up.
1245 * @param WaitContextBlock
1246 * Context block to be used with ExecutionRoutine.
1247 * @param NumberOfMapRegisters
1248 * Number of map registers requested.
1249 * @param ExecutionRoutine
1250 * Callback to call when map registers are allocated.
1253 * If not enough map registers can be allocated then
1254 * STATUS_INSUFFICIENT_RESOURCES is returned. If the function
1255 * succeeds or the callback is queued for later delivering then
1256 * STATUS_SUCCESS is returned.
1258 * @see IoFreeAdapterChannel
1264 HalAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject
,
1265 IN PWAIT_CONTEXT_BLOCK WaitContextBlock
,
1266 IN ULONG NumberOfMapRegisters
,
1267 IN PDRIVER_CONTROL ExecutionRoutine
)
1269 PADAPTER_OBJECT MasterAdapter
;
1270 PGROW_WORK_ITEM WorkItem
;
1271 ULONG Index
= MAXULONG
;
1275 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1277 /* Set up the wait context block in case we can't run right away. */
1278 WaitContextBlock
->DeviceRoutine
= ExecutionRoutine
;
1279 WaitContextBlock
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1281 /* Returns true if queued, else returns false and sets the queue to busy */
1282 if (KeInsertDeviceQueue(&AdapterObject
->ChannelWaitQueue
,
1283 &WaitContextBlock
->WaitQueueEntry
))
1285 return STATUS_SUCCESS
;
1288 MasterAdapter
= AdapterObject
->MasterAdapter
;
1290 AdapterObject
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1291 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1293 if ((NumberOfMapRegisters
) && (AdapterObject
->NeedsMapRegisters
))
1295 if (NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)
1297 AdapterObject
->NumberOfMapRegisters
= 0;
1298 IoFreeAdapterChannel(AdapterObject
);
1299 return STATUS_INSUFFICIENT_RESOURCES
;
1303 * Get the map registers. This is partly complicated by the fact
1304 * that new map registers can only be allocated at PASSIVE_LEVEL
1305 * and we're currently at DISPATCH_LEVEL. The following code has
1308 * - If there is no adapter queued for map register allocation,
1309 * try to see if enough contiguous map registers are present.
1310 * In case they're we can just get them and proceed further.
1312 * - If some adapter is already present in the queue we must
1313 * respect the order of adapters asking for map registers and
1314 * so the fast case described above can't take place.
1315 * This case is also entered if not enough coniguous map
1316 * registers are present.
1318 * A work queue item is allocated and queued, the adapter is
1319 * also queued into the master adapter queue. The worker
1320 * routine does the job of allocating the map registers at
1321 * PASSIVE_LEVEL and calling the ExecutionRoutine.
1324 KeAcquireSpinLock(&MasterAdapter
->SpinLock
, &OldIrql
);
1326 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1328 Index
= RtlFindClearBitsAndSet(MasterAdapter
->MapRegisters
, NumberOfMapRegisters
, 0);
1329 if (Index
!= MAXULONG
)
1331 AdapterObject
->MapRegisterBase
= MasterAdapter
->MapRegisterBase
+ Index
;
1332 if (!AdapterObject
->ScatterGather
)
1334 AdapterObject
->MapRegisterBase
= (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)AdapterObject
->MapRegisterBase
| MAP_BASE_SW_SG
);
1339 if (Index
== MAXULONG
)
1341 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1343 WorkItem
= ExAllocatePoolWithTag(NonPagedPool
,
1344 sizeof(GROW_WORK_ITEM
),
1348 ExInitializeWorkItem(&WorkItem
->WorkQueueItem
, HalpGrowMapBufferWorker
, WorkItem
);
1349 WorkItem
->AdapterObject
= AdapterObject
;
1350 WorkItem
->NumberOfMapRegisters
= NumberOfMapRegisters
;
1352 ExQueueWorkItem(&WorkItem
->WorkQueueItem
, DelayedWorkQueue
);
1355 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1357 return STATUS_SUCCESS
;
1360 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1364 AdapterObject
->MapRegisterBase
= NULL
;
1365 AdapterObject
->NumberOfMapRegisters
= 0;
1368 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1370 Result
= ExecutionRoutine(WaitContextBlock
->DeviceObject
,
1371 WaitContextBlock
->CurrentIrp
,
1372 AdapterObject
->MapRegisterBase
,
1373 WaitContextBlock
->DeviceContext
);
1376 * Possible return values:
1379 * Don't free any resources, the ADAPTER_OBJECT is still in use and
1380 * the caller will call IoFreeAdapterChannel later.
1382 * - DeallocateObject
1383 * Deallocate the map registers and release the ADAPTER_OBJECT, so
1384 * someone else can use it.
1386 * - DeallocateObjectKeepRegisters
1387 * Release the ADAPTER_OBJECT, but hang on to the map registers. The
1388 * client will later call IoFreeMapRegisters.
1391 * IoFreeAdapterChannel runs the queue, so it must be called unless
1392 * the adapter object is not to be freed.
1394 if (Result
== DeallocateObject
)
1396 IoFreeAdapterChannel(AdapterObject
);
1398 else if (Result
== DeallocateObjectKeepRegisters
)
1400 AdapterObject
->NumberOfMapRegisters
= 0;
1401 IoFreeAdapterChannel(AdapterObject
);
1404 return STATUS_SUCCESS
;
1408 * @name IoFreeAdapterChannel
1410 * Free DMA resources allocated by IoAllocateAdapterChannel.
1412 * @param AdapterObject
1413 * Adapter object with resources to free.
1416 * This function releases map registers registers assigned to the DMA
1417 * adapter. After releasing the adapter, it checks the adapter's queue
1418 * and runs each queued device object in series until the queue is
1419 * empty. This is the only way the device queue is emptied.
1421 * @see IoAllocateAdapterChannel
1427 IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject
)
1429 PADAPTER_OBJECT MasterAdapter
;
1430 PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
;
1431 PWAIT_CONTEXT_BLOCK WaitContextBlock
;
1432 ULONG Index
= MAXULONG
;
1436 MasterAdapter
= AdapterObject
->MasterAdapter
;
1441 * To keep map registers, call here with AdapterObject->
1442 * NumberOfMapRegisters set to zero. This trick is used in
1443 * HalAllocateAdapterChannel for example.
1445 if (AdapterObject
->NumberOfMapRegisters
)
1447 IoFreeMapRegisters(AdapterObject
,
1448 AdapterObject
->MapRegisterBase
,
1449 AdapterObject
->NumberOfMapRegisters
);
1452 DeviceQueueEntry
= KeRemoveDeviceQueue(&AdapterObject
->ChannelWaitQueue
);
1453 if (!DeviceQueueEntry
) break;
1455 WaitContextBlock
= CONTAINING_RECORD(DeviceQueueEntry
,
1459 AdapterObject
->CurrentWcb
= WaitContextBlock
;
1460 AdapterObject
->NumberOfMapRegisters
= WaitContextBlock
->NumberOfMapRegisters
;
1462 if ((WaitContextBlock
->NumberOfMapRegisters
) && (AdapterObject
->MasterAdapter
))
1464 KeAcquireSpinLock(&MasterAdapter
->SpinLock
, &OldIrql
);
1466 if (IsListEmpty(&MasterAdapter
->AdapterQueue
))
1468 Index
= RtlFindClearBitsAndSet(MasterAdapter
->MapRegisters
,
1469 WaitContextBlock
->NumberOfMapRegisters
,
1471 if (Index
!= MAXULONG
)
1473 AdapterObject
->MapRegisterBase
= MasterAdapter
->MapRegisterBase
+ Index
;
1474 if (!AdapterObject
->ScatterGather
)
1476 AdapterObject
->MapRegisterBase
=(PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)AdapterObject
->MapRegisterBase
| MAP_BASE_SW_SG
);
1481 if (Index
== MAXULONG
)
1483 InsertTailList(&MasterAdapter
->AdapterQueue
, &AdapterObject
->AdapterQueue
);
1484 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1488 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1492 AdapterObject
->MapRegisterBase
= NULL
;
1493 AdapterObject
->NumberOfMapRegisters
= 0;
1496 /* Call the adapter control routine. */
1497 Result
= ((PDRIVER_CONTROL
)WaitContextBlock
->DeviceRoutine
)(WaitContextBlock
->DeviceObject
,
1498 WaitContextBlock
->CurrentIrp
,
1499 AdapterObject
->MapRegisterBase
,
1500 WaitContextBlock
->DeviceContext
);
1505 * We're done until the caller manually calls IoFreeAdapterChannel
1506 * or IoFreeMapRegisters.
1510 case DeallocateObjectKeepRegisters
:
1512 * Hide the map registers so they aren't deallocated next time
1515 AdapterObject
->NumberOfMapRegisters
= 0;
1525 * @name IoFreeMapRegisters
1527 * Free map registers reserved by the system for a DMA.
1529 * @param AdapterObject
1530 * DMA adapter to free map registers on.
1531 * @param MapRegisterBase
1532 * Handle to map registers to free.
1533 * @param NumberOfRegisters
1534 * Number of map registers to be freed.
1540 IoFreeMapRegisters(IN PADAPTER_OBJECT AdapterObject
,
1541 IN PVOID MapRegisterBase
,
1542 IN ULONG NumberOfMapRegisters
)
1544 PADAPTER_OBJECT MasterAdapter
= AdapterObject
->MasterAdapter
;
1545 PLIST_ENTRY ListEntry
;
1550 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1552 if (!(MasterAdapter
) || !(MapRegisterBase
)) return;
1554 KeAcquireSpinLock(&MasterAdapter
->SpinLock
, &OldIrql
);
1556 if (NumberOfMapRegisters
!= 0)
1558 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1560 RealMapRegisterBase
= (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1561 RtlClearBits(MasterAdapter
->MapRegisters
,
1562 (ULONG
)(RealMapRegisterBase
- MasterAdapter
->MapRegisterBase
),
1563 NumberOfMapRegisters
);
1567 * Now that we freed few map registers it's time to look at the master
1568 * adapter queue and see if there is someone waiting for map registers.
1570 while (!IsListEmpty(&MasterAdapter
->AdapterQueue
))
1572 ListEntry
= RemoveHeadList(&MasterAdapter
->AdapterQueue
);
1573 AdapterObject
= CONTAINING_RECORD(ListEntry
, struct _ADAPTER_OBJECT
, AdapterQueue
);
1575 Index
= RtlFindClearBitsAndSet(MasterAdapter
->MapRegisters
,
1576 AdapterObject
->NumberOfMapRegisters
,
1578 if (Index
== MAXULONG
)
1580 InsertHeadList(&MasterAdapter
->AdapterQueue
, ListEntry
);
1584 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1586 AdapterObject
->MapRegisterBase
= MasterAdapter
->MapRegisterBase
+ Index
;
1587 if (!AdapterObject
->ScatterGather
)
1589 AdapterObject
->MapRegisterBase
=
1590 (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)AdapterObject
->MapRegisterBase
| MAP_BASE_SW_SG
);
1593 Result
= ((PDRIVER_CONTROL
)AdapterObject
->CurrentWcb
->DeviceRoutine
)(AdapterObject
->CurrentWcb
->DeviceObject
,
1594 AdapterObject
->CurrentWcb
->CurrentIrp
,
1595 AdapterObject
->MapRegisterBase
,
1596 AdapterObject
->CurrentWcb
->DeviceContext
);
1599 case DeallocateObjectKeepRegisters
:
1600 AdapterObject
->NumberOfMapRegisters
= 0;
1603 case DeallocateObject
:
1604 if (AdapterObject
->NumberOfMapRegisters
)
1606 KeAcquireSpinLock(&MasterAdapter
->SpinLock
, &OldIrql
);
1607 RtlClearBits(MasterAdapter
->MapRegisters
,
1608 (ULONG
)(AdapterObject
->MapRegisterBase
-
1609 MasterAdapter
->MapRegisterBase
),
1610 AdapterObject
->NumberOfMapRegisters
);
1611 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1614 IoFreeAdapterChannel(AdapterObject
);
1621 KeAcquireSpinLock(&MasterAdapter
->SpinLock
, &OldIrql
);
1624 KeReleaseSpinLock(&MasterAdapter
->SpinLock
, OldIrql
);
1628 * @name HalpCopyBufferMap
1630 * Helper function for copying data from/to map register buffers.
1632 * @see IoFlushAdapterBuffers, IoMapTransfer
1636 HalpCopyBufferMap(IN PMDL Mdl
,
1637 IN PROS_MAP_REGISTER_ENTRY MapRegisterBase
,
1640 IN BOOLEAN WriteToDevice
)
1642 ULONG CurrentLength
;
1643 ULONG_PTR CurrentAddress
;
1645 PVOID VirtualAddress
;
1647 VirtualAddress
= MmGetSystemAddressForMdlSafe(Mdl
, HighPagePriority
);
1648 if (!VirtualAddress
)
1651 * NOTE: On real NT a mechanism with reserved pages is implemented
1652 * to handle this case in a slow, but graceful non-fatal way.
1654 KeBugCheckEx(HAL_MEMORY_ALLOCATION
, PAGE_SIZE
, 0, (ULONG_PTR
)__FILE__
, 0);
1657 CurrentAddress
= (ULONG_PTR
)VirtualAddress
+
1658 (ULONG_PTR
)CurrentVa
-
1659 (ULONG_PTR
)MmGetMdlVirtualAddress(Mdl
);
1663 ByteOffset
= BYTE_OFFSET(CurrentAddress
);
1664 CurrentLength
= PAGE_SIZE
- ByteOffset
;
1665 if (CurrentLength
> Length
) CurrentLength
= Length
;
1669 RtlCopyMemory((PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1670 (PVOID
)CurrentAddress
,
1675 RtlCopyMemory((PVOID
)CurrentAddress
,
1676 (PVOID
)((ULONG_PTR
)MapRegisterBase
->VirtualAddress
+ ByteOffset
),
1680 Length
-= CurrentLength
;
1681 CurrentAddress
+= CurrentLength
;
1687 * @name IoFlushAdapterBuffers
1689 * Flush any data remaining in the DMA controller's memory into the host
1692 * @param AdapterObject
1693 * The adapter object to flush.
1695 * Original MDL to flush data into.
1696 * @param MapRegisterBase
1697 * Map register base that was just used by IoMapTransfer, etc.
1699 * Offset into Mdl to be flushed into, same as was passed to
1702 * Length of the buffer to be flushed into.
1703 * @param WriteToDevice
1704 * TRUE if it's a write, FALSE if it's a read.
1706 * @return TRUE in all cases.
1709 * This copies data from the map register-backed buffer to the user's
1710 * target buffer. Data are not in the user buffer until this function
1712 * For slave DMA transfers the controller channel is masked effectively
1713 * stopping the current transfer.
1719 IoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject
,
1721 IN PVOID MapRegisterBase
,
1724 IN BOOLEAN WriteToDevice
)
1726 BOOLEAN SlaveDma
= FALSE
;
1727 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1728 PHYSICAL_ADDRESS HighestAcceptableAddress
;
1729 PHYSICAL_ADDRESS PhysicalAddress
;
1730 PPFN_NUMBER MdlPagesPtr
;
1733 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1734 ASSERT(AdapterObject
);
1736 if (!AdapterObject
->MasterDevice
)
1738 /* Mask out (disable) the DMA channel. */
1739 if (AdapterObject
->AdapterNumber
== 1)
1741 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
1742 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
,
1743 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1747 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
1748 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
,
1749 AdapterObject
->ChannelNumber
| DMA_SETMASK
);
1754 /* This can happen if the device supports hardware scatter/gather. */
1755 if (MapRegisterBase
== NULL
) return TRUE
;
1757 RealMapRegisterBase
= (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1761 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1763 if (RealMapRegisterBase
->Counter
!= MAXULONG
)
1765 if ((SlaveDma
) && !(AdapterObject
->IgnoreCount
))
1767 Length
-= HalReadDmaCounter(AdapterObject
);
1770 HalpCopyBufferMap(Mdl
,
1771 RealMapRegisterBase
,
1778 MdlPagesPtr
= MmGetMdlPfnArray(Mdl
);
1779 MdlPagesPtr
+= ((ULONG_PTR
)CurrentVa
- (ULONG_PTR
)Mdl
->StartVa
) >> PAGE_SHIFT
;
1781 PhysicalAddress
.QuadPart
= *MdlPagesPtr
<< PAGE_SHIFT
;
1782 PhysicalAddress
.QuadPart
+= BYTE_OFFSET(CurrentVa
);
1784 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
1785 if ((PhysicalAddress
.QuadPart
+ Length
) > HighestAcceptableAddress
.QuadPart
)
1787 HalpCopyBufferMap(Mdl
,
1788 RealMapRegisterBase
,
1796 RealMapRegisterBase
->Counter
= 0;
1802 * @name IoMapTransfer
1804 * Map a DMA for transfer and do the DMA if it's a slave.
1806 * @param AdapterObject
1807 * Adapter object to do the DMA on. Bus-master may pass NULL.
1809 * Locked-down user buffer to DMA in to or out of.
1810 * @param MapRegisterBase
1811 * Handle to map registers to use for this dma.
1813 * Index into Mdl to transfer into/out of.
1815 * Length of transfer. Number of bytes actually transferred on
1817 * @param WriteToDevice
1818 * TRUE if it's an output DMA, FALSE otherwise.
1821 * A logical address that can be used to program a DMA controller, it's
1822 * not meaningful for slave DMA device.
1825 * This function does a copyover to contiguous memory <16MB represented
1826 * by the map registers if needed. If the buffer described by MDL can be
1827 * used as is no copyover is done.
1828 * If it's a slave transfer, this function actually performs it.
1834 IoMapTransfer(IN PADAPTER_OBJECT AdapterObject
,
1836 IN PVOID MapRegisterBase
,
1838 IN OUT PULONG Length
,
1839 IN BOOLEAN WriteToDevice
)
1841 PPFN_NUMBER MdlPagesPtr
;
1842 PFN_NUMBER MdlPage1
, MdlPage2
;
1844 ULONG TransferOffset
;
1845 ULONG TransferLength
;
1846 BOOLEAN UseMapRegisters
;
1847 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase
;
1848 PHYSICAL_ADDRESS PhysicalAddress
;
1849 PHYSICAL_ADDRESS HighestAcceptableAddress
;
1851 DMA_MODE AdapterMode
;
1855 * Precalculate some values that are used in all cases.
1857 * ByteOffset is offset inside the page at which the transfer starts.
1858 * MdlPagesPtr is pointer inside the MDL page chain at the page where the
1860 * PhysicalAddress is physical address corresponding to the transfer
1861 * start page and offset.
1862 * TransferLength is the initial length of the transfer, which is reminder
1863 * of the first page. The actual value is calculated below.
1865 * Note that all the variables can change during the processing which
1866 * takes place below. These are just initial values.
1868 ByteOffset
= BYTE_OFFSET(CurrentVa
);
1870 MdlPagesPtr
= MmGetMdlPfnArray(Mdl
);
1871 MdlPagesPtr
+= ((ULONG_PTR
)CurrentVa
- (ULONG_PTR
)Mdl
->StartVa
) >> PAGE_SHIFT
;
1873 PhysicalAddress
.QuadPart
= *MdlPagesPtr
<< PAGE_SHIFT
;
1874 PhysicalAddress
.QuadPart
+= ByteOffset
;
1876 TransferLength
= PAGE_SIZE
- ByteOffset
;
1879 * Special case for bus master adapters with S/G support. We can directly
1880 * use the buffer specified by the MDL, so not much work has to be done.
1882 * Just return the passed VA's corresponding physical address and update
1883 * length to the number of physically contiguous bytes found. Also
1884 * pages crossing the 4Gb boundary aren't considered physically contiguous.
1886 if (MapRegisterBase
== NULL
)
1888 while (TransferLength
< *Length
)
1890 MdlPage1
= *MdlPagesPtr
;
1891 MdlPage2
= *(MdlPagesPtr
+ 1);
1892 if (MdlPage1
+ 1 != MdlPage2
) break;
1893 if ((MdlPage1
^ MdlPage2
) & ~0xFFFFF) break;
1894 TransferLength
+= PAGE_SIZE
;
1898 if (TransferLength
< *Length
) *Length
= TransferLength
;
1900 return PhysicalAddress
;
1904 * The code below applies to slave DMA adapters and bus master adapters
1905 * without hardward S/G support.
1907 RealMapRegisterBase
= (PROS_MAP_REGISTER_ENTRY
)((ULONG_PTR
)MapRegisterBase
& ~MAP_BASE_SW_SG
);
1910 * Try to calculate the size of the transfer. We can only transfer
1911 * pages that are physically contiguous and that don't cross the
1912 * 64Kb boundary (this limitation applies only for ISA controllers).
1914 while (TransferLength
< *Length
)
1916 MdlPage1
= *MdlPagesPtr
;
1917 MdlPage2
= *(MdlPagesPtr
+ 1);
1918 if (MdlPage1
+ 1 != MdlPage2
) break;
1919 if (!HalpEisaDma
&& ((MdlPage1
^ MdlPage2
) & ~0xF)) break;
1920 TransferLength
+= PAGE_SIZE
;
1924 if (TransferLength
> *Length
) TransferLength
= *Length
;
1927 * If we're about to simulate software S/G and not all the pages are
1928 * physically contiguous then we must use the map registers to store
1929 * the data and allow the whole transfer to proceed at once.
1931 if (((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
) && (TransferLength
< *Length
))
1933 UseMapRegisters
= TRUE
;
1934 PhysicalAddress
= RealMapRegisterBase
->PhysicalAddress
;
1935 PhysicalAddress
.QuadPart
+= ByteOffset
;
1936 TransferLength
= *Length
;
1937 RealMapRegisterBase
->Counter
= MAXULONG
;
1943 * This is ordinary DMA transfer, so just update the progress
1944 * counters. These are used by IoFlushAdapterBuffers to track
1945 * the transfer progress.
1947 UseMapRegisters
= FALSE
;
1948 Counter
= RealMapRegisterBase
->Counter
;
1949 RealMapRegisterBase
->Counter
+= BYTES_TO_PAGES(ByteOffset
+ TransferLength
);
1952 * Check if the buffer doesn't exceed the highest physical address
1953 * limit of the device. In that case we must use the map registers to
1956 HighestAcceptableAddress
= HalpGetAdapterMaximumPhysicalAddress(AdapterObject
);
1957 if ((PhysicalAddress
.QuadPart
+ TransferLength
) > HighestAcceptableAddress
.QuadPart
)
1959 UseMapRegisters
= TRUE
;
1960 PhysicalAddress
= RealMapRegisterBase
[Counter
].PhysicalAddress
;
1961 PhysicalAddress
.QuadPart
+= ByteOffset
;
1962 if ((ULONG_PTR
)MapRegisterBase
& MAP_BASE_SW_SG
)
1964 RealMapRegisterBase
->Counter
= MAXULONG
;
1971 * If we decided to use the map registers (see above) and we're about
1972 * to transfer data to the device then copy the buffers into the map
1975 if ((UseMapRegisters
) && (WriteToDevice
))
1977 HalpCopyBufferMap(Mdl
,
1978 RealMapRegisterBase
+ Counter
,
1985 * Return the length of transfer that actually takes place.
1987 *Length
= TransferLength
;
1990 * If we're doing slave (system) DMA then program the (E)ISA controller
1991 * to actually start the transfer.
1993 if ((AdapterObject
) && !(AdapterObject
->MasterDevice
))
1995 AdapterMode
= AdapterObject
->AdapterMode
;
1999 AdapterMode
.TransferType
= WRITE_TRANSFER
;
2003 AdapterMode
.TransferType
= READ_TRANSFER
;
2004 if (AdapterObject
->IgnoreCount
)
2006 RtlZeroMemory((PUCHAR
)RealMapRegisterBase
[Counter
].VirtualAddress
+ ByteOffset
,
2011 TransferOffset
= PhysicalAddress
.LowPart
& 0xFFFF;
2012 if (AdapterObject
->Width16Bits
)
2014 TransferLength
>>= 1;
2015 TransferOffset
>>= 1;
2018 KeAcquireSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, &OldIrql
);
2020 if (AdapterObject
->AdapterNumber
== 1)
2022 PDMA1_CONTROL DmaControl1
= AdapterObject
->AdapterBaseVa
;
2024 /* Reset Register */
2025 WRITE_PORT_UCHAR(&DmaControl1
->ClearBytePointer
, 0);
2028 WRITE_PORT_UCHAR(&DmaControl1
->Mode
, AdapterMode
.Byte
);
2030 /* Set the Offset Register */
2031 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
2032 (UCHAR
)(TransferOffset
));
2033 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
2034 (UCHAR
)(TransferOffset
>> 8));
2036 /* Set the Page Register */
2037 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+ FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
),
2038 (UCHAR
)(PhysicalAddress
.LowPart
>> 16));
2041 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+ FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
2045 /* Set the Length */
2046 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
2047 (UCHAR
)(TransferLength
- 1));
2048 WRITE_PORT_UCHAR(&DmaControl1
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
2049 (UCHAR
)((TransferLength
- 1) >> 8));
2051 /* Unmask the Channel */
2052 WRITE_PORT_UCHAR(&DmaControl1
->SingleMask
, AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
2056 PDMA2_CONTROL DmaControl2
= AdapterObject
->AdapterBaseVa
;
2058 /* Reset Register */
2059 WRITE_PORT_UCHAR(&DmaControl2
->ClearBytePointer
, 0);
2062 WRITE_PORT_UCHAR(&DmaControl2
->Mode
, AdapterMode
.Byte
);
2064 /* Set the Offset Register */
2065 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
2066 (UCHAR
)(TransferOffset
));
2067 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseAddress
,
2068 (UCHAR
)(TransferOffset
>> 8));
2070 /* Set the Page Register */
2071 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+ FIELD_OFFSET(EISA_CONTROL
, DmaController1Pages
),
2072 (UCHAR
)(PhysicalAddress
.u
.LowPart
>> 16));
2075 WRITE_PORT_UCHAR(AdapterObject
->PagePort
+ FIELD_OFFSET(EISA_CONTROL
, DmaController2Pages
),
2079 /* Set the Length */
2080 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
2081 (UCHAR
)(TransferLength
- 1));
2082 WRITE_PORT_UCHAR(&DmaControl2
->DmaAddressCount
[AdapterObject
->ChannelNumber
].DmaBaseCount
,
2083 (UCHAR
)((TransferLength
- 1) >> 8));
2085 /* Unmask the Channel */
2086 WRITE_PORT_UCHAR(&DmaControl2
->SingleMask
,
2087 AdapterObject
->ChannelNumber
| DMA_CLEARMASK
);
2090 KeReleaseSpinLock(&AdapterObject
->MasterAdapter
->SpinLock
, OldIrql
);
2094 * Return physical address of the buffer with data that is used for the
2095 * transfer. It can either point inside the Mdl that was passed by the
2096 * caller or into the map registers if the Mdl buffer can't be used
2099 return PhysicalAddress
;
2104 * @name HalFlushCommonBuffer
2110 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject
,
2112 IN PHYSICAL_ADDRESS LogicalAddress
,
2113 IN PVOID VirtualAddress
)
2115 /* Function always returns true */
2124 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject
,
2125 IN OUT PULONG NumberOfMapRegisters
)
2127 PADAPTER_OBJECT MasterAdapter
= AdapterObject
->MasterAdapter
;
2128 ULONG MapRegisterNumber
;
2130 /* Check if it needs map registers */
2131 if (AdapterObject
->NeedsMapRegisters
)
2133 /* Check if we have enough */
2134 if (*NumberOfMapRegisters
> AdapterObject
->MapRegistersPerChannel
)
2136 /* We don't, fail */
2137 AdapterObject
->NumberOfMapRegisters
= 0;
2141 /* Try to find free map registers */
2142 MapRegisterNumber
= RtlFindClearBitsAndSet(MasterAdapter
->MapRegisters
,
2143 *NumberOfMapRegisters
,
2146 /* Check if nothing was found */
2147 if (MapRegisterNumber
== MAXULONG
)
2149 /* No free registers found, so use the base registers */
2150 RtlSetBits(MasterAdapter
->MapRegisters
,
2152 *NumberOfMapRegisters
);
2153 MapRegisterNumber
= 0;
2156 /* Calculate the new base */
2157 AdapterObject
->MapRegisterBase
=
2158 (PROS_MAP_REGISTER_ENTRY
)(MasterAdapter
->MapRegisterBase
+
2161 /* Check if scatter gather isn't supported */
2162 if (!AdapterObject
->ScatterGather
)
2165 AdapterObject
->MapRegisterBase
=
2166 (PROS_MAP_REGISTER_ENTRY
)
2167 ((ULONG_PTR
)AdapterObject
->MapRegisterBase
| MAP_BASE_SW_SG
);
2172 AdapterObject
->MapRegisterBase
= NULL
;
2173 AdapterObject
->NumberOfMapRegisters
= 0;
2176 /* Return the base */
2177 return AdapterObject
->MapRegisterBase
;