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