1 /* 2 * 3 * COPYRIGHT: See COPYING in the top level directory 4 * PROJECT: ReactOS kernel 5 * FILE: hal/halx86/generic/dma.c 6 * PURPOSE: DMA functions 7 * PROGRAMMERS: David Welch (welch@mcmail.com) 8 * Filip Navara (navaraf@reactos.com) 9 * UPDATE HISTORY: 10 * Created 22/05/98 11 */ 12 13 /** 14 * @page DMA Implementation Notes 15 * 16 * Concepts: 17 * 18 * - Map register 19 * 20 * Abstract encapsulation of physically contiguous buffer that resides 21 * in memory accessible by both the DMA device / controller and the system. 22 * The map registers are allocated and distributed on demand and are 23 * scarce resource. 24 * 25 * The actual use of map registers is to allow transfers from/to buffer 26 * located in physical memory at address inaccessible by the DMA device / 27 * controller directly. For such transfers the map register buffers 28 * are used as intermediate data storage. 29 * 30 * - Master adapter 31 * 32 * A container for map registers (typically corresponding to one physical 33 * bus connection type). There can be master adapters for 24-bit address 34 * ranges, 32-bit address ranges, etc. Every time a new DMA adapter is 35 * created it's associated with a corresponding master adapter that 36 * is used for any map register allocation requests. 37 * 38 * - Bus-master / Slave DMA 39 * 40 * Slave DMA is term used for DMA transfers done by the system (E)ISA 41 * controller as opposed to transfers mastered by the device itself 42 * (hence the name). 43 * 44 * For slave DMA special care is taken to actually access the system 45 * controller and handle the transfers. The relevant code is in 46 * HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers 47 * and IoMapTransfer. 48 * 49 * Implementation: 50 * 51 * - Allocation of map registers 52 * 53 * Initial set of map registers is allocated on the system start to 54 * ensure that low memory won't get filled up later. Additional map 55 * registers are allocated as needed by HalpGrowMapBuffers. This 56 * routine is called on two places: 57 * 58 * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that 59 * more map registers will probably be needed. 60 * - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker 61 * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly) 62 * when no more map registers are free. 63 * 64 * Note that even if no more map registers can be allocated it's not 65 * the end of the world. The adapters waiting for free map registers 66 * are queued in the master adapter's queue and once one driver hands 67 * back it's map registers (using IoFreeMapRegisters or indirectly using 68 * the execution routine callback in IoAllocateAdapterChannel) the 69 * queue gets processed and the map registers are reassigned. 70 */ 71 72 /* INCLUDES *****************************************************************/ 73 74 #include <hal.h> 75 #include <suppress.h> 76 77 #define NDEBUG 78 #include <debug.h> 79 80 #define MAX_SG_ELEMENTS 0x10 81 82 #ifndef _MINIHAL_ 83 static KEVENT HalpDmaLock; 84 static KSPIN_LOCK HalpDmaAdapterListLock; 85 static LIST_ENTRY HalpDmaAdapterList; 86 static PADAPTER_OBJECT HalpEisaAdapter[8]; 87 #endif 88 static BOOLEAN HalpEisaDma; 89 #ifndef _MINIHAL_ 90 static PADAPTER_OBJECT HalpMasterAdapter; 91 #endif 92 93 static const ULONG_PTR HalpEisaPortPage[8] = { 94 FIELD_OFFSET(DMA_PAGE, Channel0), 95 FIELD_OFFSET(DMA_PAGE, Channel1), 96 FIELD_OFFSET(DMA_PAGE, Channel2), 97 FIELD_OFFSET(DMA_PAGE, Channel3), 98 0, 99 FIELD_OFFSET(DMA_PAGE, Channel5), 100 FIELD_OFFSET(DMA_PAGE, Channel6), 101 FIELD_OFFSET(DMA_PAGE, Channel7) 102 }; 103 104 #ifndef _MINIHAL_ 105 NTSTATUS 106 NTAPI 107 HalCalculateScatterGatherListSize( 108 IN PADAPTER_OBJECT AdapterObject, 109 IN PMDL Mdl OPTIONAL, 110 IN PVOID CurrentVa, 111 IN ULONG Length, 112 OUT PULONG ScatterGatherListSize, 113 OUT PULONG pNumberOfMapRegisters); 114 115 NTSTATUS 116 NTAPI 117 HalBuildScatterGatherList( 118 IN PADAPTER_OBJECT AdapterObject, 119 IN PDEVICE_OBJECT DeviceObject, 120 IN PMDL Mdl, 121 IN PVOID CurrentVa, 122 IN ULONG Length, 123 IN PDRIVER_LIST_CONTROL ExecutionRoutine, 124 IN PVOID Context, 125 IN BOOLEAN WriteToDevice, 126 IN PVOID ScatterGatherBuffer, 127 IN ULONG ScatterGatherLength); 128 129 NTSTATUS 130 NTAPI 131 HalBuildMdlFromScatterGatherList( 132 IN PDMA_ADAPTER DmaAdapter, 133 IN PSCATTER_GATHER_LIST ScatterGather, 134 IN PMDL OriginalMdl, 135 OUT PMDL *TargetMdl); 136 137 138 static DMA_OPERATIONS HalpDmaOperations = { 139 sizeof(DMA_OPERATIONS), 140 (PPUT_DMA_ADAPTER)HalPutDmaAdapter, 141 (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer, 142 (PFREE_COMMON_BUFFER)HalFreeCommonBuffer, 143 NULL, /* Initialized in HalpInitDma() */ 144 NULL, /* Initialized in HalpInitDma() */ 145 NULL, /* Initialized in HalpInitDma() */ 146 NULL, /* Initialized in HalpInitDma() */ 147 NULL, /* Initialized in HalpInitDma() */ 148 (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment, 149 (PREAD_DMA_COUNTER)HalReadDmaCounter, 150 (PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList, 151 (PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList, 152 (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize, 153 (PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList, 154 (PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList 155 }; 156 #endif 157 158 #define MAX_MAP_REGISTERS 64 159 160 #define TAG_DMA ' AMD' 161 162 /* FUNCTIONS *****************************************************************/ 163 164 #if defined(SARCH_PC98) 165 /* 166 * Disable I/O for safety. 167 * FIXME: Add support for PC-98 DMA controllers. 168 */ 169 #undef WRITE_PORT_UCHAR 170 #undef READ_PORT_UCHAR 171 172 #define WRITE_PORT_UCHAR(Port, Data) \ 173 do { \ 174 UNIMPLEMENTED; \ 175 (Port); \ 176 (Data); \ 177 } while (0) 178 179 #define READ_PORT_UCHAR(Port) 0x00 180 #endif 181 182 #ifndef _MINIHAL_ 183 CODE_SEG("INIT") 184 VOID 185 HalpInitDma(VOID) 186 { 187 /* 188 * Initialize the DMA Operation table 189 */ 190 HalpDmaOperations.AllocateAdapterChannel = (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel; 191 HalpDmaOperations.FlushAdapterBuffers = (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers; 192 HalpDmaOperations.FreeAdapterChannel = (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel; 193 HalpDmaOperations.FreeMapRegisters = (PFREE_MAP_REGISTERS)IoFreeMapRegisters; 194 HalpDmaOperations.MapTransfer = (PMAP_TRANSFER)IoMapTransfer; 195 196 if (HalpBusType == MACHINE_TYPE_EISA) 197 { 198 /* 199 * Check if Extended DMA is available. We're just going to do a random 200 * read and write. 201 */ 202 WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)), 0x2A); 203 if (READ_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2))) == 0x2A) 204 { 205 DPRINT1("Machine supports EISA DMA. Bus type: %lu\n", HalpBusType); 206 HalpEisaDma = TRUE; 207 } 208 } 209 210 /* 211 * Intialize all the global variables and allocate master adapter with 212 * first map buffers. 213 */ 214 InitializeListHead(&HalpDmaAdapterList); 215 KeInitializeSpinLock(&HalpDmaAdapterListLock); 216 KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE); 217 HalpMasterAdapter = HalpDmaAllocateMasterAdapter(); 218 219 /* 220 * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's 221 * used by IoGetDmaAdapter in the kernel. 222 */ 223 HalGetDmaAdapter = HalpGetDmaAdapter; 224 } 225 #endif 226 227 /** 228 * @name HalpGetAdapterMaximumPhysicalAddress 229 * 230 * Get the maximum physical address acceptable by the device represented 231 * by the passed DMA adapter. 232 */ 233 PHYSICAL_ADDRESS 234 NTAPI 235 HalpGetAdapterMaximumPhysicalAddress(IN PADAPTER_OBJECT AdapterObject) 236 { 237 PHYSICAL_ADDRESS HighestAddress; 238 239 if (AdapterObject->MasterDevice) 240 { 241 if (AdapterObject->Dma64BitAddresses) 242 { 243 HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL; 244 return HighestAddress; 245 } 246 else if (AdapterObject->Dma32BitAddresses) 247 { 248 HighestAddress.QuadPart = 0xFFFFFFFF; 249 return HighestAddress; 250 } 251 } 252 253 HighestAddress.QuadPart = 0xFFFFFF; 254 return HighestAddress; 255 } 256 257 #ifndef _MINIHAL_ 258 /** 259 * @name HalpGrowMapBuffers 260 * 261 * Allocate initial, or additional, map buffers for DMA master adapter. 262 * 263 * @param MasterAdapter 264 * DMA master adapter to allocate buffers for. 265 * @param SizeOfMapBuffers 266 * Size of the map buffers to allocate (not including the size 267 * already allocated). 268 */ 269 BOOLEAN 270 NTAPI 271 HalpGrowMapBuffers(IN PADAPTER_OBJECT AdapterObject, 272 IN ULONG SizeOfMapBuffers) 273 { 274 PVOID VirtualAddress; 275 PHYSICAL_ADDRESS PhysicalAddress; 276 PHYSICAL_ADDRESS HighestAcceptableAddress; 277 PHYSICAL_ADDRESS LowestAcceptableAddress; 278 PHYSICAL_ADDRESS BoundryAddressMultiple; 279 KIRQL OldIrql; 280 ULONG MapRegisterCount; 281 282 /* Check if enough map register slots are available. */ 283 MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers); 284 if (MapRegisterCount + AdapterObject->NumberOfMapRegisters > MAX_MAP_REGISTERS) 285 { 286 DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n", 287 AdapterObject->NumberOfMapRegisters, 288 MapRegisterCount, 289 MAX_MAP_REGISTERS); 290 return FALSE; 291 } 292 293 /* 294 * Allocate memory for the new map registers. For 32-bit adapters we use 295 * two passes in order not to waste scare resource (low memory). 296 */ 297 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 298 LowestAcceptableAddress.HighPart = 0; 299 LowestAcceptableAddress.LowPart = HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0; 300 BoundryAddressMultiple.QuadPart = 0; 301 302 VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, 303 LowestAcceptableAddress, 304 HighestAcceptableAddress, 305 BoundryAddressMultiple, 306 MmNonCached); 307 if (!(VirtualAddress) && (LowestAcceptableAddress.LowPart)) 308 { 309 LowestAcceptableAddress.LowPart = 0; 310 VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, 311 LowestAcceptableAddress, 312 HighestAcceptableAddress, 313 BoundryAddressMultiple, 314 MmNonCached); 315 } 316 317 if (!VirtualAddress) return FALSE; 318 319 PhysicalAddress = MmGetPhysicalAddress(VirtualAddress); 320 321 /* 322 * All the following must be done with the master adapter lock held 323 * to prevent corruption. 324 */ 325 KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql); 326 327 /* 328 * Setup map register entries for the buffer allocated. Each entry has 329 * a virtual and physical address and corresponds to PAGE_SIZE large 330 * buffer. 331 */ 332 if (MapRegisterCount > 0) 333 { 334 PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry; 335 336 CurrentEntry = AdapterObject->MapRegisterBase + AdapterObject->NumberOfMapRegisters; 337 do 338 { 339 /* 340 * Leave one entry free for every non-contiguous memory region 341 * in the map register bitmap. This ensures that we can search 342 * using RtlFindClearBits for contiguous map register regions. 343 * 344 * Also for non-EISA DMA leave one free entry for every 64Kb 345 * break, because the DMA controller can handle only coniguous 346 * 64Kb regions. 347 */ 348 if (CurrentEntry != AdapterObject->MapRegisterBase) 349 { 350 PreviousEntry = CurrentEntry - 1; 351 if ((PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE) == PhysicalAddress.LowPart) 352 { 353 if (!HalpEisaDma) 354 { 355 if ((PreviousEntry->PhysicalAddress.LowPart ^ PhysicalAddress.LowPart) & 0xFFFF0000) 356 { 357 CurrentEntry++; 358 AdapterObject->NumberOfMapRegisters++; 359 } 360 } 361 } 362 else 363 { 364 CurrentEntry++; 365 AdapterObject->NumberOfMapRegisters++; 366 } 367 } 368 369 RtlClearBit(AdapterObject->MapRegisters, 370 (ULONG)(CurrentEntry - AdapterObject->MapRegisterBase)); 371 CurrentEntry->VirtualAddress = VirtualAddress; 372 CurrentEntry->PhysicalAddress = PhysicalAddress; 373 374 PhysicalAddress.LowPart += PAGE_SIZE; 375 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); 376 377 CurrentEntry++; 378 AdapterObject->NumberOfMapRegisters++; 379 MapRegisterCount--; 380 } while (MapRegisterCount); 381 } 382 383 KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); 384 385 return TRUE; 386 } 387 388 /** 389 * @name HalpDmaAllocateMasterAdapter 390 * 391 * Helper routine to allocate and initialize master adapter object and it's 392 * associated map register buffers. 393 * 394 * @see HalpInitDma 395 */ 396 PADAPTER_OBJECT 397 NTAPI 398 HalpDmaAllocateMasterAdapter(VOID) 399 { 400 PADAPTER_OBJECT MasterAdapter; 401 ULONG Size, SizeOfBitmap; 402 403 SizeOfBitmap = MAX_MAP_REGISTERS; 404 Size = sizeof(ADAPTER_OBJECT); 405 Size += sizeof(RTL_BITMAP); 406 Size += (SizeOfBitmap + 7) >> 3; 407 408 MasterAdapter = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_DMA); 409 if (!MasterAdapter) return NULL; 410 411 RtlZeroMemory(MasterAdapter, Size); 412 413 KeInitializeSpinLock(&MasterAdapter->SpinLock); 414 InitializeListHead(&MasterAdapter->AdapterQueue); 415 416 MasterAdapter->MapRegisters = (PVOID)(MasterAdapter + 1); 417 RtlInitializeBitMap(MasterAdapter->MapRegisters, 418 (PULONG)(MasterAdapter->MapRegisters + 1), 419 SizeOfBitmap); 420 RtlSetAllBits(MasterAdapter->MapRegisters); 421 MasterAdapter->NumberOfMapRegisters = 0; 422 MasterAdapter->CommittedMapRegisters = 0; 423 424 MasterAdapter->MapRegisterBase = ExAllocatePoolWithTag(NonPagedPool, 425 SizeOfBitmap * 426 sizeof(ROS_MAP_REGISTER_ENTRY), 427 TAG_DMA); 428 if (!MasterAdapter->MapRegisterBase) 429 { 430 ExFreePool(MasterAdapter); 431 return NULL; 432 } 433 434 RtlZeroMemory(MasterAdapter->MapRegisterBase, 435 SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY)); 436 if (!HalpGrowMapBuffers(MasterAdapter, 0x10000)) 437 { 438 ExFreePool(MasterAdapter); 439 return NULL; 440 } 441 442 return MasterAdapter; 443 } 444 445 /** 446 * @name HalpDmaAllocateChildAdapter 447 * 448 * Helper routine of HalGetAdapter. Allocate child adapter object and 449 * fill out some basic fields. 450 * 451 * @see HalGetAdapter 452 */ 453 PADAPTER_OBJECT 454 NTAPI 455 HalpDmaAllocateChildAdapter(IN ULONG NumberOfMapRegisters, 456 IN PDEVICE_DESCRIPTION DeviceDescription) 457 { 458 PADAPTER_OBJECT AdapterObject; 459 OBJECT_ATTRIBUTES ObjectAttributes; 460 NTSTATUS Status; 461 HANDLE Handle; 462 463 InitializeObjectAttributes(&ObjectAttributes, 464 NULL, 465 OBJ_KERNEL_HANDLE | OBJ_PERMANENT, 466 NULL, 467 NULL); 468 469 Status = ObCreateObject(KernelMode, 470 IoAdapterObjectType, 471 &ObjectAttributes, 472 KernelMode, 473 NULL, 474 sizeof(ADAPTER_OBJECT), 475 0, 476 0, 477 (PVOID)&AdapterObject); 478 if (!NT_SUCCESS(Status)) return NULL; 479 480 RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT)); 481 482 Status = ObInsertObject(AdapterObject, 483 NULL, 484 FILE_READ_DATA | FILE_WRITE_DATA, 485 0, 486 NULL, 487 &Handle); 488 if (!NT_SUCCESS(Status)) return NULL; 489 490 ObReferenceObject(AdapterObject); 491 492 ZwClose(Handle); 493 494 AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version; 495 AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT); 496 AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations; 497 AdapterObject->MapRegistersPerChannel = 1; 498 AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; 499 AdapterObject->ChannelNumber = 0xFF; 500 AdapterObject->MasterAdapter = HalpMasterAdapter; 501 KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue); 502 503 return AdapterObject; 504 } 505 #endif 506 507 /** 508 * @name HalpDmaInitializeEisaAdapter 509 * 510 * Setup DMA modes and extended modes for (E)ISA DMA adapter object. 511 */ 512 BOOLEAN 513 NTAPI 514 HalpDmaInitializeEisaAdapter(IN PADAPTER_OBJECT AdapterObject, 515 IN PDEVICE_DESCRIPTION DeviceDescription) 516 { 517 UCHAR Controller; 518 DMA_MODE DmaMode = {{0 }}; 519 DMA_EXTENDED_MODE ExtendedMode = {{ 0 }}; 520 PVOID AdapterBaseVa; 521 522 Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1; 523 524 if (Controller == 1) 525 { 526 AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController1)); 527 } 528 else 529 { 530 AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2)); 531 } 532 533 AdapterObject->AdapterNumber = Controller; 534 AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3); 535 AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel]; 536 AdapterObject->Width16Bits = FALSE; 537 AdapterObject->AdapterBaseVa = AdapterBaseVa; 538 539 if (HalpEisaDma) 540 { 541 ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber; 542 543 switch (DeviceDescription->DmaSpeed) 544 { 545 case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break; 546 case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break; 547 case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break; 548 case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break; 549 default: 550 return FALSE; 551 } 552 553 switch (DeviceDescription->DmaWidth) 554 { 555 case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break; 556 case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break; 557 case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break; 558 default: 559 return FALSE; 560 } 561 562 if (Controller == 1) 563 { 564 WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1)), 565 ExtendedMode.Byte); 566 } 567 else 568 { 569 WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2)), 570 ExtendedMode.Byte); 571 } 572 } 573 else 574 { 575 /* 576 * Validate setup for non-busmaster DMA adapter. Secondary controller 577 * supports only 16-bit transfers and main controller supports only 578 * 8-bit transfers. Anything else is invalid. 579 */ 580 if (!DeviceDescription->Master) 581 { 582 if ((Controller == 2) && (DeviceDescription->DmaWidth == Width16Bits)) 583 { 584 AdapterObject->Width16Bits = TRUE; 585 } 586 else if ((Controller != 1) || (DeviceDescription->DmaWidth != Width8Bits)) 587 { 588 return FALSE; 589 } 590 } 591 } 592 593 DmaMode.Channel = AdapterObject->ChannelNumber; 594 DmaMode.AutoInitialize = DeviceDescription->AutoInitialize; 595 596 /* 597 * Set the DMA request mode. 598 * 599 * For (E)ISA bus master devices just unmask (enable) the DMA channel 600 * and set it to cascade mode. Otherwise just select the right one 601 * bases on the passed device description. 602 */ 603 if (DeviceDescription->Master) 604 { 605 DmaMode.RequestMode = CASCADE_REQUEST_MODE; 606 if (Controller == 1) 607 { 608 /* Set the Request Data */ 609 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR) 610 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte); 611 612 /* Unmask DMA Channel */ 613 WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask, 614 AdapterObject->ChannelNumber | DMA_CLEARMASK); 615 } 616 else 617 { 618 /* Set the Request Data */ 619 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte); 620 621 /* Unmask DMA Channel */ 622 WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask, 623 AdapterObject->ChannelNumber | DMA_CLEARMASK); 624 } 625 } 626 else 627 { 628 if (DeviceDescription->DemandMode) 629 { 630 DmaMode.RequestMode = DEMAND_REQUEST_MODE; 631 } 632 else 633 { 634 DmaMode.RequestMode = SINGLE_REQUEST_MODE; 635 } 636 } 637 638 AdapterObject->AdapterMode = DmaMode; 639 640 return TRUE; 641 } 642 643 #ifndef _MINIHAL_ 644 /** 645 * @name HalGetAdapter 646 * 647 * Allocate an adapter object for DMA device. 648 * 649 * @param DeviceDescription 650 * Structure describing the attributes of the device. 651 * @param NumberOfMapRegisters 652 * On return filled with the maximum number of map registers the 653 * device driver can allocate for DMA transfer operations. 654 * 655 * @return The DMA adapter on success, NULL otherwise. 656 * 657 * @implemented 658 */ 659 PADAPTER_OBJECT 660 NTAPI 661 HalGetAdapter(IN PDEVICE_DESCRIPTION DeviceDescription, 662 OUT PULONG NumberOfMapRegisters) 663 { 664 PADAPTER_OBJECT AdapterObject = NULL; 665 BOOLEAN EisaAdapter; 666 ULONG MapRegisters; 667 ULONG MaximumLength; 668 KIRQL OldIrql; 669 670 /* Validate parameters in device description */ 671 if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) return NULL; 672 673 /* 674 * See if we're going to use ISA/EISA DMA adapter. These adapters are 675 * special since they're reused. 676 * 677 * Also note that we check for channel number since there are only 8 DMA 678 * channels on ISA, so any request above this requires new adapter. 679 */ 680 if (((DeviceDescription->InterfaceType == Eisa) || 681 (DeviceDescription->InterfaceType == Isa)) || !(DeviceDescription->Master)) 682 { 683 if (((DeviceDescription->InterfaceType == Isa) || 684 (DeviceDescription->InterfaceType == Eisa)) && 685 (DeviceDescription->DmaChannel >= 8)) 686 { 687 EisaAdapter = FALSE; 688 } 689 else 690 { 691 EisaAdapter = TRUE; 692 } 693 } 694 else 695 { 696 EisaAdapter = FALSE; 697 } 698 699 /* 700 * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used 701 * for cascading the controllers and it's not available for software use. 702 */ 703 if ((EisaAdapter) && (DeviceDescription->DmaChannel == 4)) return NULL; 704 705 /* 706 * Calculate the number of map registers. 707 * 708 * - For EISA and PCI scatter/gather no map registers are needed. 709 * - For ISA slave scatter/gather one map register is needed. 710 * - For all other cases the number of map registers depends on 711 * DeviceDescription->MaximumLength. 712 */ 713 MaximumLength = DeviceDescription->MaximumLength & MAXLONG; 714 if ((DeviceDescription->ScatterGather) && 715 ((DeviceDescription->InterfaceType == Eisa) || 716 (DeviceDescription->InterfaceType == PCIBus))) 717 { 718 MapRegisters = 0; 719 } 720 else if ((DeviceDescription->ScatterGather) && !(DeviceDescription->Master)) 721 { 722 MapRegisters = 1; 723 } 724 else 725 { 726 /* 727 * In the equation below the additional map register added by 728 * the "+1" accounts for the case when a transfer does not start 729 * at a page-aligned address. 730 */ 731 MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1; 732 if (MapRegisters > 16) MapRegisters = 16; 733 } 734 735 /* 736 * Acquire the DMA lock that is used to protect the EISA adapter array. 737 */ 738 KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL); 739 740 /* 741 * Now we must get ahold of the adapter object. For first eight ISA/EISA 742 * channels there are static adapter objects that are reused and updated 743 * on succesive HalGetAdapter calls. In other cases a new adapter object 744 * is always created and it's to the DMA adapter list (HalpDmaAdapterList). 745 */ 746 if (EisaAdapter) 747 { 748 AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel]; 749 if (AdapterObject) 750 { 751 if ((AdapterObject->NeedsMapRegisters) && 752 (MapRegisters > AdapterObject->MapRegistersPerChannel)) 753 { 754 AdapterObject->MapRegistersPerChannel = MapRegisters; 755 } 756 } 757 } 758 759 if (AdapterObject == NULL) 760 { 761 AdapterObject = HalpDmaAllocateChildAdapter(MapRegisters, DeviceDescription); 762 if (AdapterObject == NULL) 763 { 764 KeSetEvent(&HalpDmaLock, 0, 0); 765 return NULL; 766 } 767 768 if (EisaAdapter) 769 { 770 HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject; 771 } 772 773 if (MapRegisters > 0) 774 { 775 AdapterObject->NeedsMapRegisters = TRUE; 776 AdapterObject->MapRegistersPerChannel = MapRegisters; 777 } 778 else 779 { 780 AdapterObject->NeedsMapRegisters = FALSE; 781 if (DeviceDescription->Master) 782 { 783 AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1; 784 } 785 else 786 { 787 AdapterObject->MapRegistersPerChannel = 1; 788 } 789 } 790 } 791 792 /* 793 * Release the DMA lock. HalpEisaAdapter will no longer be touched, 794 * so we don't need it. 795 */ 796 KeSetEvent(&HalpDmaLock, 0, 0); 797 798 if (!EisaAdapter) 799 { 800 /* If it's not one of the static adapters, add it to the list */ 801 KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); 802 InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList); 803 KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); 804 } 805 806 /* 807 * Setup the values in the adapter object that are common for all 808 * types of buses. 809 */ 810 if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1) 811 { 812 AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount; 813 } 814 else 815 { 816 AdapterObject->IgnoreCount = 0; 817 } 818 819 AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; 820 AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses; 821 AdapterObject->ScatterGather = DeviceDescription->ScatterGather; 822 AdapterObject->MasterDevice = DeviceDescription->Master; 823 *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel; 824 825 /* 826 * For non-(E)ISA adapters we have already done all the work. On the 827 * other hand for (E)ISA adapters we must still setup the DMA modes 828 * and prepare the controller. 829 */ 830 if (EisaAdapter) 831 { 832 if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription)) 833 { 834 ObDereferenceObject(AdapterObject); 835 return NULL; 836 } 837 } 838 839 return AdapterObject; 840 } 841 842 /** 843 * @name HalpGetDmaAdapter 844 * 845 * Internal routine to allocate PnP DMA adapter object. It's exported through 846 * HalDispatchTable and used by IoGetDmaAdapter. 847 * 848 * @see HalGetAdapter 849 */ 850 PDMA_ADAPTER 851 NTAPI 852 HalpGetDmaAdapter(IN PVOID Context, 853 IN PDEVICE_DESCRIPTION DeviceDescription, 854 OUT PULONG NumberOfMapRegisters) 855 { 856 return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader; 857 } 858 859 /** 860 * @name HalPutDmaAdapter 861 * 862 * Internal routine to free DMA adapter and resources for reuse. It's exported 863 * using the DMA_OPERATIONS interface by HalGetAdapter. 864 * 865 * @see HalGetAdapter 866 */ 867 VOID 868 NTAPI 869 HalPutDmaAdapter(IN PADAPTER_OBJECT AdapterObject) 870 { 871 KIRQL OldIrql; 872 if (AdapterObject->ChannelNumber == 0xFF) 873 { 874 KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); 875 RemoveEntryList(&AdapterObject->AdapterList); 876 KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); 877 } 878 879 ObDereferenceObject(AdapterObject); 880 } 881 882 /** 883 * @name HalAllocateCommonBuffer 884 * 885 * Allocates memory that is visible to both the processor(s) and the DMA 886 * device. 887 * 888 * @param AdapterObject 889 * Adapter object representing the bus master or system dma controller. 890 * @param Length 891 * Number of bytes to allocate. 892 * @param LogicalAddress 893 * Logical address the driver can use to access the buffer. 894 * @param CacheEnabled 895 * Specifies if the memory can be cached. 896 * 897 * @return The base virtual address of the memory allocated or NULL on failure. 898 * 899 * @remarks 900 * On real NT x86 systems the CacheEnabled parameter is ignored, we honour 901 * it. If it proves to cause problems change it. 902 * 903 * @see HalFreeCommonBuffer 904 * 905 * @implemented 906 */ 907 PVOID 908 NTAPI 909 HalAllocateCommonBuffer(IN PADAPTER_OBJECT AdapterObject, 910 IN ULONG Length, 911 IN PPHYSICAL_ADDRESS LogicalAddress, 912 IN BOOLEAN CacheEnabled) 913 { 914 PHYSICAL_ADDRESS LowestAcceptableAddress; 915 PHYSICAL_ADDRESS HighestAcceptableAddress; 916 PHYSICAL_ADDRESS BoundryAddressMultiple; 917 PVOID VirtualAddress; 918 919 LowestAcceptableAddress.QuadPart = 0; 920 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 921 BoundryAddressMultiple.QuadPart = 0; 922 923 /* 924 * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For 925 * slave DMA devices the 64Kb boundary mustn't be crossed since the 926 * controller wouldn't be able to handle it. 927 */ 928 if (AdapterObject->MasterDevice) 929 { 930 BoundryAddressMultiple.HighPart = 1; 931 } 932 else 933 { 934 BoundryAddressMultiple.LowPart = 0x10000; 935 } 936 937 VirtualAddress = MmAllocateContiguousMemorySpecifyCache(Length, 938 LowestAcceptableAddress, 939 HighestAcceptableAddress, 940 BoundryAddressMultiple, 941 CacheEnabled ? MmCached : 942 MmNonCached); 943 if (VirtualAddress == NULL) return NULL; 944 945 *LogicalAddress = MmGetPhysicalAddress(VirtualAddress); 946 947 return VirtualAddress; 948 } 949 950 /** 951 * @name HalFreeCommonBuffer 952 * 953 * Free common buffer allocated with HalAllocateCommonBuffer. 954 * 955 * @see HalAllocateCommonBuffer 956 * 957 * @implemented 958 */ 959 VOID 960 NTAPI 961 HalFreeCommonBuffer(IN PADAPTER_OBJECT AdapterObject, 962 IN ULONG Length, 963 IN PHYSICAL_ADDRESS LogicalAddress, 964 IN PVOID VirtualAddress, 965 IN BOOLEAN CacheEnabled) 966 { 967 MmFreeContiguousMemorySpecifyCache(VirtualAddress, 968 Length, 969 CacheEnabled ? MmCached : MmNonCached); 970 } 971 972 typedef struct _SCATTER_GATHER_CONTEXT { 973 BOOLEAN UsingUserBuffer; 974 PADAPTER_OBJECT AdapterObject; 975 PMDL Mdl; 976 PUCHAR CurrentVa; 977 ULONG Length; 978 PDRIVER_LIST_CONTROL AdapterListControlRoutine; 979 PVOID AdapterListControlContext, MapRegisterBase; 980 ULONG MapRegisterCount; 981 BOOLEAN WriteToDevice; 982 WAIT_CONTEXT_BLOCK Wcb; 983 } SCATTER_GATHER_CONTEXT, *PSCATTER_GATHER_CONTEXT; 984 985 986 IO_ALLOCATION_ACTION 987 NTAPI 988 HalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject, 989 IN PIRP Irp, 990 IN PVOID MapRegisterBase, 991 IN PVOID Context) 992 { 993 PSCATTER_GATHER_CONTEXT AdapterControlContext = Context; 994 PADAPTER_OBJECT AdapterObject = AdapterControlContext->AdapterObject; 995 PSCATTER_GATHER_LIST ScatterGatherList; 996 SCATTER_GATHER_ELEMENT TempElements[MAX_SG_ELEMENTS]; 997 ULONG ElementCount = 0, RemainingLength = AdapterControlContext->Length; 998 PUCHAR CurrentVa = AdapterControlContext->CurrentVa; 999 1000 /* Store the map register base for later in HalPutScatterGatherList */ 1001 AdapterControlContext->MapRegisterBase = MapRegisterBase; 1002 1003 while (RemainingLength > 0 && ElementCount < MAX_SG_ELEMENTS) 1004 { 1005 TempElements[ElementCount].Length = RemainingLength; 1006 TempElements[ElementCount].Reserved = 0; 1007 TempElements[ElementCount].Address = IoMapTransfer(AdapterObject, 1008 AdapterControlContext->Mdl, 1009 MapRegisterBase, 1010 CurrentVa + (AdapterControlContext->Length - RemainingLength), 1011 &TempElements[ElementCount].Length, 1012 AdapterControlContext->WriteToDevice); 1013 if (TempElements[ElementCount].Length == 0) 1014 break; 1015 1016 DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n", 1017 TempElements[ElementCount].Address.QuadPart, 1018 TempElements[ElementCount].Length); 1019 1020 ASSERT(TempElements[ElementCount].Length <= RemainingLength); 1021 RemainingLength -= TempElements[ElementCount].Length; 1022 ElementCount++; 1023 } 1024 1025 if (RemainingLength > 0) 1026 { 1027 DPRINT1("Scatter/gather list construction failed!\n"); 1028 return DeallocateObject; 1029 } 1030 1031 ScatterGatherList = ExAllocatePoolWithTag(NonPagedPool, 1032 sizeof(SCATTER_GATHER_LIST) + sizeof(SCATTER_GATHER_ELEMENT) * ElementCount, 1033 TAG_DMA); 1034 ASSERT(ScatterGatherList); 1035 1036 ScatterGatherList->NumberOfElements = ElementCount; 1037 ScatterGatherList->Reserved = (ULONG_PTR)AdapterControlContext; 1038 RtlCopyMemory(ScatterGatherList->Elements, 1039 TempElements, 1040 sizeof(SCATTER_GATHER_ELEMENT) * ElementCount); 1041 1042 DPRINT("Initiating S/G DMA with %d element(s)\n", ElementCount); 1043 1044 AdapterControlContext->AdapterListControlRoutine(DeviceObject, 1045 Irp, 1046 ScatterGatherList, 1047 AdapterControlContext->AdapterListControlContext); 1048 1049 return DeallocateObjectKeepRegisters; 1050 } 1051 1052 /** 1053 * @name HalGetScatterGatherList 1054 * 1055 * Creates a scatter-gather list to be using in scatter/gather DMA 1056 * 1057 * @param AdapterObject 1058 * Adapter object representing the bus master or system dma controller. 1059 * @param DeviceObject 1060 * The device target for DMA. 1061 * @param Mdl 1062 * The MDL that describes the buffer to be mapped. 1063 * @param CurrentVa 1064 * The current VA in the buffer to be mapped for transfer. 1065 * @param Length 1066 * Specifies the length of data in bytes to be mapped. 1067 * @param ExecutionRoutine 1068 * A caller supplied AdapterListControl routine to be called when DMA is available. 1069 * @param Context 1070 * Context passed to the AdapterListControl routine. 1071 * @param WriteToDevice 1072 * Indicates direction of DMA operation. 1073 * 1074 * @return The status of the operation. 1075 * 1076 * @see HalBuildScatterGatherList 1077 * 1078 * @implemented 1079 */ 1080 NTSTATUS 1081 NTAPI 1082 HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject, 1083 IN PDEVICE_OBJECT DeviceObject, 1084 IN PMDL Mdl, 1085 IN PVOID CurrentVa, 1086 IN ULONG Length, 1087 IN PDRIVER_LIST_CONTROL ExecutionRoutine, 1088 IN PVOID Context, 1089 IN BOOLEAN WriteToDevice) 1090 { 1091 return HalBuildScatterGatherList(AdapterObject, 1092 DeviceObject, 1093 Mdl, 1094 CurrentVa, 1095 Length, 1096 ExecutionRoutine, 1097 Context, 1098 WriteToDevice, 1099 NULL, 1100 0); 1101 } 1102 1103 /** 1104 * @name HalPutScatterGatherList 1105 * 1106 * Frees a scatter-gather list allocated from HalBuildScatterGatherList 1107 * 1108 * @param AdapterObject 1109 * Adapter object representing the bus master or system dma controller. 1110 * @param ScatterGather 1111 * The scatter/gather list to be freed. 1112 * @param WriteToDevice 1113 * Indicates direction of DMA operation. 1114 * 1115 * @return None 1116 * 1117 * @see HalBuildScatterGatherList 1118 * 1119 * @implemented 1120 */ 1121 VOID 1122 NTAPI 1123 HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject, 1124 IN PSCATTER_GATHER_LIST ScatterGather, 1125 IN BOOLEAN WriteToDevice) 1126 { 1127 PSCATTER_GATHER_CONTEXT AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved; 1128 ULONG i; 1129 1130 for (i = 0; i < ScatterGather->NumberOfElements; i++) 1131 { 1132 IoFlushAdapterBuffers(AdapterObject, 1133 AdapterControlContext->Mdl, 1134 AdapterControlContext->MapRegisterBase, 1135 AdapterControlContext->CurrentVa, 1136 ScatterGather->Elements[i].Length, 1137 AdapterControlContext->WriteToDevice); 1138 AdapterControlContext->CurrentVa += ScatterGather->Elements[i].Length; 1139 } 1140 1141 IoFreeMapRegisters(AdapterObject, 1142 AdapterControlContext->MapRegisterBase, 1143 AdapterControlContext->MapRegisterCount); 1144 1145 1146 ExFreePoolWithTag(ScatterGather, TAG_DMA); 1147 1148 /* If this is our buffer, release it */ 1149 if (!AdapterControlContext->UsingUserBuffer) 1150 ExFreePoolWithTag(AdapterControlContext, TAG_DMA); 1151 1152 DPRINT("S/G DMA has finished!\n"); 1153 } 1154 1155 NTSTATUS 1156 NTAPI 1157 HalCalculateScatterGatherListSize( 1158 IN PADAPTER_OBJECT AdapterObject, 1159 IN PMDL Mdl OPTIONAL, 1160 IN PVOID CurrentVa, 1161 IN ULONG Length, 1162 OUT PULONG ScatterGatherListSize, 1163 OUT PULONG pNumberOfMapRegisters) 1164 { 1165 ULONG NumberOfMapRegisters; 1166 ULONG SgSize; 1167 1168 UNIMPLEMENTED_ONCE; 1169 1170 NumberOfMapRegisters = PAGE_ROUND_UP(Length) >> PAGE_SHIFT; 1171 SgSize = sizeof(SCATTER_GATHER_CONTEXT); 1172 1173 *ScatterGatherListSize = SgSize; 1174 if (pNumberOfMapRegisters) *pNumberOfMapRegisters = NumberOfMapRegisters; 1175 1176 return STATUS_SUCCESS; 1177 } 1178 1179 /** 1180 * @name HalBuildScatterGatherList 1181 * 1182 * Creates a scatter-gather list to be using in scatter/gather DMA 1183 * 1184 * @param AdapterObject 1185 * Adapter object representing the bus master or system dma controller. 1186 * @param DeviceObject 1187 * The device target for DMA. 1188 * @param Mdl 1189 * The MDL that describes the buffer to be mapped. 1190 * @param CurrentVa 1191 * The current VA in the buffer to be mapped for transfer. 1192 * @param Length 1193 * Specifies the length of data in bytes to be mapped. 1194 * @param ExecutionRoutine 1195 * A caller supplied AdapterListControl routine to be called when DMA is available. 1196 * @param Context 1197 * Context passed to the AdapterListControl routine. 1198 * @param WriteToDevice 1199 * Indicates direction of DMA operation. 1200 * 1201 * @param ScatterGatherBuffer 1202 * User buffer for the scatter-gather list 1203 * 1204 * @param ScatterGatherBufferLength 1205 * Buffer length 1206 * 1207 * @return The status of the operation. 1208 * 1209 * @see HalPutScatterGatherList 1210 * 1211 * @implemented 1212 */ 1213 NTSTATUS 1214 NTAPI 1215 HalBuildScatterGatherList( 1216 IN PADAPTER_OBJECT AdapterObject, 1217 IN PDEVICE_OBJECT DeviceObject, 1218 IN PMDL Mdl, 1219 IN PVOID CurrentVa, 1220 IN ULONG Length, 1221 IN PDRIVER_LIST_CONTROL ExecutionRoutine, 1222 IN PVOID Context, 1223 IN BOOLEAN WriteToDevice, 1224 IN PVOID ScatterGatherBuffer, 1225 IN ULONG ScatterGatherBufferLength) 1226 { 1227 NTSTATUS Status; 1228 ULONG SgSize, NumberOfMapRegisters; 1229 PSCATTER_GATHER_CONTEXT ScatterGatherContext; 1230 BOOLEAN UsingUserBuffer; 1231 1232 Status = HalCalculateScatterGatherListSize(AdapterObject, 1233 Mdl, 1234 CurrentVa, 1235 Length, 1236 &SgSize, 1237 &NumberOfMapRegisters); 1238 if (!NT_SUCCESS(Status)) return Status; 1239 1240 if (ScatterGatherBuffer) 1241 { 1242 /* Checking if user buffer is enough */ 1243 if (ScatterGatherBufferLength < SgSize) 1244 { 1245 return STATUS_BUFFER_TOO_SMALL; 1246 } 1247 UsingUserBuffer = TRUE; 1248 } 1249 else 1250 { 1251 ScatterGatherBuffer = ExAllocatePoolWithTag(NonPagedPool, SgSize, TAG_DMA); 1252 if (!ScatterGatherBuffer) 1253 { 1254 return STATUS_INSUFFICIENT_RESOURCES; 1255 } 1256 UsingUserBuffer = FALSE; 1257 } 1258 1259 { 1260 ScatterGatherContext = (PSCATTER_GATHER_CONTEXT)ScatterGatherBuffer; 1261 1262 /* Fill the scatter-gather context */ 1263 ScatterGatherContext->UsingUserBuffer = UsingUserBuffer; 1264 ScatterGatherContext->AdapterObject = AdapterObject; 1265 ScatterGatherContext->Mdl = Mdl; 1266 ScatterGatherContext->CurrentVa = CurrentVa; 1267 ScatterGatherContext->Length = Length; 1268 ScatterGatherContext->MapRegisterCount = NumberOfMapRegisters; 1269 ScatterGatherContext->AdapterListControlRoutine = ExecutionRoutine; 1270 ScatterGatherContext->AdapterListControlContext = Context; 1271 ScatterGatherContext->WriteToDevice = WriteToDevice; 1272 1273 ScatterGatherContext->Wcb.DeviceObject = DeviceObject; 1274 ScatterGatherContext->Wcb.DeviceContext = (PVOID)ScatterGatherContext; 1275 ScatterGatherContext->Wcb.CurrentIrp = DeviceObject->CurrentIrp; 1276 1277 Status = HalAllocateAdapterChannel(AdapterObject, 1278 &ScatterGatherContext->Wcb, 1279 NumberOfMapRegisters, 1280 HalpScatterGatherAdapterControl); 1281 1282 if (!NT_SUCCESS(Status)) 1283 { 1284 if (!UsingUserBuffer) 1285 ExFreePoolWithTag(ScatterGatherBuffer, TAG_DMA); 1286 return Status; 1287 } 1288 } 1289 1290 return STATUS_SUCCESS; 1291 } 1292 1293 NTSTATUS 1294 NTAPI 1295 HalBuildMdlFromScatterGatherList( 1296 IN PDMA_ADAPTER DmaAdapter, 1297 IN PSCATTER_GATHER_LIST ScatterGather, 1298 IN PMDL OriginalMdl, 1299 OUT PMDL *TargetMdl) 1300 { 1301 UNIMPLEMENTED; 1302 return STATUS_NOT_IMPLEMENTED; 1303 } 1304 #endif 1305 1306 /** 1307 * @name HalpDmaGetDmaAlignment 1308 * 1309 * Internal routine to return the DMA alignment requirement. It's exported 1310 * using the DMA_OPERATIONS interface by HalGetAdapter. 1311 * 1312 * @see HalGetAdapter 1313 */ 1314 ULONG 1315 NTAPI 1316 HalpDmaGetDmaAlignment(IN PADAPTER_OBJECT AdapterObject) 1317 { 1318 return 1; 1319 } 1320 1321 /* 1322 * @name HalReadDmaCounter 1323 * 1324 * Read DMA operation progress counter. 1325 * 1326 * @implemented 1327 */ 1328 ULONG 1329 NTAPI 1330 HalReadDmaCounter(IN PADAPTER_OBJECT AdapterObject) 1331 { 1332 KIRQL OldIrql; 1333 ULONG Count, OldCount; 1334 1335 ASSERT(!AdapterObject->MasterDevice); 1336 1337 /* 1338 * Acquire the master adapter lock since we're going to mess with the 1339 * system DMA controller registers and we really don't want anyone 1340 * to do the same at the same time. 1341 */ 1342 KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); 1343 1344 /* Send the request to the specific controller. */ 1345 if (AdapterObject->AdapterNumber == 1) 1346 { 1347 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 1348 1349 Count = 0xffff00; 1350 do 1351 { 1352 OldCount = Count; 1353 1354 /* Send Reset */ 1355 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); 1356 1357 /* Read Count */ 1358 Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount 1359 [AdapterObject->ChannelNumber].DmaBaseCount); 1360 Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount 1361 [AdapterObject->ChannelNumber].DmaBaseCount) << 8; 1362 } while (0xffff00 & (OldCount ^ Count)); 1363 } 1364 else 1365 { 1366 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 1367 1368 Count = 0xffff00; 1369 do 1370 { 1371 OldCount = Count; 1372 1373 /* Send Reset */ 1374 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); 1375 1376 /* Read Count */ 1377 Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount 1378 [AdapterObject->ChannelNumber].DmaBaseCount); 1379 Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount 1380 [AdapterObject->ChannelNumber].DmaBaseCount) << 8; 1381 } while (0xffff00 & (OldCount ^ Count)); 1382 } 1383 1384 KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); 1385 1386 Count++; 1387 Count &= 0xffff; 1388 if (AdapterObject->Width16Bits) Count *= 2; 1389 1390 return Count; 1391 } 1392 1393 #ifndef _MINIHAL_ 1394 /** 1395 * @name HalpGrowMapBufferWorker 1396 * 1397 * Helper routine of HalAllocateAdapterChannel for allocating map registers 1398 * at PASSIVE_LEVEL in work item. 1399 */ 1400 VOID 1401 NTAPI 1402 HalpGrowMapBufferWorker(IN PVOID DeferredContext) 1403 { 1404 PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext; 1405 KIRQL OldIrql; 1406 BOOLEAN Succeeded; 1407 1408 /* 1409 * Try to allocate new map registers for the adapter. 1410 * 1411 * NOTE: The NT implementation actually tries to allocate more map 1412 * registers than needed as an optimization. 1413 */ 1414 KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL); 1415 Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter, 1416 WorkItem->NumberOfMapRegisters << PAGE_SHIFT); 1417 KeSetEvent(&HalpDmaLock, 0, 0); 1418 1419 if (Succeeded) 1420 { 1421 /* 1422 * Flush the adapter queue now that new map registers are ready. The 1423 * easiest way to do that is to call IoFreeMapRegisters to not free 1424 * any registers. Note that we use the magic (PVOID)2 map register 1425 * base to bypass the parameter checking. 1426 */ 1427 OldIrql = KfRaiseIrql(DISPATCH_LEVEL); 1428 IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0); 1429 KfLowerIrql(OldIrql); 1430 } 1431 1432 ExFreePool(WorkItem); 1433 } 1434 1435 /** 1436 * @name HalAllocateAdapterChannel 1437 * 1438 * Setup map registers for an adapter object. 1439 * 1440 * @param AdapterObject 1441 * Pointer to an ADAPTER_OBJECT to set up. 1442 * @param WaitContextBlock 1443 * Context block to be used with ExecutionRoutine. 1444 * @param NumberOfMapRegisters 1445 * Number of map registers requested. 1446 * @param ExecutionRoutine 1447 * Callback to call when map registers are allocated. 1448 * 1449 * @return 1450 * If not enough map registers can be allocated then 1451 * STATUS_INSUFFICIENT_RESOURCES is returned. If the function 1452 * succeeds or the callback is queued for later delivering then 1453 * STATUS_SUCCESS is returned. 1454 * 1455 * @see IoFreeAdapterChannel 1456 * 1457 * @implemented 1458 */ 1459 NTSTATUS 1460 NTAPI 1461 HalAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject, 1462 IN PWAIT_CONTEXT_BLOCK WaitContextBlock, 1463 IN ULONG NumberOfMapRegisters, 1464 IN PDRIVER_CONTROL ExecutionRoutine) 1465 { 1466 PADAPTER_OBJECT MasterAdapter; 1467 PGROW_WORK_ITEM WorkItem; 1468 ULONG Index = MAXULONG; 1469 ULONG Result; 1470 KIRQL OldIrql; 1471 1472 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 1473 1474 /* Set up the wait context block in case we can't run right away. */ 1475 WaitContextBlock->DeviceRoutine = ExecutionRoutine; 1476 WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters; 1477 1478 /* Returns true if queued, else returns false and sets the queue to busy */ 1479 if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, 1480 &WaitContextBlock->WaitQueueEntry)) 1481 { 1482 return STATUS_SUCCESS; 1483 } 1484 1485 MasterAdapter = AdapterObject->MasterAdapter; 1486 1487 AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; 1488 AdapterObject->CurrentWcb = WaitContextBlock; 1489 1490 if ((NumberOfMapRegisters) && (AdapterObject->NeedsMapRegisters)) 1491 { 1492 if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) 1493 { 1494 AdapterObject->NumberOfMapRegisters = 0; 1495 IoFreeAdapterChannel(AdapterObject); 1496 return STATUS_INSUFFICIENT_RESOURCES; 1497 } 1498 1499 /* 1500 * Get the map registers. This is partly complicated by the fact 1501 * that new map registers can only be allocated at PASSIVE_LEVEL 1502 * and we're currently at DISPATCH_LEVEL. The following code has 1503 * two code paths: 1504 * 1505 * - If there is no adapter queued for map register allocation, 1506 * try to see if enough contiguous map registers are present. 1507 * In case they're we can just get them and proceed further. 1508 * 1509 * - If some adapter is already present in the queue we must 1510 * respect the order of adapters asking for map registers and 1511 * so the fast case described above can't take place. 1512 * This case is also entered if not enough coniguous map 1513 * registers are present. 1514 * 1515 * A work queue item is allocated and queued, the adapter is 1516 * also queued into the master adapter queue. The worker 1517 * routine does the job of allocating the map registers at 1518 * PASSIVE_LEVEL and calling the ExecutionRoutine. 1519 */ 1520 1521 KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); 1522 1523 if (IsListEmpty(&MasterAdapter->AdapterQueue)) 1524 { 1525 Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, NumberOfMapRegisters, 0); 1526 if (Index != MAXULONG) 1527 { 1528 AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; 1529 if (!AdapterObject->ScatterGather) 1530 { 1531 AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); 1532 } 1533 } 1534 } 1535 1536 if (Index == MAXULONG) 1537 { 1538 InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); 1539 1540 WorkItem = ExAllocatePoolWithTag(NonPagedPool, 1541 sizeof(GROW_WORK_ITEM), 1542 TAG_DMA); 1543 if (WorkItem) 1544 { 1545 ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem); 1546 WorkItem->AdapterObject = AdapterObject; 1547 WorkItem->NumberOfMapRegisters = NumberOfMapRegisters; 1548 1549 ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); 1550 } 1551 1552 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1553 1554 return STATUS_SUCCESS; 1555 } 1556 1557 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1558 } 1559 else 1560 { 1561 AdapterObject->MapRegisterBase = NULL; 1562 AdapterObject->NumberOfMapRegisters = 0; 1563 } 1564 1565 AdapterObject->CurrentWcb = WaitContextBlock; 1566 1567 Result = ExecutionRoutine(WaitContextBlock->DeviceObject, 1568 WaitContextBlock->CurrentIrp, 1569 AdapterObject->MapRegisterBase, 1570 WaitContextBlock->DeviceContext); 1571 1572 /* 1573 * Possible return values: 1574 * 1575 * - KeepObject 1576 * Don't free any resources, the ADAPTER_OBJECT is still in use and 1577 * the caller will call IoFreeAdapterChannel later. 1578 * 1579 * - DeallocateObject 1580 * Deallocate the map registers and release the ADAPTER_OBJECT, so 1581 * someone else can use it. 1582 * 1583 * - DeallocateObjectKeepRegisters 1584 * Release the ADAPTER_OBJECT, but hang on to the map registers. The 1585 * client will later call IoFreeMapRegisters. 1586 * 1587 * NOTE: 1588 * IoFreeAdapterChannel runs the queue, so it must be called unless 1589 * the adapter object is not to be freed. 1590 */ 1591 if (Result == DeallocateObject) 1592 { 1593 IoFreeAdapterChannel(AdapterObject); 1594 } 1595 else if (Result == DeallocateObjectKeepRegisters) 1596 { 1597 AdapterObject->NumberOfMapRegisters = 0; 1598 IoFreeAdapterChannel(AdapterObject); 1599 } 1600 1601 return STATUS_SUCCESS; 1602 } 1603 1604 /** 1605 * @name IoFreeAdapterChannel 1606 * 1607 * Free DMA resources allocated by IoAllocateAdapterChannel. 1608 * 1609 * @param AdapterObject 1610 * Adapter object with resources to free. 1611 * 1612 * @remarks 1613 * This function releases map registers registers assigned to the DMA 1614 * adapter. After releasing the adapter, it checks the adapter's queue 1615 * and runs each queued device object in series until the queue is 1616 * empty. This is the only way the device queue is emptied. 1617 * 1618 * @see IoAllocateAdapterChannel 1619 * 1620 * @implemented 1621 */ 1622 VOID 1623 NTAPI 1624 IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject) 1625 { 1626 PADAPTER_OBJECT MasterAdapter; 1627 PKDEVICE_QUEUE_ENTRY DeviceQueueEntry; 1628 PWAIT_CONTEXT_BLOCK WaitContextBlock; 1629 ULONG Index = MAXULONG; 1630 ULONG Result; 1631 KIRQL OldIrql; 1632 1633 MasterAdapter = AdapterObject->MasterAdapter; 1634 1635 for (;;) 1636 { 1637 /* 1638 * To keep map registers, call here with AdapterObject-> 1639 * NumberOfMapRegisters set to zero. This trick is used in 1640 * HalAllocateAdapterChannel for example. 1641 */ 1642 if (AdapterObject->NumberOfMapRegisters) 1643 { 1644 IoFreeMapRegisters(AdapterObject, 1645 AdapterObject->MapRegisterBase, 1646 AdapterObject->NumberOfMapRegisters); 1647 } 1648 1649 DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue); 1650 if (!DeviceQueueEntry) break; 1651 1652 WaitContextBlock = CONTAINING_RECORD(DeviceQueueEntry, 1653 WAIT_CONTEXT_BLOCK, 1654 WaitQueueEntry); 1655 1656 AdapterObject->CurrentWcb = WaitContextBlock; 1657 AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters; 1658 1659 if ((WaitContextBlock->NumberOfMapRegisters) && (AdapterObject->MasterAdapter)) 1660 { 1661 KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); 1662 1663 if (IsListEmpty(&MasterAdapter->AdapterQueue)) 1664 { 1665 Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, 1666 WaitContextBlock->NumberOfMapRegisters, 1667 0); 1668 if (Index != MAXULONG) 1669 { 1670 AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; 1671 if (!AdapterObject->ScatterGather) 1672 { 1673 AdapterObject->MapRegisterBase =(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); 1674 } 1675 } 1676 } 1677 1678 if (Index == MAXULONG) 1679 { 1680 InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); 1681 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1682 break; 1683 } 1684 1685 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1686 } 1687 else 1688 { 1689 AdapterObject->MapRegisterBase = NULL; 1690 AdapterObject->NumberOfMapRegisters = 0; 1691 } 1692 1693 /* Call the adapter control routine. */ 1694 Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, 1695 WaitContextBlock->CurrentIrp, 1696 AdapterObject->MapRegisterBase, 1697 WaitContextBlock->DeviceContext); 1698 switch (Result) 1699 { 1700 case KeepObject: 1701 /* 1702 * We're done until the caller manually calls IoFreeAdapterChannel 1703 * or IoFreeMapRegisters. 1704 */ 1705 return; 1706 1707 case DeallocateObjectKeepRegisters: 1708 /* 1709 * Hide the map registers so they aren't deallocated next time 1710 * around. 1711 */ 1712 AdapterObject->NumberOfMapRegisters = 0; 1713 break; 1714 1715 default: 1716 break; 1717 } 1718 } 1719 } 1720 1721 /** 1722 * @name IoFreeMapRegisters 1723 * 1724 * Free map registers reserved by the system for a DMA. 1725 * 1726 * @param AdapterObject 1727 * DMA adapter to free map registers on. 1728 * @param MapRegisterBase 1729 * Handle to map registers to free. 1730 * @param NumberOfRegisters 1731 * Number of map registers to be freed. 1732 * 1733 * @implemented 1734 */ 1735 VOID 1736 NTAPI 1737 IoFreeMapRegisters(IN PADAPTER_OBJECT AdapterObject, 1738 IN PVOID MapRegisterBase, 1739 IN ULONG NumberOfMapRegisters) 1740 { 1741 PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; 1742 PLIST_ENTRY ListEntry; 1743 KIRQL OldIrql; 1744 ULONG Index; 1745 ULONG Result; 1746 1747 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 1748 1749 if (!(MasterAdapter) || !(MapRegisterBase)) return; 1750 1751 KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); 1752 1753 if (NumberOfMapRegisters != 0) 1754 { 1755 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 1756 1757 RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 1758 RtlClearBits(MasterAdapter->MapRegisters, 1759 (ULONG)(RealMapRegisterBase - MasterAdapter->MapRegisterBase), 1760 NumberOfMapRegisters); 1761 } 1762 1763 /* 1764 * Now that we freed few map registers it's time to look at the master 1765 * adapter queue and see if there is someone waiting for map registers. 1766 */ 1767 while (!IsListEmpty(&MasterAdapter->AdapterQueue)) 1768 { 1769 ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue); 1770 AdapterObject = CONTAINING_RECORD(ListEntry, struct _ADAPTER_OBJECT, AdapterQueue); 1771 1772 Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, 1773 AdapterObject->NumberOfMapRegisters, 1774 0); 1775 if (Index == MAXULONG) 1776 { 1777 InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry); 1778 break; 1779 } 1780 1781 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1782 1783 AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; 1784 if (!AdapterObject->ScatterGather) 1785 { 1786 AdapterObject->MapRegisterBase = 1787 (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); 1788 } 1789 1790 Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(AdapterObject->CurrentWcb->DeviceObject, 1791 AdapterObject->CurrentWcb->CurrentIrp, 1792 AdapterObject->MapRegisterBase, 1793 AdapterObject->CurrentWcb->DeviceContext); 1794 switch (Result) 1795 { 1796 case DeallocateObjectKeepRegisters: 1797 AdapterObject->NumberOfMapRegisters = 0; 1798 /* fall through */ 1799 1800 case DeallocateObject: 1801 if (AdapterObject->NumberOfMapRegisters) 1802 { 1803 KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); 1804 RtlClearBits(MasterAdapter->MapRegisters, 1805 (ULONG)(AdapterObject->MapRegisterBase - 1806 MasterAdapter->MapRegisterBase), 1807 AdapterObject->NumberOfMapRegisters); 1808 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1809 } 1810 1811 IoFreeAdapterChannel(AdapterObject); 1812 break; 1813 1814 default: 1815 break; 1816 } 1817 1818 KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); 1819 } 1820 1821 KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); 1822 } 1823 1824 /** 1825 * @name HalpCopyBufferMap 1826 * 1827 * Helper function for copying data from/to map register buffers. 1828 * 1829 * @see IoFlushAdapterBuffers, IoMapTransfer 1830 */ 1831 VOID 1832 NTAPI 1833 HalpCopyBufferMap(IN PMDL Mdl, 1834 IN PROS_MAP_REGISTER_ENTRY MapRegisterBase, 1835 IN PVOID CurrentVa, 1836 IN ULONG Length, 1837 IN BOOLEAN WriteToDevice) 1838 { 1839 ULONG CurrentLength; 1840 ULONG_PTR CurrentAddress; 1841 ULONG ByteOffset; 1842 PVOID VirtualAddress; 1843 1844 VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority); 1845 if (!VirtualAddress) 1846 { 1847 /* 1848 * NOTE: On real NT a mechanism with reserved pages is implemented 1849 * to handle this case in a slow, but graceful non-fatal way. 1850 */ 1851 KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); 1852 } 1853 1854 CurrentAddress = (ULONG_PTR)VirtualAddress + 1855 (ULONG_PTR)CurrentVa - 1856 (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); 1857 1858 while (Length > 0) 1859 { 1860 ByteOffset = BYTE_OFFSET(CurrentAddress); 1861 CurrentLength = PAGE_SIZE - ByteOffset; 1862 if (CurrentLength > Length) CurrentLength = Length; 1863 1864 if (WriteToDevice) 1865 { 1866 RtlCopyMemory((PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), 1867 (PVOID)CurrentAddress, 1868 CurrentLength); 1869 } 1870 else 1871 { 1872 RtlCopyMemory((PVOID)CurrentAddress, 1873 (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), 1874 CurrentLength); 1875 } 1876 1877 Length -= CurrentLength; 1878 CurrentAddress += CurrentLength; 1879 MapRegisterBase++; 1880 } 1881 } 1882 1883 /** 1884 * @name IoFlushAdapterBuffers 1885 * 1886 * Flush any data remaining in the DMA controller's memory into the host 1887 * memory. 1888 * 1889 * @param AdapterObject 1890 * The adapter object to flush. 1891 * @param Mdl 1892 * Original MDL to flush data into. 1893 * @param MapRegisterBase 1894 * Map register base that was just used by IoMapTransfer, etc. 1895 * @param CurrentVa 1896 * Offset into Mdl to be flushed into, same as was passed to 1897 * IoMapTransfer. 1898 * @param Length 1899 * Length of the buffer to be flushed into. 1900 * @param WriteToDevice 1901 * TRUE if it's a write, FALSE if it's a read. 1902 * 1903 * @return TRUE in all cases. 1904 * 1905 * @remarks 1906 * This copies data from the map register-backed buffer to the user's 1907 * target buffer. Data are not in the user buffer until this function 1908 * is called. 1909 * For slave DMA transfers the controller channel is masked effectively 1910 * stopping the current transfer. 1911 * 1912 * @unimplemented. 1913 */ 1914 BOOLEAN 1915 NTAPI 1916 IoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject, 1917 IN PMDL Mdl, 1918 IN PVOID MapRegisterBase, 1919 IN PVOID CurrentVa, 1920 IN ULONG Length, 1921 IN BOOLEAN WriteToDevice) 1922 { 1923 BOOLEAN SlaveDma = FALSE; 1924 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 1925 PHYSICAL_ADDRESS HighestAcceptableAddress; 1926 PHYSICAL_ADDRESS PhysicalAddress; 1927 PPFN_NUMBER MdlPagesPtr; 1928 1929 /* Sanity checks */ 1930 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1931 ASSERT(AdapterObject); 1932 1933 if (!AdapterObject->MasterDevice) 1934 { 1935 /* Mask out (disable) the DMA channel. */ 1936 if (AdapterObject->AdapterNumber == 1) 1937 { 1938 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 1939 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, 1940 AdapterObject->ChannelNumber | DMA_SETMASK); 1941 } 1942 else 1943 { 1944 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 1945 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, 1946 AdapterObject->ChannelNumber | DMA_SETMASK); 1947 } 1948 SlaveDma = TRUE; 1949 } 1950 1951 /* This can happen if the device supports hardware scatter/gather. */ 1952 if (MapRegisterBase == NULL) return TRUE; 1953 1954 RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 1955 1956 if (!WriteToDevice) 1957 { 1958 if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) 1959 { 1960 if (RealMapRegisterBase->Counter != MAXULONG) 1961 { 1962 if ((SlaveDma) && !(AdapterObject->IgnoreCount)) 1963 { 1964 Length -= HalReadDmaCounter(AdapterObject); 1965 } 1966 } 1967 HalpCopyBufferMap(Mdl, 1968 RealMapRegisterBase, 1969 CurrentVa, 1970 Length, 1971 FALSE); 1972 } 1973 else 1974 { 1975 MdlPagesPtr = MmGetMdlPfnArray(Mdl); 1976 MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; 1977 1978 PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; 1979 PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa); 1980 1981 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 1982 if ((PhysicalAddress.QuadPart + Length) > HighestAcceptableAddress.QuadPart) 1983 { 1984 HalpCopyBufferMap(Mdl, 1985 RealMapRegisterBase, 1986 CurrentVa, 1987 Length, 1988 FALSE); 1989 } 1990 } 1991 } 1992 1993 RealMapRegisterBase->Counter = 0; 1994 1995 return TRUE; 1996 } 1997 1998 /** 1999 * @name IoMapTransfer 2000 * 2001 * Map a DMA for transfer and do the DMA if it's a slave. 2002 * 2003 * @param AdapterObject 2004 * Adapter object to do the DMA on. Bus-master may pass NULL. 2005 * @param Mdl 2006 * Locked-down user buffer to DMA in to or out of. 2007 * @param MapRegisterBase 2008 * Handle to map registers to use for this dma. 2009 * @param CurrentVa 2010 * Index into Mdl to transfer into/out of. 2011 * @param Length 2012 * Length of transfer. Number of bytes actually transferred on 2013 * output. 2014 * @param WriteToDevice 2015 * TRUE if it's an output DMA, FALSE otherwise. 2016 * 2017 * @return 2018 * A logical address that can be used to program a DMA controller, it's 2019 * not meaningful for slave DMA device. 2020 * 2021 * @remarks 2022 * This function does a copyover to contiguous memory <16MB represented 2023 * by the map registers if needed. If the buffer described by MDL can be 2024 * used as is no copyover is done. 2025 * If it's a slave transfer, this function actually performs it. 2026 * 2027 * @implemented 2028 */ 2029 PHYSICAL_ADDRESS 2030 NTAPI 2031 IoMapTransfer(IN PADAPTER_OBJECT AdapterObject, 2032 IN PMDL Mdl, 2033 IN PVOID MapRegisterBase, 2034 IN PVOID CurrentVa, 2035 IN OUT PULONG Length, 2036 IN BOOLEAN WriteToDevice) 2037 { 2038 PPFN_NUMBER MdlPagesPtr; 2039 PFN_NUMBER MdlPage1, MdlPage2; 2040 ULONG ByteOffset; 2041 ULONG TransferOffset; 2042 ULONG TransferLength; 2043 BOOLEAN UseMapRegisters; 2044 PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; 2045 PHYSICAL_ADDRESS PhysicalAddress; 2046 PHYSICAL_ADDRESS HighestAcceptableAddress; 2047 ULONG Counter; 2048 DMA_MODE AdapterMode; 2049 KIRQL OldIrql; 2050 2051 /* 2052 * Precalculate some values that are used in all cases. 2053 * 2054 * ByteOffset is offset inside the page at which the transfer starts. 2055 * MdlPagesPtr is pointer inside the MDL page chain at the page where the 2056 * transfer start. 2057 * PhysicalAddress is physical address corresponding to the transfer 2058 * start page and offset. 2059 * TransferLength is the initial length of the transfer, which is reminder 2060 * of the first page. The actual value is calculated below. 2061 * 2062 * Note that all the variables can change during the processing which 2063 * takes place below. These are just initial values. 2064 */ 2065 ByteOffset = BYTE_OFFSET(CurrentVa); 2066 2067 MdlPagesPtr = MmGetMdlPfnArray(Mdl); 2068 MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; 2069 2070 PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; 2071 PhysicalAddress.QuadPart += ByteOffset; 2072 2073 TransferLength = PAGE_SIZE - ByteOffset; 2074 2075 /* 2076 * Special case for bus master adapters with S/G support. We can directly 2077 * use the buffer specified by the MDL, so not much work has to be done. 2078 * 2079 * Just return the passed VA's corresponding physical address and update 2080 * length to the number of physically contiguous bytes found. Also 2081 * pages crossing the 4Gb boundary aren't considered physically contiguous. 2082 */ 2083 if (MapRegisterBase == NULL) 2084 { 2085 while (TransferLength < *Length) 2086 { 2087 MdlPage1 = *MdlPagesPtr; 2088 MdlPage2 = *(MdlPagesPtr + 1); 2089 if (MdlPage1 + 1 != MdlPage2) break; 2090 if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) break; 2091 TransferLength += PAGE_SIZE; 2092 MdlPagesPtr++; 2093 } 2094 2095 if (TransferLength < *Length) *Length = TransferLength; 2096 2097 return PhysicalAddress; 2098 } 2099 2100 /* 2101 * The code below applies to slave DMA adapters and bus master adapters 2102 * without hardward S/G support. 2103 */ 2104 RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); 2105 2106 /* 2107 * Try to calculate the size of the transfer. We can only transfer 2108 * pages that are physically contiguous and that don't cross the 2109 * 64Kb boundary (this limitation applies only for ISA controllers). 2110 */ 2111 while (TransferLength < *Length) 2112 { 2113 MdlPage1 = *MdlPagesPtr; 2114 MdlPage2 = *(MdlPagesPtr + 1); 2115 if (MdlPage1 + 1 != MdlPage2) break; 2116 if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) break; 2117 TransferLength += PAGE_SIZE; 2118 MdlPagesPtr++; 2119 } 2120 2121 if (TransferLength > *Length) TransferLength = *Length; 2122 2123 /* 2124 * If we're about to simulate software S/G and not all the pages are 2125 * physically contiguous then we must use the map registers to store 2126 * the data and allow the whole transfer to proceed at once. 2127 */ 2128 if (((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) && (TransferLength < *Length)) 2129 { 2130 UseMapRegisters = TRUE; 2131 PhysicalAddress = RealMapRegisterBase->PhysicalAddress; 2132 PhysicalAddress.QuadPart += ByteOffset; 2133 TransferLength = *Length; 2134 RealMapRegisterBase->Counter = MAXULONG; 2135 Counter = 0; 2136 } 2137 else 2138 { 2139 /* 2140 * This is ordinary DMA transfer, so just update the progress 2141 * counters. These are used by IoFlushAdapterBuffers to track 2142 * the transfer progress. 2143 */ 2144 UseMapRegisters = FALSE; 2145 Counter = RealMapRegisterBase->Counter; 2146 RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength); 2147 2148 /* 2149 * Check if the buffer doesn't exceed the highest physical address 2150 * limit of the device. In that case we must use the map registers to 2151 * store the data. 2152 */ 2153 HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); 2154 if ((PhysicalAddress.QuadPart + TransferLength) > HighestAcceptableAddress.QuadPart) 2155 { 2156 UseMapRegisters = TRUE; 2157 PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress; 2158 PhysicalAddress.QuadPart += ByteOffset; 2159 if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) 2160 { 2161 RealMapRegisterBase->Counter = MAXULONG; 2162 Counter = 0; 2163 } 2164 } 2165 } 2166 2167 /* 2168 * If we decided to use the map registers (see above) and we're about 2169 * to transfer data to the device then copy the buffers into the map 2170 * register memory. 2171 */ 2172 if ((UseMapRegisters) && (WriteToDevice)) 2173 { 2174 HalpCopyBufferMap(Mdl, 2175 RealMapRegisterBase + Counter, 2176 CurrentVa, 2177 TransferLength, 2178 WriteToDevice); 2179 } 2180 2181 /* 2182 * Return the length of transfer that actually takes place. 2183 */ 2184 *Length = TransferLength; 2185 2186 /* 2187 * If we're doing slave (system) DMA then program the (E)ISA controller 2188 * to actually start the transfer. 2189 */ 2190 if ((AdapterObject) && !(AdapterObject->MasterDevice)) 2191 { 2192 AdapterMode = AdapterObject->AdapterMode; 2193 2194 if (WriteToDevice) 2195 { 2196 AdapterMode.TransferType = WRITE_TRANSFER; 2197 } 2198 else 2199 { 2200 AdapterMode.TransferType = READ_TRANSFER; 2201 if (AdapterObject->IgnoreCount) 2202 { 2203 RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + ByteOffset, 2204 TransferLength); 2205 } 2206 } 2207 2208 TransferOffset = PhysicalAddress.LowPart & 0xFFFF; 2209 if (AdapterObject->Width16Bits) 2210 { 2211 TransferLength >>= 1; 2212 TransferOffset >>= 1; 2213 } 2214 2215 KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); 2216 2217 if (AdapterObject->AdapterNumber == 1) 2218 { 2219 PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; 2220 2221 /* Reset Register */ 2222 WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); 2223 2224 /* Set the Mode */ 2225 WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte); 2226 2227 /* Set the Offset Register */ 2228 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 2229 (UCHAR)(TransferOffset)); 2230 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 2231 (UCHAR)(TransferOffset >> 8)); 2232 2233 /* Set the Page Register */ 2234 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), 2235 (UCHAR)(PhysicalAddress.LowPart >> 16)); 2236 if (HalpEisaDma) 2237 { 2238 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 2239 0); 2240 } 2241 2242 /* Set the Length */ 2243 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 2244 (UCHAR)(TransferLength - 1)); 2245 WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 2246 (UCHAR)((TransferLength - 1) >> 8)); 2247 2248 /* Unmask the Channel */ 2249 WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); 2250 } 2251 else 2252 { 2253 PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; 2254 2255 /* Reset Register */ 2256 WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); 2257 2258 /* Set the Mode */ 2259 WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte); 2260 2261 /* Set the Offset Register */ 2262 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 2263 (UCHAR)(TransferOffset)); 2264 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, 2265 (UCHAR)(TransferOffset >> 8)); 2266 2267 /* Set the Page Register */ 2268 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), 2269 (UCHAR)(PhysicalAddress.u.LowPart >> 16)); 2270 if (HalpEisaDma) 2271 { 2272 WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), 2273 0); 2274 } 2275 2276 /* Set the Length */ 2277 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 2278 (UCHAR)(TransferLength - 1)); 2279 WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, 2280 (UCHAR)((TransferLength - 1) >> 8)); 2281 2282 /* Unmask the Channel */ 2283 WRITE_PORT_UCHAR(&DmaControl2->SingleMask, 2284 AdapterObject->ChannelNumber | DMA_CLEARMASK); 2285 } 2286 2287 KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); 2288 } 2289 2290 /* 2291 * Return physical address of the buffer with data that is used for the 2292 * transfer. It can either point inside the Mdl that was passed by the 2293 * caller or into the map registers if the Mdl buffer can't be used 2294 * directly. 2295 */ 2296 return PhysicalAddress; 2297 } 2298 #endif 2299 2300 /** 2301 * @name HalFlushCommonBuffer 2302 * 2303 * @implemented 2304 */ 2305 BOOLEAN 2306 NTAPI 2307 HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject, 2308 IN ULONG Length, 2309 IN PHYSICAL_ADDRESS LogicalAddress, 2310 IN PVOID VirtualAddress) 2311 { 2312 /* Function always returns true */ 2313 return TRUE; 2314 } 2315 2316 /* 2317 * @implemented 2318 */ 2319 PVOID 2320 NTAPI 2321 HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject, 2322 IN OUT PULONG NumberOfMapRegisters) 2323 { 2324 PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; 2325 ULONG MapRegisterNumber; 2326 2327 /* Check if it needs map registers */ 2328 if (AdapterObject->NeedsMapRegisters) 2329 { 2330 /* Check if we have enough */ 2331 if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) 2332 { 2333 /* We don't, fail */ 2334 AdapterObject->NumberOfMapRegisters = 0; 2335 return NULL; 2336 } 2337 2338 /* Try to find free map registers */ 2339 MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, 2340 *NumberOfMapRegisters, 2341 0); 2342 2343 /* Check if nothing was found */ 2344 if (MapRegisterNumber == MAXULONG) 2345 { 2346 /* No free registers found, so use the base registers */ 2347 RtlSetBits(MasterAdapter->MapRegisters, 2348 0, 2349 *NumberOfMapRegisters); 2350 MapRegisterNumber = 0; 2351 } 2352 2353 /* Calculate the new base */ 2354 AdapterObject->MapRegisterBase = 2355 (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase + 2356 MapRegisterNumber); 2357 2358 /* Check if scatter gather isn't supported */ 2359 if (!AdapterObject->ScatterGather) 2360 { 2361 /* Set the flag */ 2362 AdapterObject->MapRegisterBase = 2363 (PROS_MAP_REGISTER_ENTRY) 2364 ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); 2365 } 2366 } 2367 else 2368 { 2369 AdapterObject->MapRegisterBase = NULL; 2370 AdapterObject->NumberOfMapRegisters = 0; 2371 } 2372 2373 /* Return the base */ 2374 return AdapterObject->MapRegisterBase; 2375 } 2376 2377 /* EOF */ 2378