Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendma.c
Go to the documentation of this file.
00001 /* $Id: dma.c 24759 2006-11-14 20:59:48Z ion $ 00002 * 00003 * COPYRIGHT: See COPYING in the top level directory 00004 * PROJECT: ReactOS kernel 00005 * FILE: ntoskrnl/hal/x86/dma.c 00006 * PURPOSE: DMA functions 00007 * PROGRAMMERS: David Welch (welch@mcmail.com) 00008 * Filip Navara (navaraf@reactos.com) 00009 * UPDATE HISTORY: 00010 * Created 22/05/98 00011 */ 00012 00072 /* INCLUDES *****************************************************************/ 00073 00074 #include <hal.h> 00075 #define NDEBUG 00076 #include <debug.h> 00077 00078 static KEVENT HalpDmaLock; 00079 static LIST_ENTRY HalpDmaAdapterList; 00080 static PADAPTER_OBJECT HalpEisaAdapter[8]; 00081 static BOOLEAN HalpEisaDma; 00082 static PADAPTER_OBJECT HalpMasterAdapter; 00083 00084 static const ULONG_PTR HalpEisaPortPage[8] = { 00085 FIELD_OFFSET(DMA_PAGE, Channel0), 00086 FIELD_OFFSET(DMA_PAGE, Channel1), 00087 FIELD_OFFSET(DMA_PAGE, Channel2), 00088 FIELD_OFFSET(DMA_PAGE, Channel3), 00089 0, 00090 FIELD_OFFSET(DMA_PAGE, Channel5), 00091 FIELD_OFFSET(DMA_PAGE, Channel6), 00092 FIELD_OFFSET(DMA_PAGE, Channel7) 00093 }; 00094 00095 static DMA_OPERATIONS HalpDmaOperations = { 00096 sizeof(DMA_OPERATIONS), 00097 (PPUT_DMA_ADAPTER)HalPutDmaAdapter, 00098 (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer, 00099 (PFREE_COMMON_BUFFER)HalFreeCommonBuffer, 00100 NULL, /* Initialized in HalpInitDma() */ 00101 NULL, /* Initialized in HalpInitDma() */ 00102 NULL, /* Initialized in HalpInitDma() */ 00103 NULL, /* Initialized in HalpInitDma() */ 00104 NULL, /* Initialized in HalpInitDma() */ 00105 (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment, 00106 (PREAD_DMA_COUNTER)HalReadDmaCounter, 00107 /* FIXME: Implement the S/G funtions. */ 00108 NULL /*(PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList*/, 00109 NULL /*(PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList*/, 00110 NULL /*(PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize*/, 00111 NULL /*(PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList*/, 00112 NULL /*(PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList*/ 00113 }; 00114 00115 #define MAX_MAP_REGISTERS 64 00116 00117 #define TAG_DMA ' AMD' 00118 00119 /* FUNCTIONS *****************************************************************/ 00120 00121 VOID 00122 HalpInitDma(VOID) 00123 { 00124 /* 00125 * Initialize the DMA Operation table 00126 */ 00127 HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel; 00128 HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers; 00129 HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel; 00130 HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters; 00131 HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer; 00132 00133 /* 00134 * Check if Extended DMA is available. We're just going to do a random 00135 * read and write. 00136 */ 00137 00138 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2), 0x2A); 00139 if (READ_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)) == 0x2A) 00140 HalpEisaDma = TRUE; 00141 00142 /* 00143 * Intialize all the global variables and allocate master adapter with 00144 * first map buffers. 00145 */ 00146 00147 InitializeListHead(&HalpDmaAdapterList); 00148 KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE); 00149 00150 HalpMasterAdapter = HalpDmaAllocateMasterAdapter(); 00151 00152 /* 00153 * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's 00154 * used by IoGetDmaAdapter in the kernel. 00155 */ 00156 00157 HalGetDmaAdapter = HalpGetDmaAdapter; 00158 } 00159 00167 PHYSICAL_ADDRESS NTAPI 00168 HalpGetAdapterMaximumPhysicalAddress( 00169 IN PADAPTER_OBJECT AdapterObject) 00170 { 00171 PHYSICAL_ADDRESS HighestAddress; 00172 00173 if (AdapterObject->MasterDevice) 00174 { 00175 if (AdapterObject->Dma64BitAddresses) 00176 { 00177 HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL; 00178 return HighestAddress; 00179 } 00180 else if (AdapterObject->Dma32BitAddresses) 00181 { 00182 HighestAddress.QuadPart = 0xFFFFFFFF; 00183 return HighestAddress; 00184 } 00185 } 00186 00187 HighestAddress.QuadPart = 0xFFFFFF; 00188 return HighestAddress; 00189 } 00190 00203 BOOLEAN NTAPI 00204 HalpGrowMapBuffers( 00205 IN PADAPTER_OBJECT AdapterObject, 00206 IN ULONG SizeOfMapBuffers) 00207 { 00208 PVOID VirtualAddress; 00209 PHYSICAL_ADDRESS PhysicalAddress; 00210 PHYSICAL_ADDRESS HighestAcceptableAddress; 00211 PHYSICAL_ADDRESS LowestAcceptableAddress; 00212 PHYSICAL_ADDRESS BoundryAddressMultiple; 00213 KIRQL OldIrql; 00214 ULONG MapRegisterCount; 00215 00216 /* FIXME: Check if enough map register slots are available. */ 00217 00218 MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers); 00219 00220 /* 00221 * Allocate memory for the new map registers. For 32-bit adapters we use 00222 * two passes in order not to waste scare resource (low memory). 00223 */ 00224 00225 HighestAcceptableAddress = 00226 HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 00227 LowestAcceptableAddress.HighPart = 0; 00228 LowestAcceptableAddress.LowPart = 00229 HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0; 00230 BoundryAddressMultiple.QuadPart = 0; 00231 00232 VirtualAddress = MmAllocateContiguousMemorySpecifyCache( 00233 MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, 00234 HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); 00235 00236 if (VirtualAddress == NULL && LowestAcceptableAddress.LowPart != 0) 00237 { 00238 LowestAcceptableAddress.LowPart = 0; 00239 VirtualAddress = MmAllocateContiguousMemorySpecifyCache( 00240 MapRegisterCount << PAGE_SHIFT, LowestAcceptableAddress, 00241 HighestAcceptableAddress, BoundryAddressMultiple, MmNonCached); 00242 } 00243 00244 if (VirtualAddress == NULL) 00245 return FALSE; 00246 00247 PhysicalAddress = MmGetPhysicalAddress(VirtualAddress); 00248 00249 /* 00250 * All the following must be done with the master adapter lock held 00251 * to prevent corruption. 00252 */ 00253 00254 OldIrql = KfAcquireSpinLock(&AdapterObject->SpinLock); 00255 00256 /* 00257 * Setup map register entries for the buffer allocated. Each entry has 00258 * a virtual and physical address and corresponds to PAGE_SIZE large 00259 * buffer. 00260 */ 00261 00262 if (MapRegisterCount > 0) 00263 { 00264 PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry; 00265 00266 CurrentEntry = AdapterObject->MapRegisterBase + 00267 AdapterObject->NumberOfMapRegisters; 00268 do 00269 { 00270 /* 00271 * Leave one entry free for every non-contiguous memory region 00272 * in the map register bitmap. This ensures that we can search 00273 * using RtlFindClearBits for contiguous map register regions. 00274 * 00275 * Also for non-EISA DMA leave one free entry for every 64Kb 00276 * break, because the DMA controller can handle only coniguous 00277 * 64Kb regions. 00278 */ 00279 00280 if (CurrentEntry != AdapterObject->MapRegisterBase) 00281 { 00282 PreviousEntry = CurrentEntry - 1; 00283 if (PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE == 00284 PhysicalAddress.LowPart) 00285 { 00286 if (!HalpEisaDma) 00287 { 00288 if ((PreviousEntry->PhysicalAddress.LowPart ^ 00289 PhysicalAddress.LowPart) & 0xFFFF0000) 00290 { 00291 CurrentEntry++; 00292 AdapterObject->NumberOfMapRegisters++; 00293 } 00294 } 00295 } 00296 else 00297 { 00298 CurrentEntry++; 00299 AdapterObject->NumberOfMapRegisters++; 00300 } 00301 } 00302 00303 RtlClearBit(AdapterObject->MapRegisters, 00304 CurrentEntry - AdapterObject->MapRegisterBase); 00305 CurrentEntry->VirtualAddress = VirtualAddress; 00306 CurrentEntry->PhysicalAddress = PhysicalAddress; 00307 00308 PhysicalAddress.LowPart += PAGE_SIZE; 00309 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); 00310 00311 CurrentEntry++; 00312 AdapterObject->NumberOfMapRegisters++; 00313 MapRegisterCount--; 00314 } 00315 while (MapRegisterCount != 0); 00316 } 00317 00318 KfReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); 00319 00320 return TRUE; 00321 } 00322 00332 PADAPTER_OBJECT NTAPI 00333 HalpDmaAllocateMasterAdapter(VOID) 00334 { 00335 PADAPTER_OBJECT MasterAdapter; 00336 ULONG Size, SizeOfBitmap; 00337 00338 SizeOfBitmap = MAX_MAP_REGISTERS; 00339 Size = sizeof(ADAPTER_OBJECT); 00340 Size += sizeof(RTL_BITMAP); 00341 Size += (SizeOfBitmap + 7) >> 3; 00342 00343 MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA); 00344 if (MasterAdapter == NULL) 00345 return NULL; 00346 00347 RtlZeroMemory(MasterAdapter, Size); 00348 00349 KeInitializeSpinLock(&MasterAdapter->SpinLock); 00350 InitializeListHead(&MasterAdapter->AdapterQueue); 00351 00352 MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1); 00353 RtlInitializeBitMap( 00354 MasterAdapter->MapRegisters, 00355 (PULONG)(MasterAdapter->MapRegisters + 1), 00356 SizeOfBitmap); 00357 RtlSetAllBits(MasterAdapter->MapRegisters); 00358 MasterAdapter->NumberOfMapRegisters = 0; 00359 MasterAdapter->CommittedMapRegisters = 0; 00360 00361 MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag( 00362 NonPagedPool, 00363 SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY), 00364 TAG_DMA); 00365 if (MasterAdapter->MapRegisterBase == NULL) 00366 { 00367 ExFreePool(MasterAdapter); 00368 return NULL; 00369 } 00370 00371 RtlZeroMemory(MasterAdapter->MapRegisterBase, 00372 SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY)); 00373 if (!HalpGrowMapBuffers(MasterAdapter, 0x10000)) 00374 { 00375 ExFreePool(MasterAdapter); 00376 return NULL; 00377 } 00378 00379 return MasterAdapter; 00380 } 00381 00391 PADAPTER_OBJECT NTAPI 00392 HalpDmaAllocateChildAdapter( 00393 ULONG NumberOfMapRegisters, 00394 PDEVICE_DESCRIPTION DeviceDescription) 00395 { 00396 PADAPTER_OBJECT AdapterObject; 00397 OBJECT_ATTRIBUTES ObjectAttributes; 00398 NTSTATUS Status; 00399 HANDLE Handle; 00400 00401 InitializeObjectAttributes( 00402 &ObjectAttributes, 00403 NULL, 00404 OBJ_KERNEL_HANDLE | OBJ_PERMANENT, 00405 NULL, 00406 NULL); 00407 00408 Status = ObCreateObject( 00409 KernelMode, 00410 IoAdapterObjectType, 00411 &ObjectAttributes, 00412 KernelMode, 00413 NULL, 00414 sizeof(ADAPTER_OBJECT), 00415 0, 00416 0, 00417 (PVOID)&AdapterObject); 00418 if (!NT_SUCCESS(Status)) 00419 return NULL; 00420 00421 Status = ObReferenceObjectByPointer( 00422 AdapterObject, 00423 FILE_READ_DATA | FILE_WRITE_DATA, 00424 IoAdapterObjectType, 00425 KernelMode); 00426 if (!NT_SUCCESS(Status)) 00427 return NULL; 00428 00429 RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT)); 00430 00431 Status = ObInsertObject( 00432 AdapterObject, 00433 NULL, 00434 FILE_READ_DATA | FILE_WRITE_DATA, 00435 0, 00436 NULL, 00437 &Handle); 00438 if (!NT_SUCCESS(Status)) 00439 return NULL; 00440 00441 ZwClose(Handle); 00442 00443 AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version; 00444 AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT); 00445 AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations; 00446 AdapterObject->MapRegistersPerChannel = 1; 00447 AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; 00448 AdapterObject->ChannelNumber = 0xFF; 00449 AdapterObject->MasterAdapter = HalpMasterAdapter; 00450 KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue); 00451 00452 return AdapterObject; 00453 } 00454 00461 BOOLEAN NTAPI 00462 HalpDmaInitializeEisaAdapter( 00463 PADAPTER_OBJECT AdapterObject, 00464 PDEVICE_DESCRIPTION DeviceDescription) 00465 { 00466 UCHAR Controller; 00467 DMA_MODE DmaMode = {{0 }}; 00468 DMA_EXTENDED_MODE ExtendedMode = {{ 0 }}; 00469 PVOID AdapterBaseVa; 00470 00471 Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1; 00472 00473 if (Controller == 1) 00474 AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1); 00475 else 00476 AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2); 00477 00478 AdapterObject->AdapterNumber = Controller; 00479 AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3); 00480 AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel]; 00481 AdapterObject->Width16Bits = FALSE; 00482 AdapterObject->AdapterBaseVa = AdapterBaseVa; 00483 00484 if (HalpEisaDma) 00485 { 00486 ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber; 00487 00488 switch (DeviceDescription->DmaSpeed) 00489 { 00490 case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break; 00491 case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break; 00492 case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break; 00493 case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break; 00494 default: 00495 return FALSE; 00496 } 00497 00498 switch (DeviceDescription->DmaWidth) 00499 { 00500 case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break; 00501 case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break; 00502 case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break; 00503 default: 00504 return FALSE; 00505 } 00506 00507 if (Controller == 1) 00508 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1), 00509 ExtendedMode.Byte); 00510 else 00511 WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2), 00512 ExtendedMode.Byte); 00513 } 00514 else 00515 { 00516 /* 00517 * Validate setup for non-busmaster DMA adapter. Secondary controller 00518 * supports only 16-bit transfers and main controller supports only 00519 * 8-bit transfers. Anything else is invalid. 00520 */ 00521 00522 if (!DeviceDescription->Master) 00523 { 00524 if (Controller == 2 && DeviceDescription->DmaWidth == Width16Bits) 00525 AdapterObject->Width16Bits = TRUE; 00526 else if (Controller != 1 || DeviceDescription->DmaWidth != Width8Bits) 00527 return FALSE; 00528 } 00529 } 00530 00531 DmaMode.Channel = AdapterObject->ChannelNumber; 00532 DmaMode.AutoInitialize = DeviceDescription->AutoInitialize; 00533 00534 /* 00535 * Set the DMA request mode. 00536 * 00537 * For (E)ISA bus master devices just unmask (enable) the DMA channel 00538 * and set it to cascade mode. Otherwise just select the right one 00539 * bases on the passed device description. 00540 */ 00541 00542 if (DeviceDescription->Master) 00543 { 00544 DmaMode.RequestMode = CASCADE_REQUEST_MODE; 00545 if (Controller == 1) 00546 { 00547 /* Set the Request Data */ 00548 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, 00549 DmaMode.Byte); 00550 /* Unmask DMA Channel */ 00551 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask, 00552 AdapterObject->ChannelNumber | DMA_CLEARMASK); 00553 } else { 00554 /* Set the Request Data */ 00555 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, 00556 DmaMode.Byte); 00557 /* Unmask DMA Channel */ 00558 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask, 00559 AdapterObject->ChannelNumber | DMA_CLEARMASK); 00560 } 00561 } 00562 else 00563 { 00564 if (DeviceDescription->DemandMode) 00565 DmaMode.RequestMode = DEMAND_REQUEST_MODE; 00566 else 00567 DmaMode.RequestMode = SINGLE_REQUEST_MODE; 00568 } 00569 00570 AdapterObject->AdapterMode = DmaMode; 00571 00572 return TRUE; 00573 } 00574 00591 PADAPTER_OBJECT NTAPI 00592 HalGetAdapter( 00593 PDEVICE_DESCRIPTION DeviceDescription, 00594 PULONG NumberOfMapRegisters) 00595 { 00596 PADAPTER_OBJECT AdapterObject = NULL; 00597 PADAPTER_OBJECT MasterAdapter; 00598 BOOLEAN EisaAdapter; 00599 ULONG MapRegisters; 00600 ULONG MaximumLength; 00601 00602 /* Validate parameters in device description */ 00603 if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) 00604 return NULL; 00605 00606 /* 00607 * See if we're going to use ISA/EISA DMA adapter. These adapters are 00608 * special since they're reused. 00609 * 00610 * Also note that we check for channel number since there are only 8 DMA 00611 * channels on ISA, so any request above this requires new adapter. 00612 */ 00613 00614 if (DeviceDescription->InterfaceType == Isa || !DeviceDescription->Master) 00615 { 00616 if (DeviceDescription->InterfaceType == Isa && 00617 DeviceDescription->DmaChannel >= 8) 00618 EisaAdapter = FALSE; 00619 else 00620 EisaAdapter = TRUE; 00621 } 00622 else 00623 { 00624 EisaAdapter = FALSE; 00625 } 00626 00627 /* 00628 * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used 00629 * for cascading the controllers and it's not available for software use. 00630 */ 00631 00632 if (EisaAdapter && DeviceDescription->DmaChannel == 4) 00633 return NULL; 00634 00635 /* 00636 * Calculate the number of map registers. 00637 * 00638 * - For EISA and PCI scatter/gather no map registers are needed. 00639 * - For ISA slave scatter/gather one map register is needed. 00640 * - For all other cases the number of map registers depends on 00641 * DeviceDescription->MaximumLength. 00642 */ 00643 00644 MaximumLength = DeviceDescription->MaximumLength & MAXLONG; 00645 if (DeviceDescription->ScatterGather && 00646 (DeviceDescription->InterfaceType == Eisa || 00647 DeviceDescription->InterfaceType == PCIBus)) 00648 { 00649 MapRegisters = 0; 00650 } 00651 else if (DeviceDescription->ScatterGather && 00652 !DeviceDescription->Master) 00653 { 00654 MapRegisters = 1; 00655 } 00656 else 00657 { 00658 /* 00659 * In the equation below the additional map register added by 00660 * the "+1" accounts for the case when a transfer does not start 00661 * at a page-aligned address. 00662 */ 00663 MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1; 00664 if (MapRegisters > 16) 00665 MapRegisters = 16; 00666 } 00667 00668 /* 00669 * Acquire the DMA lock that is used to protect adapter lists and 00670 * EISA adapter array. 00671 */ 00672 00673 KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, 00674 FALSE, NULL); 00675 00676 /* 00677 * Now we must get ahold of the adapter object. For first eight ISA/EISA 00678 * channels there are static adapter objects that are reused and updated 00679 * on succesive HalGetAdapter calls. In other cases a new adapter object 00680 * is always created and it's to the DMA adapter list (HalpDmaAdapterList). 00681 */ 00682 00683 if (EisaAdapter) 00684 { 00685 AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel]; 00686 if (AdapterObject != NULL) 00687 { 00688 if (AdapterObject->NeedsMapRegisters && 00689 MapRegisters > AdapterObject->MapRegistersPerChannel) 00690 AdapterObject->MapRegistersPerChannel = MapRegisters; 00691 } 00692 } 00693 00694 if (AdapterObject == NULL) 00695 { 00696 AdapterObject = HalpDmaAllocateChildAdapter( 00697 MapRegisters, DeviceDescription); 00698 if (AdapterObject == NULL) 00699 { 00700 KeSetEvent(&HalpDmaLock, 0, 0); 00701 return NULL; 00702 } 00703 00704 if (EisaAdapter) 00705 { 00706 HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject; 00707 } 00708 00709 if (MapRegisters > 0) 00710 { 00711 AdapterObject->NeedsMapRegisters = TRUE; 00712 MasterAdapter = HalpMasterAdapter; 00713 AdapterObject->MapRegistersPerChannel = MapRegisters; 00714 00715 /* 00716 * FIXME: Verify that the following makes sense. Actually 00717 * MasterAdapter->NumberOfMapRegisters contains even the number 00718 * of gaps, so this will not work correctly all the time. It 00719 * doesn't matter much since it's only optimization to avoid 00720 * queuing work items in HalAllocateAdapterChannel. 00721 */ 00722 00723 MasterAdapter->CommittedMapRegisters += MapRegisters; 00724 if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters) 00725 HalpGrowMapBuffers(MasterAdapter, 0x10000); 00726 } 00727 else 00728 { 00729 AdapterObject->NeedsMapRegisters = FALSE; 00730 if (DeviceDescription->Master) 00731 AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1; 00732 else 00733 AdapterObject->MapRegistersPerChannel = 1; 00734 } 00735 } 00736 00737 if (!EisaAdapter) 00738 InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList); 00739 00740 /* 00741 * Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will 00742 * no longer be touched, so we don't need it. 00743 */ 00744 00745 KeSetEvent(&HalpDmaLock, 0, 0); 00746 00747 /* 00748 * Setup the values in the adapter object that are common for all 00749 * types of buses. 00750 */ 00751 00752 if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1) 00753 AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount; 00754 else 00755 AdapterObject->IgnoreCount = 0; 00756 00757 AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; 00758 AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses; 00759 AdapterObject->ScatterGather = DeviceDescription->ScatterGather; 00760 AdapterObject->MasterDevice = DeviceDescription->Master; 00761 *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel; 00762 00763 /* 00764 * For non-(E)ISA adapters we have already done all the work. On the 00765 * other hand for (E)ISA adapters we must still setup the DMA modes 00766 * and prepare the controller. 00767 */ 00768 00769 if (EisaAdapter) 00770 { 00771 if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription)) 00772 { 00773 ObDereferenceObject(AdapterObject); 00774 return NULL; 00775 } 00776 } 00777 00778 return AdapterObject; 00779 } 00780 00790 PDMA_ADAPTER NTAPI 00791 HalpGetDmaAdapter( 00792 IN PVOID Context, 00793 IN PDEVICE_DESCRIPTION DeviceDescription, 00794 OUT PULONG NumberOfMapRegisters) 00795 { 00796 return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader; 00797 } 00798 00808 VOID NTAPI 00809 HalPutDmaAdapter( 00810 PADAPTER_OBJECT AdapterObject) 00811 { 00812 if (AdapterObject->ChannelNumber == 0xFF) 00813 { 00814 KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, 00815 FALSE, NULL); 00816 RemoveEntryList(&AdapterObject->AdapterList); 00817 KeSetEvent(&HalpDmaLock, 0, 0); 00818 } 00819 00820 ObDereferenceObject(AdapterObject); 00821 } 00822 00849 PVOID NTAPI 00850 HalAllocateCommonBuffer( 00851 PADAPTER_OBJECT AdapterObject, 00852 ULONG Length, 00853 PPHYSICAL_ADDRESS LogicalAddress, 00854 BOOLEAN CacheEnabled) 00855 { 00856 PHYSICAL_ADDRESS LowestAcceptableAddress; 00857 PHYSICAL_ADDRESS HighestAcceptableAddress; 00858 PHYSICAL_ADDRESS BoundryAddressMultiple; 00859 PVOID VirtualAddress; 00860 00861 LowestAcceptableAddress.QuadPart = 0; 00862 HighestAcceptableAddress = 00863 HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 00864 BoundryAddressMultiple.QuadPart = 0; 00865 00866 /* 00867 * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For 00868 * slave DMA devices the 64Kb boundary mustn't be crossed since the 00869 * controller wouldn't be able to handle it. 00870 */ 00871 00872 if (AdapterObject->MasterDevice) 00873 BoundryAddressMultiple.HighPart = 1; 00874 else 00875 BoundryAddressMultiple.LowPart = 0x10000; 00876 00877 VirtualAddress = MmAllocateContiguousMemorySpecifyCache( 00878 Length, LowestAcceptableAddress, HighestAcceptableAddress, 00879 BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached); 00880 if (VirtualAddress == NULL) 00881 return NULL; 00882 00883 *LogicalAddress = MmGetPhysicalAddress(VirtualAddress); 00884 00885 return VirtualAddress; 00886 } 00887 00898 VOID NTAPI 00899 HalFreeCommonBuffer( 00900 PADAPTER_OBJECT AdapterObject, 00901 ULONG Length, 00902 PHYSICAL_ADDRESS LogicalAddress, 00903 PVOID VirtualAddress, 00904 BOOLEAN CacheEnabled) 00905 { 00906 MmFreeContiguousMemory(VirtualAddress); 00907 } 00908 00918 ULONG NTAPI 00919 HalpDmaGetDmaAlignment( 00920 PADAPTER_OBJECT AdapterObject) 00921 { 00922 return 1; 00923 } 00924 00925 /* 00926 * @name HalReadDmaCounter 00927 * 00928 * Read DMA operation progress counter. 00929 * 00930 * @implemented 00931 */ 00932 00933 ULONG NTAPI 00934 HalReadDmaCounter( 00935 PADAPTER_OBJECT AdapterObject) 00936 { 00937 KIRQL OldIrql; 00938 ULONG Count, OldCount; 00939 00940 ASSERT(!AdapterObject->MasterDevice); 00941 00942 /* 00943 * Acquire the master adapter lock since we're going to mess with the 00944 * system DMA controller registers and we really don't want anyone 00945 * to do the same at the same time. 00946 */ 00947 00948 KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); 00949 00950 /* Send the request to the specific controller. */ 00951 if (AdapterObject->AdapterNumber == 1) 00952 { 00953 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 00954 00955 Count = 0xffff00; 00956 do 00957 { 00958 OldCount = Count; 00959 /* Send Reset */ 00960 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); 00961 /* Read Count */ 00962 Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount 00963 [AdapterObject->ChannelNumber].DmaBaseCount); 00964 Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount 00965 [AdapterObject->ChannelNumber].DmaBaseCount) << 8; 00966 } 00967 while (0xffff00 & (OldCount ^ Count)); 00968 } 00969 else 00970 { 00971 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 00972 00973 Count = 0xffff00; 00974 do 00975 { 00976 OldCount = Count; 00977 /* Send Reset */ 00978 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); 00979 /* Read Count */ 00980 Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount 00981 [AdapterObject->ChannelNumber].DmaBaseCount); 00982 Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount 00983 [AdapterObject->ChannelNumber].DmaBaseCount) << 8; 00984 } 00985 while (0xffff00 & (OldCount ^ Count)); 00986 } 00987 00988 KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); 00989 00990 Count++; 00991 Count &= 0xffff; 00992 if (AdapterObject->Width16Bits) 00993 Count *= 2; 00994 00995 return Count; 00996 } 00997 01005 VOID NTAPI 01006 HalpGrowMapBufferWorker(PVOID DeferredContext) 01007 { 01008 PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext; 01009 KIRQL OldIrql; 01010 BOOLEAN Succeeded; 01011 01012 /* 01013 * Try to allocate new map registers for the adapter. 01014 * 01015 * NOTE: The NT implementation actually tries to allocate more map 01016 * registers than needed as an optimization. 01017 */ 01018 01019 KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, 01020 FALSE, NULL); 01021 Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter, 01022 WorkItem->NumberOfMapRegisters); 01023 KeSetEvent(&HalpDmaLock, 0, 0); 01024 01025 if (Succeeded) 01026 { 01027 /* 01028 * Flush the adapter queue now that new map registers are ready. The 01029 * easiest way to do that is to call IoFreeMapRegisters to not free 01030 * any registers. Note that we use the magic (PVOID)2 map register 01031 * base to bypass the parameter checking. 01032 */ 01033 01034 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 01035 IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0); 01036 KeLowerIrql(OldIrql); 01037 } 01038 01039 ExFreePool(WorkItem); 01040 } 01041 01067 NTSTATUS NTAPI 01068 HalAllocateAdapterChannel( 01069 PADAPTER_OBJECT AdapterObject, 01070 PWAIT_CONTEXT_BLOCK WaitContextBlock, 01071 ULONG NumberOfMapRegisters, 01072 PDRIVER_CONTROL ExecutionRoutine) 01073 { 01074 PADAPTER_OBJECT MasterAdapter; 01075 PGROW_WORK_ITEM WorkItem; 01076 ULONG Index = MAXULONG; 01077 ULONG Result; 01078 KIRQL OldIrql; 01079 01080 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01081 01082 /* Set up the wait context block in case we can't run right away. */ 01083 WaitContextBlock->DeviceRoutine = ExecutionRoutine; 01084 WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters; 01085 01086 /* Returns true if queued, else returns false and sets the queue to busy */ 01087 if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, &WaitContextBlock->WaitQueueEntry)) 01088 return STATUS_SUCCESS; 01089 01090 MasterAdapter = AdapterObject->MasterAdapter; 01091 01092 AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; 01093 AdapterObject->CurrentWcb = WaitContextBlock; 01094 01095 if (NumberOfMapRegisters && AdapterObject->NeedsMapRegisters) 01096 { 01097 if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) 01098 { 01099 AdapterObject->NumberOfMapRegisters = 0; 01100 IoFreeAdapterChannel(AdapterObject); 01101 return STATUS_INSUFFICIENT_RESOURCES; 01102 } 01103 01104 /* 01105 * Get the map registers. This is partly complicated by the fact 01106 * that new map registers can only be allocated at PASSIVE_LEVEL 01107 * and we're currently at DISPATCH_LEVEL. The following code has 01108 * two code paths: 01109 * 01110 * - If there is no adapter queued for map register allocation, 01111 * try to see if enough contiguous map registers are present. 01112 * In case they're we can just get them and proceed further. 01113 * 01114 * - If some adapter is already present in the queue we must 01115 * respect the order of adapters asking for map registers and 01116 * so the fast case described above can't take place. 01117 * This case is also entered if not enough coniguous map 01118 * registers are present. 01119 * 01120 * A work queue item is allocated and queued, the adapter is 01121 * also queued into the master adapter queue. The worker 01122 * routine does the job of allocating the map registers at 01123 * PASSIVE_LEVEL and calling the ExecutionRoutine. 01124 */ 01125 01126 OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); 01127 01128 if (IsListEmpty(&MasterAdapter->AdapterQueue)) 01129 { 01130 Index = RtlFindClearBitsAndSet( 01131 MasterAdapter->MapRegisters, NumberOfMapRegisters, 0); 01132 if (Index != MAXULONG) 01133 { 01134 AdapterObject->MapRegisterBase = 01135 MasterAdapter->MapRegisterBase + Index; 01136 if (!AdapterObject->ScatterGather) 01137 { 01138 AdapterObject->MapRegisterBase = 01139 (PROS_MAP_REGISTER_ENTRY)( 01140 (ULONG_PTR)AdapterObject->MapRegisterBase | 01141 MAP_BASE_SW_SG); 01142 } 01143 } 01144 } 01145 01146 if (Index == MAXULONG) 01147 { 01148 WorkItem = ExAllocatePoolWithTag( 01149 NonPagedPool, sizeof(GROW_WORK_ITEM), TAG_DMA); 01150 if (WorkItem == NULL) 01151 { 01152 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01153 AdapterObject->NumberOfMapRegisters = 0; 01154 IoFreeAdapterChannel(AdapterObject); 01155 return STATUS_INSUFFICIENT_RESOURCES; 01156 } 01157 01158 InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); 01159 01160 ExInitializeWorkItem( 01161 &WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem); 01162 WorkItem->AdapterObject = AdapterObject; 01163 WorkItem->NumberOfMapRegisters = NumberOfMapRegisters; 01164 01165 ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); 01166 01167 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01168 01169 return STATUS_SUCCESS; 01170 } 01171 01172 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01173 } 01174 else 01175 { 01176 AdapterObject->MapRegisterBase = NULL; 01177 AdapterObject->NumberOfMapRegisters = 0; 01178 } 01179 01180 AdapterObject->CurrentWcb = WaitContextBlock; 01181 01182 Result = ExecutionRoutine( 01183 WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, 01184 AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext); 01185 01186 /* 01187 * Possible return values: 01188 * 01189 * - KeepObject 01190 * Don't free any resources, the ADAPTER_OBJECT is still in use and 01191 * the caller will call IoFreeAdapterChannel later. 01192 * 01193 * - DeallocateObject 01194 * Deallocate the map registers and release the ADAPTER_OBJECT, so 01195 * someone else can use it. 01196 * 01197 * - DeallocateObjectKeepRegisters 01198 * Release the ADAPTER_OBJECT, but hang on to the map registers. The 01199 * client will later call IoFreeMapRegisters. 01200 * 01201 * NOTE: 01202 * IoFreeAdapterChannel runs the queue, so it must be called unless 01203 * the adapter object is not to be freed. 01204 */ 01205 01206 if (Result == DeallocateObject) 01207 { 01208 IoFreeAdapterChannel(AdapterObject); 01209 } 01210 else if (Result == DeallocateObjectKeepRegisters) 01211 { 01212 AdapterObject->NumberOfMapRegisters = 0; 01213 IoFreeAdapterChannel(AdapterObject); 01214 } 01215 01216 return STATUS_SUCCESS; 01217 } 01218 01238 VOID NTAPI 01239 IoFreeAdapterChannel( 01240 PADAPTER_OBJECT AdapterObject) 01241 { 01242 PADAPTER_OBJECT MasterAdapter; 01243 PKDEVICE_QUEUE_ENTRY DeviceQueueEntry; 01244 PWAIT_CONTEXT_BLOCK WaitContextBlock; 01245 ULONG Index = MAXULONG; 01246 ULONG Result; 01247 KIRQL OldIrql; 01248 01249 MasterAdapter = AdapterObject->MasterAdapter; 01250 01251 for (;;) 01252 { 01253 /* 01254 * To keep map registers, call here with AdapterObject-> 01255 * NumberOfMapRegisters set to zero. This trick is used in 01256 * HalAllocateAdapterChannel for example. 01257 */ 01258 if (AdapterObject->NumberOfMapRegisters) 01259 { 01260 IoFreeMapRegisters( 01261 AdapterObject, 01262 AdapterObject->MapRegisterBase, 01263 AdapterObject->NumberOfMapRegisters); 01264 } 01265 01266 DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue); 01267 if (DeviceQueueEntry == NULL) 01268 { 01269 break; 01270 } 01271 01272 WaitContextBlock = CONTAINING_RECORD( 01273 DeviceQueueEntry, 01274 WAIT_CONTEXT_BLOCK, 01275 WaitQueueEntry); 01276 01277 AdapterObject->CurrentWcb = WaitContextBlock; 01278 AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters; 01279 01280 if (WaitContextBlock->NumberOfMapRegisters && 01281 AdapterObject->MasterAdapter) 01282 { 01283 OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); 01284 01285 if (IsListEmpty(&MasterAdapter->AdapterQueue)) 01286 { 01287 Index = RtlFindClearBitsAndSet( 01288 MasterAdapter->MapRegisters, 01289 WaitContextBlock->NumberOfMapRegisters, 0); 01290 if (Index != MAXULONG) 01291 { 01292 AdapterObject->MapRegisterBase = 01293 MasterAdapter->MapRegisterBase + Index; 01294 if (!AdapterObject->ScatterGather) 01295 { 01296 AdapterObject->MapRegisterBase = 01297 (PROS_MAP_REGISTER_ENTRY)( 01298 (ULONG_PTR)AdapterObject->MapRegisterBase | 01299 MAP_BASE_SW_SG); 01300 } 01301 } 01302 } 01303 01304 if (Index == MAXULONG) 01305 { 01306 InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); 01307 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01308 break; 01309 } 01310 01311 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01312 } 01313 else 01314 { 01315 AdapterObject->MapRegisterBase = NULL; 01316 AdapterObject->NumberOfMapRegisters = 0; 01317 } 01318 01319 /* Call the adapter control routine. */ 01320 Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)( 01321 WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp, 01322 AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext); 01323 01324 switch (Result) 01325 { 01326 case KeepObject: 01327 /* 01328 * We're done until the caller manually calls IoFreeAdapterChannel 01329 * or IoFreeMapRegisters. 01330 */ 01331 return; 01332 01333 case DeallocateObjectKeepRegisters: 01334 /* 01335 * Hide the map registers so they aren't deallocated next time 01336 * around. 01337 */ 01338 AdapterObject->NumberOfMapRegisters = 0; 01339 break; 01340 01341 default: 01342 break; 01343 } 01344 } 01345 } 01346 01362 VOID NTAPI 01363 IoFreeMapRegisters( 01364 IN PADAPTER_OBJECT AdapterObject, 01365 IN PVOID MapRegisterBase, 01366 IN ULONG NumberOfMapRegisters) 01367 { 01368 PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; 01369 PLIST_ENTRY ListEntry; 01370 KIRQL OldIrql; 01371 ULONG Index; 01372 ULONG Result; 01373 01374 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01375 01376 if (MasterAdapter == NULL || MapRegisterBase == NULL) 01377 return; 01378 01379 OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); 01380 01381 if (NumberOfMapRegisters != 0) 01382 { 01383 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 01384 01385 RealMapRegisterBase = 01386 (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 01387 RtlClearBits(MasterAdapter->MapRegisters, 01388 RealMapRegisterBase - MasterAdapter->MapRegisterBase, 01389 NumberOfMapRegisters); 01390 } 01391 01392 /* 01393 * Now that we freed few map registers it's time to look at the master 01394 * adapter queue and see if there is someone waiting for map registers. 01395 */ 01396 01397 while (!IsListEmpty(&MasterAdapter->AdapterQueue)) 01398 { 01399 ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue); 01400 AdapterObject = CONTAINING_RECORD( 01401 ListEntry, struct _ADAPTER_OBJECT, AdapterQueue); 01402 01403 Index = RtlFindClearBitsAndSet( 01404 MasterAdapter->MapRegisters, 01405 AdapterObject->NumberOfMapRegisters, 01406 MasterAdapter->NumberOfMapRegisters); 01407 if (Index == MAXULONG) 01408 { 01409 InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry); 01410 break; 01411 } 01412 01413 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01414 01415 AdapterObject->MapRegisterBase = 01416 MasterAdapter->MapRegisterBase + Index; 01417 if (!AdapterObject->ScatterGather) 01418 { 01419 AdapterObject->MapRegisterBase = 01420 (PROS_MAP_REGISTER_ENTRY)( 01421 (ULONG_PTR)AdapterObject->MapRegisterBase | 01422 MAP_BASE_SW_SG); 01423 } 01424 01425 Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)( 01426 AdapterObject->CurrentWcb->DeviceObject, 01427 AdapterObject->CurrentWcb->CurrentIrp, 01428 AdapterObject->MapRegisterBase, 01429 AdapterObject->CurrentWcb->DeviceContext); 01430 01431 switch (Result) 01432 { 01433 case DeallocateObjectKeepRegisters: 01434 AdapterObject->NumberOfMapRegisters = 0; 01435 /* fall through */ 01436 01437 case DeallocateObject: 01438 if (AdapterObject->NumberOfMapRegisters) 01439 { 01440 OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); 01441 RtlClearBits(MasterAdapter->MapRegisters, 01442 AdapterObject->MapRegisterBase - 01443 MasterAdapter->MapRegisterBase, 01444 AdapterObject->NumberOfMapRegisters); 01445 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01446 } 01447 IoFreeAdapterChannel(AdapterObject); 01448 break; 01449 01450 default: 01451 break; 01452 } 01453 01454 OldIrql = KfAcquireSpinLock(&MasterAdapter->SpinLock); 01455 } 01456 01457 KfReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 01458 } 01459 01468 VOID NTAPI 01469 HalpCopyBufferMap( 01470 PMDL Mdl, 01471 PROS_MAP_REGISTER_ENTRY MapRegisterBase, 01472 PVOID CurrentVa, 01473 ULONG Length, 01474 BOOLEAN WriteToDevice) 01475 { 01476 ULONG CurrentLength; 01477 ULONG_PTR CurrentAddress; 01478 ULONG ByteOffset; 01479 PVOID VirtualAddress; 01480 01481 VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority); 01482 if (VirtualAddress == NULL) 01483 { 01484 /* 01485 * NOTE: On real NT a mechanism with reserved pages is implemented 01486 * to handle this case in a slow, but graceful non-fatal way. 01487 */ 01488 KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); 01489 } 01490 01491 CurrentAddress = (ULONG_PTR)VirtualAddress + 01492 (ULONG_PTR)CurrentVa - 01493 (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); 01494 01495 while (Length > 0) 01496 { 01497 ByteOffset = BYTE_OFFSET(CurrentAddress); 01498 CurrentLength = PAGE_SIZE - ByteOffset; 01499 if (CurrentLength > Length) 01500 CurrentLength = Length; 01501 01502 if (WriteToDevice) 01503 { 01504 RtlCopyMemory( 01505 (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), 01506 (PVOID)CurrentAddress, 01507 CurrentLength); 01508 } 01509 else 01510 { 01511 RtlCopyMemory( 01512 (PVOID)CurrentAddress, 01513 (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), 01514 CurrentLength); 01515 } 01516 01517 Length -= CurrentLength; 01518 CurrentAddress += CurrentLength; 01519 MapRegisterBase++; 01520 } 01521 } 01522 01555 BOOLEAN NTAPI 01556 IoFlushAdapterBuffers( 01557 PADAPTER_OBJECT AdapterObject, 01558 PMDL Mdl, 01559 PVOID MapRegisterBase, 01560 PVOID CurrentVa, 01561 ULONG Length, 01562 BOOLEAN WriteToDevice) 01563 { 01564 BOOLEAN SlaveDma = FALSE; 01565 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 01566 PHYSICAL_ADDRESS HighestAcceptableAddress; 01567 PHYSICAL_ADDRESS PhysicalAddress; 01568 PPFN_NUMBER MdlPagesPtr; 01569 01570 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 01571 01572 if (AdapterObject != NULL && !AdapterObject->MasterDevice) 01573 { 01574 /* Mask out (disable) the DMA channel. */ 01575 if (AdapterObject->AdapterNumber == 1) 01576 { 01577 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 01578 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, 01579 AdapterObject->ChannelNumber | DMA_SETMASK); 01580 } 01581 else 01582 { 01583 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 01584 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, 01585 AdapterObject->ChannelNumber | DMA_SETMASK); 01586 } 01587 SlaveDma = TRUE; 01588 } 01589 01590 /* This can happen if the device supports hardware scatter/gather. */ 01591 if (MapRegisterBase == NULL) 01592 return TRUE; 01593 01594 RealMapRegisterBase = 01595 (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 01596 01597 if (!WriteToDevice) 01598 { 01599 if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) 01600 { 01601 if (RealMapRegisterBase->Counter != MAXULONG) 01602 { 01603 if (SlaveDma && !AdapterObject->IgnoreCount) 01604 Length -= HalReadDmaCounter(AdapterObject); 01605 HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE); 01606 } 01607 } 01608 else 01609 { 01610 MdlPagesPtr = MmGetMdlPfnArray(Mdl); 01611 MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; 01612 01613 PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; 01614 PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa); 01615 01616 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 01617 if (PhysicalAddress.QuadPart + Length > 01618 HighestAcceptableAddress.QuadPart) 01619 { 01620 HalpCopyBufferMap(Mdl, RealMapRegisterBase, CurrentVa, Length, FALSE); 01621 } 01622 } 01623 } 01624 01625 RealMapRegisterBase->Counter = 0; 01626 01627 return TRUE; 01628 } 01629 01662 PHYSICAL_ADDRESS NTAPI 01663 IoMapTransfer( 01664 IN PADAPTER_OBJECT AdapterObject, 01665 IN PMDL Mdl, 01666 IN PVOID MapRegisterBase, 01667 IN PVOID CurrentVa, 01668 IN OUT PULONG Length, 01669 IN BOOLEAN WriteToDevice) 01670 { 01671 PPFN_NUMBER MdlPagesPtr; 01672 PFN_NUMBER MdlPage1, MdlPage2; 01673 ULONG ByteOffset; 01674 ULONG TransferOffset; 01675 ULONG TransferLength; 01676 BOOLEAN UseMapRegisters; 01677 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 01678 PHYSICAL_ADDRESS PhysicalAddress; 01679 PHYSICAL_ADDRESS HighestAcceptableAddress; 01680 ULONG Counter; 01681 DMA_MODE AdapterMode; 01682 KIRQL OldIrql; 01683 01684 /* 01685 * Precalculate some values that are used in all cases. 01686 * 01687 * ByteOffset is offset inside the page at which the transfer starts. 01688 * MdlPagesPtr is pointer inside the MDL page chain at the page where the 01689 * transfer start. 01690 * PhysicalAddress is physical address corresponding to the transfer 01691 * start page and offset. 01692 * TransferLength is the inital length of the transfer, which is reminder 01693 * of the first page. The actual value is calculated below. 01694 * 01695 * Note that all the variables can change during the processing which 01696 * takes place below. These are just initial values. 01697 */ 01698 01699 ByteOffset = BYTE_OFFSET(CurrentVa); 01700 01701 MdlPagesPtr = MmGetMdlPfnArray(Mdl); 01702 MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; 01703 01704 PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; 01705 PhysicalAddress.QuadPart += ByteOffset; 01706 01707 TransferLength = PAGE_SIZE - ByteOffset; 01708 01709 /* 01710 * Special case for bus master adapters with S/G support. We can directly 01711 * use the buffer specified by the MDL, so not much work has to be done. 01712 * 01713 * Just return the passed VA's corresponding physical address and update 01714 * length to the number of physically contiguous bytes found. Also 01715 * pages crossing the 4Gb boundary aren't considered physically contiguous. 01716 */ 01717 01718 if (MapRegisterBase == NULL) 01719 { 01720 while (TransferLength < *Length) 01721 { 01722 MdlPage1 = *MdlPagesPtr; 01723 MdlPage2 = *(MdlPagesPtr + 1); 01724 if (MdlPage1 + 1 != MdlPage2) 01725 break; 01726 if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) 01727 break; 01728 TransferLength += PAGE_SIZE; 01729 MdlPagesPtr++; 01730 } 01731 01732 if (TransferLength < *Length) 01733 *Length = TransferLength; 01734 01735 return PhysicalAddress; 01736 } 01737 01738 /* 01739 * The code below applies to slave DMA adapters and bus master adapters 01740 * without hardward S/G support. 01741 */ 01742 01743 RealMapRegisterBase = 01744 (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 01745 01746 /* 01747 * Try to calculate the size of the transfer. We can only transfer 01748 * pages that are physically contiguous and that don't cross the 01749 * 64Kb boundary (this limitation applies only for ISA controllers). 01750 */ 01751 01752 while (TransferLength < *Length) 01753 { 01754 MdlPage1 = *MdlPagesPtr; 01755 MdlPage2 = *(MdlPagesPtr + 1); 01756 if (MdlPage1 + 1 != MdlPage2) 01757 break; 01758 if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) 01759 break; 01760 TransferLength += PAGE_SIZE; 01761 MdlPagesPtr++; 01762 } 01763 01764 if (TransferLength > *Length) 01765 TransferLength = *Length; 01766 01767 /* 01768 * If we're about to simulate software S/G and not all the pages are 01769 * physically contiguous then we must use the map registers to store 01770 * the data and allow the whole transfer to proceed at once. 01771 */ 01772 01773 if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG && 01774 TransferLength < *Length) 01775 { 01776 UseMapRegisters = TRUE; 01777 PhysicalAddress = RealMapRegisterBase->PhysicalAddress; 01778 PhysicalAddress.QuadPart += ByteOffset; 01779 TransferLength = *Length; 01780 RealMapRegisterBase->Counter = MAXULONG; 01781 Counter = 0; 01782 } 01783 else 01784 { 01785 /* 01786 * This is ordinary DMA transfer, so just update the progress 01787 * counters. These are used by IoFlushAdapterBuffers to track 01788 * the transfer progress. 01789 */ 01790 01791 UseMapRegisters = FALSE; 01792 Counter = RealMapRegisterBase->Counter; 01793 RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength); 01794 01795 /* 01796 * Check if the buffer doesn't exceed the highest physical address 01797 * limit of the device. In that case we must use the map registers to 01798 * store the data. 01799 */ 01800 01801 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 01802 if (PhysicalAddress.QuadPart + TransferLength > 01803 HighestAcceptableAddress.QuadPart) 01804 { 01805 UseMapRegisters = TRUE; 01806 PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress; 01807 PhysicalAddress.QuadPart += ByteOffset; 01808 if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) 01809 { 01810 RealMapRegisterBase->Counter = MAXULONG; 01811 Counter = 0; 01812 } 01813 } 01814 } 01815 01816 /* 01817 * If we decided to use the map registers (see above) and we're about 01818 * to transfer data to the device then copy the buffers into the map 01819 * register memory. 01820 */ 01821 01822 if (UseMapRegisters && WriteToDevice) 01823 { 01824 HalpCopyBufferMap(Mdl, RealMapRegisterBase + Counter, 01825 CurrentVa, TransferLength, WriteToDevice); 01826 } 01827 01828 /* 01829 * Return the length of transfer that actually takes place. 01830 */ 01831 01832 *Length = TransferLength; 01833 01834 /* 01835 * If we're doing slave (system) DMA then program the (E)ISA controller 01836 * to actually start the transfer. 01837 */ 01838 01839 if (AdapterObject != NULL && !AdapterObject->MasterDevice) 01840 { 01841 AdapterMode = AdapterObject->AdapterMode; 01842 01843 if (WriteToDevice) 01844 { 01845 AdapterMode.TransferType = WRITE_TRANSFER; 01846 } 01847 else 01848 { 01849 AdapterMode.TransferType = READ_TRANSFER; 01850 if (AdapterObject->IgnoreCount) 01851 { 01852 RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + 01853 ByteOffset, TransferLength); 01854 } 01855 } 01856 01857 TransferOffset = PhysicalAddress.LowPart & 0xFFFF; 01858 if (AdapterObject->Width16Bits) 01859 { 01860 TransferLength >>= 1; 01861 TransferOffset >>= 1; 01862 } 01863 01864 OldIrql = KfAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock); 01865 01866 if (AdapterObject->AdapterNumber == 1) 01867 { 01868 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 01869 01870 /* Reset Register */ 01871 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); 01872 /* Set the Mode */ 01873 WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte); 01874 /* Set the Offset Register */ 01875 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 01876 (UCHAR)(TransferOffset)); 01877 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 01878 (UCHAR)(TransferOffset >> 8)); 01879 /* Set the Page Register */ 01880 WRITE_PORT_UCHAR(AdapterObject->PagePort + 01881 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), 01882 (UCHAR)(PhysicalAddress.LowPart >> 16)); 01883 if (HalpEisaDma) 01884 { 01885 WRITE_PORT_UCHAR(AdapterObject->PagePort + 01886 FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 01887 0); 01888 } 01889 /* Set the Length */ 01890 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 01891 (UCHAR)(TransferLength - 1)); 01892 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 01893 (UCHAR)((TransferLength - 1) >> 8)); 01894 /* Unmask the Channel */ 01895 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, 01896 AdapterObject->ChannelNumber | DMA_CLEARMASK); 01897 } 01898 else 01899 { 01900 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 01901 01902 /* Reset Register */ 01903 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); 01904 /* Set the Mode */ 01905 WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte); 01906 /* Set the Offset Register */ 01907 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 01908 (UCHAR)(TransferOffset)); 01909 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 01910 (UCHAR)(TransferOffset >> 8)); 01911 /* Set the Page Register */ 01912 WRITE_PORT_UCHAR(AdapterObject->PagePort + 01913 FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), 01914 (UCHAR)(PhysicalAddress.u.LowPart >> 16)); 01915 if (HalpEisaDma) 01916 { 01917 WRITE_PORT_UCHAR(AdapterObject->PagePort + 01918 FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 01919 0); 01920 } 01921 /* Set the Length */ 01922 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 01923 (UCHAR)(TransferLength - 1)); 01924 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 01925 (UCHAR)((TransferLength - 1) >> 8)); 01926 /* Unmask the Channel */ 01927 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, 01928 AdapterObject->ChannelNumber | DMA_CLEARMASK); 01929 } 01930 01931 KfReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); 01932 } 01933 01934 /* 01935 * Return physical address of the buffer with data that is used for the 01936 * transfer. It can either point inside the Mdl that was passed by the 01937 * caller or into the map registers if the Mdl buffer can't be used 01938 * directly. 01939 */ 01940 01941 return PhysicalAddress; 01942 } 01943 01949 BOOLEAN 01950 NTAPI 01951 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject, 01952 IN ULONG Length, 01953 IN PHYSICAL_ADDRESS LogicalAddress, 01954 IN PVOID VirtualAddress) 01955 { 01956 /* Function always returns true */ 01957 return TRUE; 01958 } 01959 01960 /* 01961 * @implemented 01962 */ 01963 PVOID 01964 NTAPI 01965 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject, 01966 IN OUT PULONG NumberOfMapRegisters) 01967 { 01968 PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; 01969 ULONG MapRegisterNumber; 01970 01971 /* Check if it needs map registers */ 01972 if (AdapterObject->NeedsMapRegisters) 01973 { 01974 /* Check if we have enough */ 01975 if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) 01976 { 01977 /* We don't, fail */ 01978 AdapterObject->NumberOfMapRegisters = 0; 01979 return NULL; 01980 } 01981 01982 /* Try to find free map registers */ 01983 MapRegisterNumber = MAXULONG; 01984 MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, 01985 *NumberOfMapRegisters, 01986 0); 01987 01988 /* Check if nothing was found */ 01989 if (MapRegisterNumber == MAXULONG) 01990 { 01991 /* No free registers found, so use the base registers */ 01992 RtlSetBits(MasterAdapter->MapRegisters, 01993 0, 01994 *NumberOfMapRegisters); 01995 MapRegisterNumber = 0; 01996 } 01997 01998 /* Calculate the new base */ 01999 AdapterObject->MapRegisterBase = 02000 (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase + 02001 MapRegisterNumber); 02002 02003 /* Check if scatter gather isn't supported */ 02004 if (!AdapterObject->ScatterGather) 02005 { 02006 /* Set the flag */ 02007 AdapterObject->MapRegisterBase = 02008 (PROS_MAP_REGISTER_ENTRY) 02009 ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); 02010 } 02011 } 02012 else 02013 { 02014 AdapterObject->MapRegisterBase = NULL; 02015 AdapterObject->NumberOfMapRegisters = 0; 02016 } 02017 02018 /* Return the base */ 02019 return AdapterObject->MapRegisterBase; 02020 } 02021 02022 /* EOF */ Generated on Sun May 27 2012 04:28:00 for ReactOS by
1.7.6.1
|