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