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