Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378/* * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: hal/halx86/generic/dma.c * PURPOSE: DMA functions * PROGRAMMERS: David Welch (welch@mcmail.com) * Filip Navara (navaraf@reactos.com) * UPDATE HISTORY: * Created 22/05/98 */
/** * @page DMA Implementation Notes * * Concepts: * * - Map register * * Abstract encapsulation of physically contiguous buffer that resides * in memory accessible by both the DMA device / controller and the system. * The map registers are allocated and distributed on demand and are * scarce resource. * * The actual use of map registers is to allow transfers from/to buffer * located in physical memory at address inaccessible by the DMA device / * controller directly. For such transfers the map register buffers * are used as intermediate data storage. * * - Master adapter * * A container for map registers (typically corresponding to one physical * bus connection type). There can be master adapters for 24-bit address * ranges, 32-bit address ranges, etc. Every time a new DMA adapter is * created it's associated with a corresponding master adapter that * is used for any map register allocation requests. * * - Bus-master / Slave DMA * * Slave DMA is term used for DMA transfers done by the system (E)ISA * controller as opposed to transfers mastered by the device itself * (hence the name). * * For slave DMA special care is taken to actually access the system * controller and handle the transfers. The relevant code is in * HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers * and IoMapTransfer. * * Implementation: * * - Allocation of map registers * * Initial set of map registers is allocated on the system start to * ensure that low memory won't get filled up later. Additional map * registers are allocated as needed by HalpGrowMapBuffers. This * routine is called on two places: * * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that * more map registers will probably be needed. * - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly) * when no more map registers are free. * * Note that even if no more map registers can be allocated it's not * the end of the world. The adapters waiting for free map registers * are queued in the master adapter's queue and once one driver hands * back it's map registers (using IoFreeMapRegisters or indirectly using * the execution routine callback in IoAllocateAdapterChannel) the * queue gets processed and the map registers are reassigned. */
/* INCLUDES *****************************************************************/
#include <hal.h>#include <suppress.h>
#define NDEBUG#include <debug.h>
#define MAX_SG_ELEMENTS 0x10
#ifndef _MINIHAL_static KEVENT HalpDmaLock;static KSPIN_LOCK HalpDmaAdapterListLock;static LIST_ENTRY HalpDmaAdapterList;static PADAPTER_OBJECT HalpEisaAdapter[8];#endifstatic BOOLEAN HalpEisaDma;#ifndef _MINIHAL_static PADAPTER_OBJECT HalpMasterAdapter;#endif
static const ULONG_PTR HalpEisaPortPage[8] = { FIELD_OFFSET(DMA_PAGE, Channel0), FIELD_OFFSET(DMA_PAGE, Channel1), FIELD_OFFSET(DMA_PAGE, Channel2), FIELD_OFFSET(DMA_PAGE, Channel3), 0, FIELD_OFFSET(DMA_PAGE, Channel5), FIELD_OFFSET(DMA_PAGE, Channel6), FIELD_OFFSET(DMA_PAGE, Channel7)};
#ifndef _MINIHAL_NTSTATUSNTAPIHalCalculateScatterGatherListSize( IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl OPTIONAL, IN PVOID CurrentVa, IN ULONG Length, OUT PULONG ScatterGatherListSize, OUT PULONG pNumberOfMapRegisters);
NTSTATUSNTAPIHalBuildScatterGatherList( IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_OBJECT DeviceObject, IN PMDL Mdl, IN PVOID CurrentVa, IN ULONG Length, IN PDRIVER_LIST_CONTROL ExecutionRoutine, IN PVOID Context, IN BOOLEAN WriteToDevice, IN PVOID ScatterGatherBuffer, IN ULONG ScatterGatherLength);
NTSTATUSNTAPIHalBuildMdlFromScatterGatherList( IN PDMA_ADAPTER DmaAdapter, IN PSCATTER_GATHER_LIST ScatterGather, IN PMDL OriginalMdl, OUT PMDL *TargetMdl);
static DMA_OPERATIONS HalpDmaOperations = { sizeof(DMA_OPERATIONS), (PPUT_DMA_ADAPTER)HalPutDmaAdapter, (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer, (PFREE_COMMON_BUFFER)HalFreeCommonBuffer, NULL, /* Initialized in HalpInitDma() */ NULL, /* Initialized in HalpInitDma() */ NULL, /* Initialized in HalpInitDma() */ NULL, /* Initialized in HalpInitDma() */ NULL, /* Initialized in HalpInitDma() */ (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment, (PREAD_DMA_COUNTER)HalReadDmaCounter, (PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList, (PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList, (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize, (PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList, (PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList};#endif
#define MAX_MAP_REGISTERS 64
#define TAG_DMA ' AMD'
/* FUNCTIONS *****************************************************************/
#if defined(SARCH_PC98)/* * Disable I/O for safety. * FIXME: Add support for PC-98 DMA controllers. */#undef WRITE_PORT_UCHAR#undef READ_PORT_UCHAR
#define WRITE_PORT_UCHAR(Port, Data) \ do { \ UNIMPLEMENTED; \ (Port); \ (Data); \ } while (0)
#define READ_PORT_UCHAR(Port) 0x00#endif
#ifndef _MINIHAL_CODE_SEG("INIT")VOIDHalpInitDma(VOID){ /* * Initialize the DMA Operation table */ HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel; HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers; HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel; HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters; HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer;
if (HalpBusType == MACHINE_TYPE_EISA) { /* * Check if Extended DMA is available. We're just going to do a random * read and write. */ WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)), 0x2A); if (READ_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2))) == 0x2A) { DPRINT1("Machine supports EISA DMA. Bus type: %lu\n", HalpBusType); HalpEisaDma = TRUE; } }
/* * Intialize all the global variables and allocate master adapter with * first map buffers. */ InitializeListHead(&HalpDmaAdapterList); KeInitializeSpinLock(&HalpDmaAdapterListLock); KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE); HalpMasterAdapter = HalpDmaAllocateMasterAdapter();
/* * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's * used by IoGetDmaAdapter in the kernel. */ HalGetDmaAdapter = HalpGetDmaAdapter;}#endif
/** * @name HalpGetAdapterMaximumPhysicalAddress * * Get the maximum physical address acceptable by the device represented * by the passed DMA adapter. */PHYSICAL_ADDRESSNTAPIHalpGetAdapterMaximumPhysicalAddress(IN PADAPTER_OBJECT AdapterObject){ PHYSICAL_ADDRESS HighestAddress;
if (AdapterObject->MasterDevice) { if (AdapterObject->Dma64BitAddresses) { HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL; return HighestAddress; } else if (AdapterObject->Dma32BitAddresses) { HighestAddress.QuadPart = 0xFFFFFFFF; return HighestAddress; } }
HighestAddress.QuadPart = 0xFFFFFF; return HighestAddress;}
#ifndef _MINIHAL_/** * @name HalpGrowMapBuffers * * Allocate initial, or additional, map buffers for DMA master adapter. * * @param MasterAdapter * DMA master adapter to allocate buffers for. * @param SizeOfMapBuffers * Size of the map buffers to allocate (not including the size * already allocated). */BOOLEANNTAPIHalpGrowMapBuffers(IN PADAPTER_OBJECT AdapterObject, IN ULONG SizeOfMapBuffers){ PVOID VirtualAddress; PHYSICAL_ADDRESS PhysicalAddress; PHYSICAL_ADDRESS HighestAcceptableAddress; PHYSICAL_ADDRESS LowestAcceptableAddress; PHYSICAL_ADDRESS BoundryAddressMultiple; KIRQL OldIrql; ULONG MapRegisterCount;
/* Check if enough map register slots are available. */ MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers); if (MapRegisterCount + AdapterObject->NumberOfMapRegisters > MAX_MAP_REGISTERS) { DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n", AdapterObject->NumberOfMapRegisters, MapRegisterCount, MAX_MAP_REGISTERS); return FALSE; }
/* * Allocate memory for the new map registers. For 32-bit adapters we use * two passes in order not to waste scare resource (low memory). */ HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); LowestAcceptableAddress.HighPart = 0; LowestAcceptableAddress.LowPart = HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0; BoundryAddressMultiple.QuadPart = 0;
VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); if (!(VirtualAddress) && (LowestAcceptableAddress.LowPart)) { LowestAcceptableAddress.LowPart = 0; VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); }
if (!VirtualAddress) return FALSE;
PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
/* * All the following must be done with the master adapter lock held * to prevent corruption. */ KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql);
/* * Setup map register entries for the buffer allocated. Each entry has * a virtual and physical address and corresponds to PAGE_SIZE large * buffer. */ if (MapRegisterCount > 0) { PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry;
CurrentEntry = AdapterObject->MapRegisterBase + AdapterObject->NumberOfMapRegisters; do { /* * Leave one entry free for every non-contiguous memory region * in the map register bitmap. This ensures that we can search * using RtlFindClearBits for contiguous map register regions. * * Also for non-EISA DMA leave one free entry for every 64Kb * break, because the DMA controller can handle only coniguous * 64Kb regions. */ if (CurrentEntry != AdapterObject->MapRegisterBase) { PreviousEntry = CurrentEntry - 1; if ((PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE) == PhysicalAddress.LowPart) { if (!HalpEisaDma) { if ((PreviousEntry->PhysicalAddress.LowPart ^ PhysicalAddress.LowPart) & 0xFFFF0000) { CurrentEntry++; AdapterObject->NumberOfMapRegisters++; } } } else { CurrentEntry++; AdapterObject->NumberOfMapRegisters++; } }
RtlClearBit(AdapterObject->MapRegisters, (ULONG)(CurrentEntry - AdapterObject->MapRegisterBase)); CurrentEntry->VirtualAddress = VirtualAddress; CurrentEntry->PhysicalAddress = PhysicalAddress;
PhysicalAddress.LowPart += PAGE_SIZE; VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
CurrentEntry++; AdapterObject->NumberOfMapRegisters++; MapRegisterCount--; } while (MapRegisterCount); }
KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql);
return TRUE;}
/** * @name HalpDmaAllocateMasterAdapter * * Helper routine to allocate and initialize master adapter object and it's * associated map register buffers. * * @see HalpInitDma */PADAPTER_OBJECTNTAPIHalpDmaAllocateMasterAdapter(VOID){ PADAPTER_OBJECT MasterAdapter; ULONG Size, SizeOfBitmap;
SizeOfBitmap = MAX_MAP_REGISTERS; Size = sizeof(ADAPTER_OBJECT); Size += sizeof(RTL_BITMAP); Size += (SizeOfBitmap + 7) >> 3;
MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA); if (!MasterAdapter) return NULL;
RtlZeroMemory(MasterAdapter, Size);
KeInitializeSpinLock(&MasterAdapter->SpinLock); InitializeListHead(&MasterAdapter->AdapterQueue);
MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1); RtlInitializeBitMap(MasterAdapter->MapRegisters, (PULONG)(MasterAdapter->MapRegisters + 1), SizeOfBitmap); RtlSetAllBits(MasterAdapter->MapRegisters); MasterAdapter->NumberOfMapRegisters = 0; MasterAdapter->CommittedMapRegisters = 0;
MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag(NonPagedPool, SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY), TAG_DMA); if (!MasterAdapter->MapRegisterBase) { ExFreePool(MasterAdapter); return NULL; }
RtlZeroMemory(MasterAdapter->MapRegisterBase, SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY)); if (!HalpGrowMapBuffers(MasterAdapter, 0x10000)) { ExFreePool(MasterAdapter); return NULL; }
return MasterAdapter;}
/** * @name HalpDmaAllocateChildAdapter * * Helper routine of HalGetAdapter. Allocate child adapter object and * fill out some basic fields. * * @see HalGetAdapter */PADAPTER_OBJECTNTAPIHalpDmaAllocateChildAdapter(IN ULONG NumberOfMapRegisters, IN PDEVICE_DESCRIPTION DeviceDescription){ PADAPTER_OBJECT AdapterObject; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; HANDLE Handle;
InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE | OBJ_PERMANENT, NULL, NULL);
Status = ObCreateObject(KernelMode, IoAdapterObjectType, &ObjectAttributes, KernelMode, NULL, sizeof(ADAPTER_OBJECT), 0, 0, (PVOID)&AdapterObject); if (!NT_SUCCESS(Status)) return NULL;
RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
Status = ObInsertObject(AdapterObject, NULL, FILE_READ_DATA | FILE_WRITE_DATA, 0, NULL, &Handle); if (!NT_SUCCESS(Status)) return NULL;
ObReferenceObject(AdapterObject);
ZwClose(Handle);
AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version; AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT); AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations; AdapterObject->MapRegistersPerChannel = 1; AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; AdapterObject->ChannelNumber = 0xFF; AdapterObject->MasterAdapter = HalpMasterAdapter; KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
return AdapterObject;}#endif
/** * @name HalpDmaInitializeEisaAdapter * * Setup DMA modes and extended modes for (E)ISA DMA adapter object. */BOOLEANNTAPIHalpDmaInitializeEisaAdapter(IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_DESCRIPTION DeviceDescription){ UCHAR Controller; DMA_MODE DmaMode = {{0 }}; DMA_EXTENDED_MODE ExtendedMode = {{ 0 }}; PVOID AdapterBaseVa;
Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1;
if (Controller == 1) { AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController1)); } else { AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2)); }
AdapterObject->AdapterNumber = Controller; AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3); AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel]; AdapterObject->Width16Bits = FALSE; AdapterObject->AdapterBaseVa = AdapterBaseVa;
if (HalpEisaDma) { ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber;
switch (DeviceDescription->DmaSpeed) { case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break; case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break; case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break; case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break; default: return FALSE; }
switch (DeviceDescription->DmaWidth) { case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break; case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break; case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break; default: return FALSE; }
if (Controller == 1) { WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1)), ExtendedMode.Byte); } else { WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2)), ExtendedMode.Byte); } } else { /* * Validate setup for non-busmaster DMA adapter. Secondary controller * supports only 16-bit transfers and main controller supports only * 8-bit transfers. Anything else is invalid. */ if (!DeviceDescription->Master) { if ((Controller == 2) && (DeviceDescription->DmaWidth == Width16Bits)) { AdapterObject->Width16Bits = TRUE; } else if ((Controller != 1) || (DeviceDescription->DmaWidth != Width8Bits)) { return FALSE; } } }
DmaMode.Channel = AdapterObject->ChannelNumber; DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
/* * Set the DMA request mode. * * For (E)ISA bus master devices just unmask (enable) the DMA channel * and set it to cascade mode. Otherwise just select the right one * bases on the passed device description. */ if (DeviceDescription->Master) { DmaMode.RequestMode = CASCADE_REQUEST_MODE; if (Controller == 1) { /* Set the Request Data */ _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR) WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
/* Unmask DMA Channel */ WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); } else { /* Set the Request Data */ WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte);
/* Unmask DMA Channel */ WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); } } else { if (DeviceDescription->DemandMode) { DmaMode.RequestMode = DEMAND_REQUEST_MODE; } else { DmaMode.RequestMode = SINGLE_REQUEST_MODE; } }
AdapterObject->AdapterMode = DmaMode;
return TRUE;}
#ifndef _MINIHAL_/** * @name HalGetAdapter * * Allocate an adapter object for DMA device. * * @param DeviceDescription * Structure describing the attributes of the device. * @param NumberOfMapRegisters * On return filled with the maximum number of map registers the * device driver can allocate for DMA transfer operations. * * @return The DMA adapter on success, NULL otherwise. * * @implemented */PADAPTER_OBJECTNTAPIHalGetAdapter(IN PDEVICE_DESCRIPTION DeviceDescription, OUT PULONG NumberOfMapRegisters){ PADAPTER_OBJECT AdapterObject = NULL; BOOLEAN EisaAdapter; ULONG MapRegisters; ULONG MaximumLength; KIRQL OldIrql;
/* Validate parameters in device description */ if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) return NULL;
/* * See if we're going to use ISA/EISA DMA adapter. These adapters are * special since they're reused. * * Also note that we check for channel number since there are only 8 DMA * channels on ISA, so any request above this requires new adapter. */ if (((DeviceDescription->InterfaceType == Eisa) || (DeviceDescription->InterfaceType == Isa)) || !(DeviceDescription->Master)) { if (((DeviceDescription->InterfaceType == Isa) || (DeviceDescription->InterfaceType == Eisa)) && (DeviceDescription->DmaChannel >= 8)) { EisaAdapter = FALSE; } else { EisaAdapter = TRUE; } } else { EisaAdapter = FALSE; }
/* * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used * for cascading the controllers and it's not available for software use. */ if ((EisaAdapter) && (DeviceDescription->DmaChannel == 4)) return NULL;
/* * Calculate the number of map registers. * * - For EISA and PCI scatter/gather no map registers are needed. * - For ISA slave scatter/gather one map register is needed. * - For all other cases the number of map registers depends on * DeviceDescription->MaximumLength. */ MaximumLength = DeviceDescription->MaximumLength & MAXLONG; if ((DeviceDescription->ScatterGather) && ((DeviceDescription->InterfaceType == Eisa) || (DeviceDescription->InterfaceType == PCIBus))) { MapRegisters = 0; } else if ((DeviceDescription->ScatterGather) && !(DeviceDescription->Master)) { MapRegisters = 1; } else { /* * In the equation below the additional map register added by * the "+1" accounts for the case when a transfer does not start * at a page-aligned address. */ MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1; if (MapRegisters > 16) MapRegisters = 16; }
/* * Acquire the DMA lock that is used to protect the EISA adapter array. */ KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL);
/* * Now we must get ahold of the adapter object. For first eight ISA/EISA * channels there are static adapter objects that are reused and updated * on succesive HalGetAdapter calls. In other cases a new adapter object * is always created and it's to the DMA adapter list (HalpDmaAdapterList). */ if (EisaAdapter) { AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel]; if (AdapterObject) { if ((AdapterObject->NeedsMapRegisters) && (MapRegisters > AdapterObject->MapRegistersPerChannel)) { AdapterObject->MapRegistersPerChannel = MapRegisters; } } }
if (AdapterObject == NULL) { AdapterObject = HalpDmaAllocateChildAdapter(MapRegisters, DeviceDescription); if (AdapterObject == NULL) { KeSetEvent(&HalpDmaLock, 0, 0); return NULL; }
if (EisaAdapter) { HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject; }
if (MapRegisters > 0) { AdapterObject->NeedsMapRegisters = TRUE; AdapterObject->MapRegistersPerChannel = MapRegisters; } else { AdapterObject->NeedsMapRegisters = FALSE; if (DeviceDescription->Master) { AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1; } else { AdapterObject->MapRegistersPerChannel = 1; } } }
/* * Release the DMA lock. HalpEisaAdapter will no longer be touched, * so we don't need it. */ KeSetEvent(&HalpDmaLock, 0, 0);
if (!EisaAdapter) { /* If it's not one of the static adapters, add it to the list */ KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList); KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); }
/* * Setup the values in the adapter object that are common for all * types of buses. */ if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1) { AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount; } else { AdapterObject->IgnoreCount = 0; }
AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses; AdapterObject->ScatterGather = DeviceDescription->ScatterGather; AdapterObject->MasterDevice = DeviceDescription->Master; *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel;
/* * For non-(E)ISA adapters we have already done all the work. On the * other hand for (E)ISA adapters we must still setup the DMA modes * and prepare the controller. */ if (EisaAdapter) { if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription)) { ObDereferenceObject(AdapterObject); return NULL; } }
return AdapterObject;}
/** * @name HalpGetDmaAdapter * * Internal routine to allocate PnP DMA adapter object. It's exported through * HalDispatchTable and used by IoGetDmaAdapter. * * @see HalGetAdapter */PDMA_ADAPTERNTAPIHalpGetDmaAdapter(IN PVOID Context, IN PDEVICE_DESCRIPTION DeviceDescription, OUT PULONG NumberOfMapRegisters){ return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader;}
/** * @name HalPutDmaAdapter * * Internal routine to free DMA adapter and resources for reuse. It's exported * using the DMA_OPERATIONS interface by HalGetAdapter. * * @see HalGetAdapter */VOIDNTAPIHalPutDmaAdapter(IN PADAPTER_OBJECT AdapterObject){ KIRQL OldIrql; if (AdapterObject->ChannelNumber == 0xFF) { KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); RemoveEntryList(&AdapterObject->AdapterList); KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); }
ObDereferenceObject(AdapterObject);}
/** * @name HalAllocateCommonBuffer * * Allocates memory that is visible to both the processor(s) and the DMA * device. * * @param AdapterObject * Adapter object representing the bus master or system dma controller. * @param Length * Number of bytes to allocate. * @param LogicalAddress * Logical address the driver can use to access the buffer. * @param CacheEnabled * Specifies if the memory can be cached. * * @return The base virtual address of the memory allocated or NULL on failure. * * @remarks * On real NT x86 systems the CacheEnabled parameter is ignored, we honour * it. If it proves to cause problems change it. * * @see HalFreeCommonBuffer * * @implemented */PVOIDNTAPIHalAllocateCommonBuffer(IN PADAPTER_OBJECT AdapterObject, IN ULONG Length, IN PPHYSICAL_ADDRESS LogicalAddress, IN BOOLEAN CacheEnabled){ PHYSICAL_ADDRESS LowestAcceptableAddress; PHYSICAL_ADDRESS HighestAcceptableAddress; PHYSICAL_ADDRESS BoundryAddressMultiple; PVOID VirtualAddress;
LowestAcceptableAddress.QuadPart = 0; HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); BoundryAddressMultiple.QuadPart = 0;
/* * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For * slave DMA devices the 64Kb boundary mustn't be crossed since the * controller wouldn't be able to handle it. */ if (AdapterObject->MasterDevice) { BoundryAddressMultiple.HighPart = 1; } else { BoundryAddressMultiple.LowPart = 0x10000; }
VirtualAddress = MmAllocateContiguousMemorySpecifyCache(Length, LowestAcceptableAddress, HighestAcceptableAddress, BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached); if (VirtualAddress == NULL) return NULL;
*LogicalAddress = MmGetPhysicalAddress(VirtualAddress);
return VirtualAddress;}
/** * @name HalFreeCommonBuffer * * Free common buffer allocated with HalAllocateCommonBuffer. * * @see HalAllocateCommonBuffer * * @implemented */VOIDNTAPIHalFreeCommonBuffer(IN PADAPTER_OBJECT AdapterObject, IN ULONG Length, IN PHYSICAL_ADDRESS LogicalAddress, IN PVOID VirtualAddress, IN BOOLEAN CacheEnabled){ MmFreeContiguousMemorySpecifyCache(VirtualAddress, Length, CacheEnabled ? MmCached : MmNonCached);}
typedef struct _SCATTER_GATHER_CONTEXT { BOOLEAN UsingUserBuffer; PADAPTER_OBJECT AdapterObject; PMDL Mdl; PUCHAR CurrentVa; ULONG Length; PDRIVER_LIST_CONTROL AdapterListControlRoutine; PVOID AdapterListControlContext, MapRegisterBase; ULONG MapRegisterCount; BOOLEAN WriteToDevice; WAIT_CONTEXT_BLOCK Wcb;} SCATTER_GATHER_CONTEXT, *PSCATTER_GATHER_CONTEXT;
IO_ALLOCATION_ACTIONNTAPIHalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context){ PSCATTER_GATHER_CONTEXT AdapterControlContext = Context; PADAPTER_OBJECT AdapterObject = AdapterControlContext->AdapterObject; PSCATTER_GATHER_LIST ScatterGatherList; SCATTER_GATHER_ELEMENT TempElements[MAX_SG_ELEMENTS]; ULONG ElementCount = 0, RemainingLength = AdapterControlContext->Length; PUCHAR CurrentVa = AdapterControlContext->CurrentVa;
/* Store the map register base for later in HalPutScatterGatherList */ AdapterControlContext->MapRegisterBase = MapRegisterBase;
while (RemainingLength > 0 && ElementCount < MAX_SG_ELEMENTS) { TempElements[ElementCount].Length = RemainingLength; TempElements[ElementCount].Reserved = 0; TempElements[ElementCount].Address = IoMapTransfer(AdapterObject, AdapterControlContext->Mdl, MapRegisterBase, CurrentVa + (AdapterControlContext->Length - RemainingLength), &TempElements[ElementCount].Length, AdapterControlContext->WriteToDevice); if (TempElements[ElementCount].Length == 0) break;
DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n", TempElements[ElementCount].Address.QuadPart, TempElements[ElementCount].Length);
ASSERT(TempElements[ElementCount].Length <= RemainingLength); RemainingLength -= TempElements[ElementCount].Length; ElementCount++; }
if (RemainingLength > 0) { DPRINT1("Scatter/gather list construction failed!\n"); return DeallocateObject; }
ScatterGatherList = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCATTER_GATHER_LIST) + sizeof(SCATTER_GATHER_ELEMENT) * ElementCount, TAG_DMA); ASSERT(ScatterGatherList);
ScatterGatherList->NumberOfElements = ElementCount; ScatterGatherList->Reserved = (ULONG_PTR)AdapterControlContext; RtlCopyMemory(ScatterGatherList->Elements, TempElements, sizeof(SCATTER_GATHER_ELEMENT) * ElementCount);
DPRINT("Initiating S/G DMA with %d element(s)\n", ElementCount);
AdapterControlContext->AdapterListControlRoutine(DeviceObject, Irp, ScatterGatherList, AdapterControlContext->AdapterListControlContext);
return DeallocateObjectKeepRegisters;}
/** * @name HalGetScatterGatherList * * Creates a scatter-gather list to be using in scatter/gather DMA * * @param AdapterObject * Adapter object representing the bus master or system dma controller. * @param DeviceObject * The device target for DMA. * @param Mdl * The MDL that describes the buffer to be mapped. * @param CurrentVa * The current VA in the buffer to be mapped for transfer. * @param Length * Specifies the length of data in bytes to be mapped. * @param ExecutionRoutine * A caller supplied AdapterListControl routine to be called when DMA is available. * @param Context * Context passed to the AdapterListControl routine. * @param WriteToDevice * Indicates direction of DMA operation. * * @return The status of the operation. * * @see HalBuildScatterGatherList * * @implemented */ NTSTATUS NTAPI HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_OBJECT DeviceObject, IN PMDL Mdl, IN PVOID CurrentVa, IN ULONG Length, IN PDRIVER_LIST_CONTROL ExecutionRoutine, IN PVOID Context, IN BOOLEAN WriteToDevice){ return HalBuildScatterGatherList(AdapterObject, DeviceObject, Mdl, CurrentVa, Length, ExecutionRoutine, Context, WriteToDevice, NULL, 0);}
/** * @name HalPutScatterGatherList * * Frees a scatter-gather list allocated from HalBuildScatterGatherList * * @param AdapterObject * Adapter object representing the bus master or system dma controller. * @param ScatterGather * The scatter/gather list to be freed. * @param WriteToDevice * Indicates direction of DMA operation. * * @return None * * @see HalBuildScatterGatherList * * @implemented */ VOID NTAPI HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject, IN PSCATTER_GATHER_LIST ScatterGather, IN BOOLEAN WriteToDevice){ PSCATTER_GATHER_CONTEXT AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved; ULONG i;
for (i = 0; i < ScatterGather->NumberOfElements; i++) { IoFlushAdapterBuffers(AdapterObject, AdapterControlContext->Mdl, AdapterControlContext->MapRegisterBase, AdapterControlContext->CurrentVa, ScatterGather->Elements[i].Length, AdapterControlContext->WriteToDevice); AdapterControlContext->CurrentVa += ScatterGather->Elements[i].Length; }
IoFreeMapRegisters(AdapterObject, AdapterControlContext->MapRegisterBase, AdapterControlContext->MapRegisterCount);
ExFreePoolWithTag(ScatterGather, TAG_DMA);
/* If this is our buffer, release it */ if (!AdapterControlContext->UsingUserBuffer) ExFreePoolWithTag(AdapterControlContext, TAG_DMA);
DPRINT("S/G DMA has finished!\n");}
NTSTATUSNTAPIHalCalculateScatterGatherListSize( IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl OPTIONAL, IN PVOID CurrentVa, IN ULONG Length, OUT PULONG ScatterGatherListSize, OUT PULONG pNumberOfMapRegisters){ ULONG NumberOfMapRegisters; ULONG SgSize;
UNIMPLEMENTED_ONCE;
NumberOfMapRegisters = PAGE_ROUND_UP(Length) >> PAGE_SHIFT; SgSize = sizeof(SCATTER_GATHER_CONTEXT);
*ScatterGatherListSize = SgSize; if (pNumberOfMapRegisters) *pNumberOfMapRegisters = NumberOfMapRegisters;
return STATUS_SUCCESS;}
/** * @name HalBuildScatterGatherList * * Creates a scatter-gather list to be using in scatter/gather DMA * * @param AdapterObject * Adapter object representing the bus master or system dma controller. * @param DeviceObject * The device target for DMA. * @param Mdl * The MDL that describes the buffer to be mapped. * @param CurrentVa * The current VA in the buffer to be mapped for transfer. * @param Length * Specifies the length of data in bytes to be mapped. * @param ExecutionRoutine * A caller supplied AdapterListControl routine to be called when DMA is available. * @param Context * Context passed to the AdapterListControl routine. * @param WriteToDevice * Indicates direction of DMA operation. * * @param ScatterGatherBuffer * User buffer for the scatter-gather list * * @param ScatterGatherBufferLength * Buffer length * * @return The status of the operation. * * @see HalPutScatterGatherList * * @implemented */NTSTATUSNTAPIHalBuildScatterGatherList( IN PADAPTER_OBJECT AdapterObject, IN PDEVICE_OBJECT DeviceObject, IN PMDL Mdl, IN PVOID CurrentVa, IN ULONG Length, IN PDRIVER_LIST_CONTROL ExecutionRoutine, IN PVOID Context, IN BOOLEAN WriteToDevice, IN PVOID ScatterGatherBuffer, IN ULONG ScatterGatherBufferLength){ NTSTATUS Status; ULONG SgSize, NumberOfMapRegisters; PSCATTER_GATHER_CONTEXT ScatterGatherContext; BOOLEAN UsingUserBuffer;
Status = HalCalculateScatterGatherListSize(AdapterObject, Mdl, CurrentVa, Length, &SgSize, &NumberOfMapRegisters); if (!NT_SUCCESS(Status)) return Status;
if (ScatterGatherBuffer) { /* Checking if user buffer is enough */ if (ScatterGatherBufferLength < SgSize) { return STATUS_BUFFER_TOO_SMALL; } UsingUserBuffer = TRUE; } else { ScatterGatherBuffer = ExAllocatePoolWithTag(NonPagedPool, SgSize, TAG_DMA); if (!ScatterGatherBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } UsingUserBuffer = FALSE; }
{ ScatterGatherContext = (PSCATTER_GATHER_CONTEXT)ScatterGatherBuffer;
/* Fill the scatter-gather context */ ScatterGatherContext->UsingUserBuffer = UsingUserBuffer; ScatterGatherContext->AdapterObject = AdapterObject; ScatterGatherContext->Mdl = Mdl; ScatterGatherContext->CurrentVa = CurrentVa; ScatterGatherContext->Length = Length; ScatterGatherContext->MapRegisterCount = NumberOfMapRegisters; ScatterGatherContext->AdapterListControlRoutine = ExecutionRoutine; ScatterGatherContext->AdapterListControlContext = Context; ScatterGatherContext->WriteToDevice = WriteToDevice;
ScatterGatherContext->Wcb.DeviceObject = DeviceObject; ScatterGatherContext->Wcb.DeviceContext = (PVOID)ScatterGatherContext; ScatterGatherContext->Wcb.CurrentIrp = DeviceObject->CurrentIrp;
Status = HalAllocateAdapterChannel(AdapterObject, &ScatterGatherContext->Wcb, NumberOfMapRegisters, HalpScatterGatherAdapterControl);
if (!NT_SUCCESS(Status)) { if (!UsingUserBuffer) ExFreePoolWithTag(ScatterGatherBuffer, TAG_DMA); return Status; } }
return STATUS_SUCCESS;}
NTSTATUSNTAPIHalBuildMdlFromScatterGatherList( IN PDMA_ADAPTER DmaAdapter, IN PSCATTER_GATHER_LIST ScatterGather, IN PMDL OriginalMdl, OUT PMDL *TargetMdl){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}#endif
/** * @name HalpDmaGetDmaAlignment * * Internal routine to return the DMA alignment requirement. It's exported * using the DMA_OPERATIONS interface by HalGetAdapter. * * @see HalGetAdapter */ULONGNTAPIHalpDmaGetDmaAlignment(IN PADAPTER_OBJECT AdapterObject){ return 1;}
/* * @name HalReadDmaCounter * * Read DMA operation progress counter. * * @implemented */ULONGNTAPIHalReadDmaCounter(IN PADAPTER_OBJECT AdapterObject){ KIRQL OldIrql; ULONG Count, OldCount;
ASSERT(!AdapterObject->MasterDevice);
/* * Acquire the master adapter lock since we're going to mess with the * system DMA controller registers and we really don't want anyone * to do the same at the same time. */ KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
/* Send the request to the specific controller. */ if (AdapterObject->AdapterNumber == 1) { PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
Count = 0xffff00; do { OldCount = Count;
/* Send Reset */ WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
/* Read Count */ Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount [AdapterObject->ChannelNumber].DmaBaseCount); Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount [AdapterObject->ChannelNumber].DmaBaseCount) << 8; } while (0xffff00 & (OldCount ^ Count)); } else { PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
Count = 0xffff00; do { OldCount = Count;
/* Send Reset */ WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
/* Read Count */ Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount [AdapterObject->ChannelNumber].DmaBaseCount); Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount [AdapterObject->ChannelNumber].DmaBaseCount) << 8; } while (0xffff00 & (OldCount ^ Count)); }
KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql);
Count++; Count &= 0xffff; if (AdapterObject->Width16Bits) Count *= 2;
return Count;}
#ifndef _MINIHAL_/** * @name HalpGrowMapBufferWorker * * Helper routine of HalAllocateAdapterChannel for allocating map registers * at PASSIVE_LEVEL in work item. */VOIDNTAPIHalpGrowMapBufferWorker(IN PVOID DeferredContext){ PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext; KIRQL OldIrql; BOOLEAN Succeeded;
/* * Try to allocate new map registers for the adapter. * * NOTE: The NT implementation actually tries to allocate more map * registers than needed as an optimization. */ KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL); Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter, WorkItem->NumberOfMapRegisters << PAGE_SHIFT); KeSetEvent(&HalpDmaLock, 0, 0);
if (Succeeded) { /* * Flush the adapter queue now that new map registers are ready. The * easiest way to do that is to call IoFreeMapRegisters to not free * any registers. Note that we use the magic (PVOID)2 map register * base to bypass the parameter checking. */ OldIrql = KfRaiseIrql(DISPATCH_LEVEL); IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0); KfLowerIrql(OldIrql); }
ExFreePool(WorkItem);}
/** * @name HalAllocateAdapterChannel * * Setup map registers for an adapter object. * * @param AdapterObject * Pointer to an ADAPTER_OBJECT to set up. * @param WaitContextBlock * Context block to be used with ExecutionRoutine. * @param NumberOfMapRegisters * Number of map registers requested. * @param ExecutionRoutine * Callback to call when map registers are allocated. * * @return * If not enough map registers can be allocated then * STATUS_INSUFFICIENT_RESOURCES is returned. If the function * succeeds or the callback is queued for later delivering then * STATUS_SUCCESS is returned. * * @see IoFreeAdapterChannel * * @implemented */NTSTATUSNTAPIHalAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject, IN PWAIT_CONTEXT_BLOCK WaitContextBlock, IN ULONG NumberOfMapRegisters, IN PDRIVER_CONTROL ExecutionRoutine){ PADAPTER_OBJECT MasterAdapter; PGROW_WORK_ITEM WorkItem; ULONG Index = MAXULONG; ULONG Result; KIRQL OldIrql;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Set up the wait context block in case we can't run right away. */ WaitContextBlock->DeviceRoutine = ExecutionRoutine; WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
/* Returns true if queued, else returns false and sets the queue to busy */ if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry)) { return STATUS_SUCCESS; }
MasterAdapter = AdapterObject->MasterAdapter;
AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; AdapterObject->CurrentWcb = WaitContextBlock;
if ((NumberOfMapRegisters) && (AdapterObject->NeedsMapRegisters)) { if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { AdapterObject->NumberOfMapRegisters = 0; IoFreeAdapterChannel(AdapterObject); return STATUS_INSUFFICIENT_RESOURCES; }
/* * Get the map registers. This is partly complicated by the fact * that new map registers can only be allocated at PASSIVE_LEVEL * and we're currently at DISPATCH_LEVEL. The following code has * two code paths: * * - If there is no adapter queued for map register allocation, * try to see if enough contiguous map registers are present. * In case they're we can just get them and proceed further. * * - If some adapter is already present in the queue we must * respect the order of adapters asking for map registers and * so the fast case described above can't take place. * This case is also entered if not enough coniguous map * registers are present. * * A work queue item is allocated and queued, the adapter is * also queued into the master adapter queue. The worker * routine does the job of allocating the map registers at * PASSIVE_LEVEL and calling the ExecutionRoutine. */
KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
if (IsListEmpty(&MasterAdapter->AdapterQueue)) { Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, NumberOfMapRegisters, 0); if (Index != MAXULONG) { AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; if (!AdapterObject->ScatterGather) { AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); } } }
if (Index == MAXULONG) { InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue);
WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(GROW_WORK_ITEM), TAG_DMA); if (WorkItem) { ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem); WorkItem->AdapterObject = AdapterObject; WorkItem->NumberOfMapRegisters = NumberOfMapRegisters;
ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
return STATUS_SUCCESS; }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); } else { AdapterObject->MapRegisterBase = NULL; AdapterObject->NumberOfMapRegisters = 0; }
AdapterObject->CurrentWcb = WaitContextBlock;
Result = ExecutionRoutine(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
/* * Possible return values: * * - KeepObject * Don't free any resources, the ADAPTER_OBJECT is still in use and * the caller will call IoFreeAdapterChannel later. * * - DeallocateObject * Deallocate the map registers and release the ADAPTER_OBJECT, so * someone else can use it. * * - DeallocateObjectKeepRegisters * Release the ADAPTER_OBJECT, but hang on to the map registers. The * client will later call IoFreeMapRegisters. * * NOTE: * IoFreeAdapterChannel runs the queue, so it must be called unless * the adapter object is not to be freed. */ if (Result == DeallocateObject) { IoFreeAdapterChannel(AdapterObject); } else if (Result == DeallocateObjectKeepRegisters) { AdapterObject->NumberOfMapRegisters = 0; IoFreeAdapterChannel(AdapterObject); }
return STATUS_SUCCESS;}
/** * @name IoFreeAdapterChannel * * Free DMA resources allocated by IoAllocateAdapterChannel. * * @param AdapterObject * Adapter object with resources to free. * * @remarks * This function releases map registers registers assigned to the DMA * adapter. After releasing the adapter, it checks the adapter's queue * and runs each queued device object in series until the queue is * empty. This is the only way the device queue is emptied. * * @see IoAllocateAdapterChannel * * @implemented */VOIDNTAPIIoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject){ PADAPTER_OBJECT MasterAdapter; PKDEVICE_QUEUE_ENTRY DeviceQueueEntry; PWAIT_CONTEXT_BLOCK WaitContextBlock; ULONG Index = MAXULONG; ULONG Result; KIRQL OldIrql;
MasterAdapter = AdapterObject->MasterAdapter;
for (;;) { /* * To keep map registers, call here with AdapterObject-> * NumberOfMapRegisters set to zero. This trick is used in * HalAllocateAdapterChannel for example. */ if (AdapterObject->NumberOfMapRegisters) { IoFreeMapRegisters(AdapterObject, AdapterObject->MapRegisterBase, AdapterObject->NumberOfMapRegisters); }
DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue); if (!DeviceQueueEntry) break;
WaitContextBlock = CONTAINING_RECORD(DeviceQueueEntry, WAIT_CONTEXT_BLOCK, WaitQueueEntry);
AdapterObject->CurrentWcb = WaitContextBlock; AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters;
if ((WaitContextBlock->NumberOfMapRegisters) && (AdapterObject->MasterAdapter)) { KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
if (IsListEmpty(&MasterAdapter->AdapterQueue)) { Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, WaitContextBlock->NumberOfMapRegisters, 0); if (Index != MAXULONG) { AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; if (!AdapterObject->ScatterGather) { AdapterObject->MapRegisterBase =(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); } } }
if (Index == MAXULONG) { InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); break; }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); } else { AdapterObject->MapRegisterBase = NULL; AdapterObject->NumberOfMapRegisters = 0; }
/* Call the adapter control routine. */ Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext); switch (Result) { case KeepObject: /* * We're done until the caller manually calls IoFreeAdapterChannel * or IoFreeMapRegisters. */ return;
case DeallocateObjectKeepRegisters: /* * Hide the map registers so they aren't deallocated next time * around. */ AdapterObject->NumberOfMapRegisters = 0; break;
default: break; } }}
/** * @name IoFreeMapRegisters * * Free map registers reserved by the system for a DMA. * * @param AdapterObject * DMA adapter to free map registers on. * @param MapRegisterBase * Handle to map registers to free. * @param NumberOfRegisters * Number of map registers to be freed. * * @implemented */VOIDNTAPIIoFreeMapRegisters(IN PADAPTER_OBJECT AdapterObject, IN PVOID MapRegisterBase, IN ULONG NumberOfMapRegisters){ PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; PLIST_ENTRY ListEntry; KIRQL OldIrql; ULONG Index; ULONG Result;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
if (!(MasterAdapter) || !(MapRegisterBase)) return;
KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql);
if (NumberOfMapRegisters != 0) { PROS_MAP_REGISTER_ENTRY RealMapRegisterBase;
RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); RtlClearBits(MasterAdapter->MapRegisters, (ULONG)(RealMapRegisterBase - MasterAdapter->MapRegisterBase), NumberOfMapRegisters); }
/* * Now that we freed few map registers it's time to look at the master * adapter queue and see if there is someone waiting for map registers. */ while (!IsListEmpty(&MasterAdapter->AdapterQueue)) { ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue); AdapterObject = CONTAINING_RECORD(ListEntry, struct _ADAPTER_OBJECT, AdapterQueue);
Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, AdapterObject->NumberOfMapRegisters, 0); if (Index == MAXULONG) { InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry); break; }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);
AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; if (!AdapterObject->ScatterGather) { AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); }
Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(AdapterObject->CurrentWcb->DeviceObject, AdapterObject->CurrentWcb->CurrentIrp, AdapterObject->MapRegisterBase, AdapterObject->CurrentWcb->DeviceContext); switch (Result) { case DeallocateObjectKeepRegisters: AdapterObject->NumberOfMapRegisters = 0; /* fall through */
case DeallocateObject: if (AdapterObject->NumberOfMapRegisters) { KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); RtlClearBits(MasterAdapter->MapRegisters, (ULONG)(AdapterObject->MapRegisterBase - MasterAdapter->MapRegisterBase), AdapterObject->NumberOfMapRegisters); KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); }
IoFreeAdapterChannel(AdapterObject); break;
default: break; }
KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); }
KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql);}
/** * @name HalpCopyBufferMap * * Helper function for copying data from/to map register buffers. * * @see IoFlushAdapterBuffers, IoMapTransfer */VOIDNTAPIHalpCopyBufferMap(IN PMDL Mdl, IN PROS_MAP_REGISTER_ENTRY MapRegisterBase, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice){ ULONG CurrentLength; ULONG_PTR CurrentAddress; ULONG ByteOffset; PVOID VirtualAddress;
VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority); if (!VirtualAddress) { /* * NOTE: On real NT a mechanism with reserved pages is implemented * to handle this case in a slow, but graceful non-fatal way. */ KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); }
CurrentAddress = (ULONG_PTR)VirtualAddress + (ULONG_PTR)CurrentVa - (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
while (Length > 0) { ByteOffset = BYTE_OFFSET(CurrentAddress); CurrentLength = PAGE_SIZE - ByteOffset; if (CurrentLength > Length) CurrentLength = Length;
if (WriteToDevice) { RtlCopyMemory((PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), (PVOID)CurrentAddress, CurrentLength); } else { RtlCopyMemory((PVOID)CurrentAddress, (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), CurrentLength); }
Length -= CurrentLength; CurrentAddress += CurrentLength; MapRegisterBase++; }}
/** * @name IoFlushAdapterBuffers * * Flush any data remaining in the DMA controller's memory into the host * memory. * * @param AdapterObject * The adapter object to flush. * @param Mdl * Original MDL to flush data into. * @param MapRegisterBase * Map register base that was just used by IoMapTransfer, etc. * @param CurrentVa * Offset into Mdl to be flushed into, same as was passed to * IoMapTransfer. * @param Length * Length of the buffer to be flushed into. * @param WriteToDevice * TRUE if it's a write, FALSE if it's a read. * * @return TRUE in all cases. * * @remarks * This copies data from the map register-backed buffer to the user's * target buffer. Data are not in the user buffer until this function * is called. * For slave DMA transfers the controller channel is masked effectively * stopping the current transfer. * * @unimplemented. */BOOLEANNTAPIIoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN ULONG Length, IN BOOLEAN WriteToDevice){ BOOLEAN SlaveDma = FALSE; PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; PHYSICAL_ADDRESS HighestAcceptableAddress; PHYSICAL_ADDRESS PhysicalAddress; PPFN_NUMBER MdlPagesPtr;
/* Sanity checks */ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT(AdapterObject);
if (!AdapterObject->MasterDevice) { /* Mask out (disable) the DMA channel. */ if (AdapterObject->AdapterNumber == 1) { PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_SETMASK); } else { PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; WRITE_PORT_UCHAR(&DmaControl2->SingleMask, AdapterObject->ChannelNumber | DMA_SETMASK); } SlaveDma = TRUE; }
/* This can happen if the device supports hardware scatter/gather. */ if (MapRegisterBase == NULL) return TRUE;
RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
if (!WriteToDevice) { if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) { if (RealMapRegisterBase->Counter != MAXULONG) { if ((SlaveDma) && !(AdapterObject->IgnoreCount)) { Length -= HalReadDmaCounter(AdapterObject); } } HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE); } else { MdlPagesPtr = MmGetMdlPfnArray(Mdl); MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa);
HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); if ((PhysicalAddress.QuadPart + Length) > HighestAcceptableAddress.QuadPart) { HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE); } } }
RealMapRegisterBase->Counter = 0;
return TRUE;}
/** * @name IoMapTransfer * * Map a DMA for transfer and do the DMA if it's a slave. * * @param AdapterObject * Adapter object to do the DMA on. Bus-master may pass NULL. * @param Mdl * Locked-down user buffer to DMA in to or out of. * @param MapRegisterBase * Handle to map registers to use for this dma. * @param CurrentVa * Index into Mdl to transfer into/out of. * @param Length * Length of transfer. Number of bytes actually transferred on * output. * @param WriteToDevice * TRUE if it's an output DMA, FALSE otherwise. * * @return * A logical address that can be used to program a DMA controller, it's * not meaningful for slave DMA device. * * @remarks * This function does a copyover to contiguous memory <16MB represented * by the map registers if needed. If the buffer described by MDL can be * used as is no copyover is done. * If it's a slave transfer, this function actually performs it. * * @implemented */PHYSICAL_ADDRESSNTAPIIoMapTransfer(IN PADAPTER_OBJECT AdapterObject, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN OUT PULONG Length, IN BOOLEAN WriteToDevice){ PPFN_NUMBER MdlPagesPtr; PFN_NUMBER MdlPage1, MdlPage2; ULONG ByteOffset; ULONG TransferOffset; ULONG TransferLength; BOOLEAN UseMapRegisters; PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; PHYSICAL_ADDRESS PhysicalAddress; PHYSICAL_ADDRESS HighestAcceptableAddress; ULONG Counter; DMA_MODE AdapterMode; KIRQL OldIrql;
/* * Precalculate some values that are used in all cases. * * ByteOffset is offset inside the page at which the transfer starts. * MdlPagesPtr is pointer inside the MDL page chain at the page where the * transfer start. * PhysicalAddress is physical address corresponding to the transfer * start page and offset. * TransferLength is the initial length of the transfer, which is reminder * of the first page. The actual value is calculated below. * * Note that all the variables can change during the processing which * takes place below. These are just initial values. */ ByteOffset = BYTE_OFFSET(CurrentVa);
MdlPagesPtr = MmGetMdlPfnArray(Mdl); MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT;
PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; PhysicalAddress.QuadPart += ByteOffset;
TransferLength = PAGE_SIZE - ByteOffset;
/* * Special case for bus master adapters with S/G support. We can directly * use the buffer specified by the MDL, so not much work has to be done. * * Just return the passed VA's corresponding physical address and update * length to the number of physically contiguous bytes found. Also * pages crossing the 4Gb boundary aren't considered physically contiguous. */ if (MapRegisterBase == NULL) { while (TransferLength < *Length) { MdlPage1 = *MdlPagesPtr; MdlPage2 = *(MdlPagesPtr + 1); if (MdlPage1 + 1 != MdlPage2) break; if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) break; TransferLength += PAGE_SIZE; MdlPagesPtr++; }
if (TransferLength < *Length) *Length = TransferLength;
return PhysicalAddress; }
/* * The code below applies to slave DMA adapters and bus master adapters * without hardward S/G support. */ RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG);
/* * Try to calculate the size of the transfer. We can only transfer * pages that are physically contiguous and that don't cross the * 64Kb boundary (this limitation applies only for ISA controllers). */ while (TransferLength < *Length) { MdlPage1 = *MdlPagesPtr; MdlPage2 = *(MdlPagesPtr + 1); if (MdlPage1 + 1 != MdlPage2) break; if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) break; TransferLength += PAGE_SIZE; MdlPagesPtr++; }
if (TransferLength > *Length) TransferLength = *Length;
/* * If we're about to simulate software S/G and not all the pages are * physically contiguous then we must use the map registers to store * the data and allow the whole transfer to proceed at once. */ if (((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) && (TransferLength < *Length)) { UseMapRegisters = TRUE; PhysicalAddress = RealMapRegisterBase->PhysicalAddress; PhysicalAddress.QuadPart += ByteOffset; TransferLength = *Length; RealMapRegisterBase->Counter = MAXULONG; Counter = 0; } else { /* * This is ordinary DMA transfer, so just update the progress * counters. These are used by IoFlushAdapterBuffers to track * the transfer progress. */ UseMapRegisters = FALSE; Counter = RealMapRegisterBase->Counter; RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength);
/* * Check if the buffer doesn't exceed the highest physical address * limit of the device. In that case we must use the map registers to * store the data. */ HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); if ((PhysicalAddress.QuadPart + TransferLength) > HighestAcceptableAddress.QuadPart) { UseMapRegisters = TRUE; PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress; PhysicalAddress.QuadPart += ByteOffset; if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) { RealMapRegisterBase->Counter = MAXULONG; Counter = 0; } } }
/* * If we decided to use the map registers (see above) and we're about * to transfer data to the device then copy the buffers into the map * register memory. */ if ((UseMapRegisters) && (WriteToDevice)) { HalpCopyBufferMap(Mdl, RealMapRegisterBase + Counter, CurrentVa, TransferLength, WriteToDevice); }
/* * Return the length of transfer that actually takes place. */ *Length = TransferLength;
/* * If we're doing slave (system) DMA then program the (E)ISA controller * to actually start the transfer. */ if ((AdapterObject) && !(AdapterObject->MasterDevice)) { AdapterMode = AdapterObject->AdapterMode;
if (WriteToDevice) { AdapterMode.TransferType = WRITE_TRANSFER; } else { AdapterMode.TransferType = READ_TRANSFER; if (AdapterObject->IgnoreCount) { RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + ByteOffset, TransferLength); } }
TransferOffset = PhysicalAddress.LowPart & 0xFFFF; if (AdapterObject->Width16Bits) { TransferLength >>= 1; TransferOffset >>= 1; }
KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
if (AdapterObject->AdapterNumber == 1) { PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
/* Reset Register */ WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
/* Set the Mode */ WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte);
/* Set the Offset Register */ WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, (UCHAR)(TransferOffset)); WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, (UCHAR)(TransferOffset >> 8));
/* Set the Page Register */ WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), (UCHAR)(PhysicalAddress.LowPart >> 16)); if (HalpEisaDma) { WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 0); }
/* Set the Length */ WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, (UCHAR)(TransferLength - 1)); WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, (UCHAR)((TransferLength - 1) >> 8));
/* Unmask the Channel */ WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); } else { PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
/* Reset Register */ WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0);
/* Set the Mode */ WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte);
/* Set the Offset Register */ WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, (UCHAR)(TransferOffset)); WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, (UCHAR)(TransferOffset >> 8));
/* Set the Page Register */ WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), (UCHAR)(PhysicalAddress.u.LowPart >> 16)); if (HalpEisaDma) { WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 0); }
/* Set the Length */ WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, (UCHAR)(TransferLength - 1)); WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, (UCHAR)((TransferLength - 1) >> 8));
/* Unmask the Channel */ WRITE_PORT_UCHAR(&DmaControl2->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); }
KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); }
/* * Return physical address of the buffer with data that is used for the * transfer. It can either point inside the Mdl that was passed by the * caller or into the map registers if the Mdl buffer can't be used * directly. */ return PhysicalAddress;}#endif
/** * @name HalFlushCommonBuffer * * @implemented */BOOLEANNTAPIHalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject, IN ULONG Length, IN PHYSICAL_ADDRESS LogicalAddress, IN PVOID VirtualAddress){ /* Function always returns true */ return TRUE;}
/* * @implemented */PVOIDNTAPIHalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject, IN OUT PULONG NumberOfMapRegisters){ PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; ULONG MapRegisterNumber;
/* Check if it needs map registers */ if (AdapterObject->NeedsMapRegisters) { /* Check if we have enough */ if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { /* We don't, fail */ AdapterObject->NumberOfMapRegisters = 0; return NULL; }
/* Try to find free map registers */ MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, *NumberOfMapRegisters, 0);
/* Check if nothing was found */ if (MapRegisterNumber == MAXULONG) { /* No free registers found, so use the base registers */ RtlSetBits(MasterAdapter->MapRegisters, 0, *NumberOfMapRegisters); MapRegisterNumber = 0; }
/* Calculate the new base */ AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase + MapRegisterNumber);
/* Check if scatter gather isn't supported */ if (!AdapterObject->ScatterGather) { /* Set the flag */ AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY) ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); } } else { AdapterObject->MapRegisterBase = NULL; AdapterObject->NumberOfMapRegisters = 0; }
/* Return the base */ return AdapterObject->MapRegisterBase;}
/* EOF */