Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
IOPCIFamily/PEX8733/PCIDriverKitPEX8733/PCIDriverKitPEX8733.cpp
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
504 lines (421 sloc)
23.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // PCIDriverKitPEX8733.cpp | |
| // PCIDriverKitPEX8733 | |
| // | |
| // Created by Kevin Strasberg on 10/29/19. | |
| // | |
| #include <stdio.h> | |
| #include <os/log.h> | |
| #include <DriverKit/IOLib.h> | |
| #include <DriverKit/DriverKit.h> | |
| #include <PCIDriverKit/PCIDriverKit.h> | |
| #include "PCIDriverKitPEX8733.h" | |
| #include "PEX8733Definitions.h" | |
| #define debugLog(fmt, args...) os_log(OS_LOG_DEFAULT, "PCIDriverKitPEX8733::%s: " fmt, __FUNCTION__,##args) | |
| struct PCIDriverKitPEX8733_IVars | |
| { | |
| IOPCIDevice* pciDevice; | |
| IOInterruptDispatchSource* interruptSource; | |
| IODispatchQueue* defaultQueue; | |
| uint64_t vendorCapabilityOffset; | |
| PEX8733TestMode currentTest; | |
| IOBufferMemoryDescriptor* blockTransferBuffer; | |
| IODMACommand* blockTransferDMA; | |
| IOBufferMemoryDescriptor** descriptorTransferBuffers; | |
| IODMACommand** descriptorTransferDMAs; | |
| IOBufferMemoryDescriptor* ringBuffer; | |
| IODMACommand* ringBufferDMA; | |
| }; | |
| bool | |
| PCIDriverKitPEX8733::init() | |
| { | |
| if(super::init() != true) | |
| { | |
| return false; | |
| } | |
| ivars = IONewZero(PCIDriverKitPEX8733_IVars, 1); | |
| if(ivars == NULL) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| void | |
| PCIDriverKitPEX8733::free() | |
| { | |
| IOSafeDeleteNULL(ivars, PCIDriverKitPEX8733_IVars, 1); | |
| super::free(); | |
| } | |
| kern_return_t | |
| IMPL(PCIDriverKitPEX8733, Start) | |
| { | |
| kern_return_t result = Start(provider, SUPERDISPATCH); | |
| if(result != kIOReturnSuccess) | |
| { | |
| return result; | |
| } | |
| ivars->pciDevice = OSDynamicCast(IOPCIDevice, provider); | |
| if(ivars->pciDevice == NULL) | |
| { | |
| Stop(provider); | |
| return kIOReturnNoDevice; | |
| } | |
| ivars->pciDevice->retain(); | |
| if(ivars->pciDevice->Open(this, 0) != kIOReturnSuccess) | |
| { | |
| Stop(provider); | |
| return kIOReturnNoDevice; | |
| } | |
| uint8_t functionNumber = 0; | |
| if(ivars->pciDevice->GetBusDeviceFunction(NULL, NULL, &functionNumber) != kIOReturnSuccess) | |
| { | |
| debugLog("unable to get B:D:F"); | |
| Stop(provider); | |
| return false; | |
| } | |
| if(functionNumber != 1) | |
| { | |
| debugLog("skipping function %u", functionNumber); | |
| Stop(provider); | |
| return false; | |
| } | |
| debugLog("Kevin enabling bus master and memory space"); | |
| uint16_t command; | |
| ivars->pciDevice->ConfigurationRead16(kIOPCIConfigurationOffsetCommand, &command); | |
| ivars->pciDevice->ConfigurationWrite16(kIOPCIConfigurationOffsetCommand, | |
| command | kIOPCICommandBusMaster | kIOPCICommandMemorySpace); | |
| ivars->pciDevice->FindPCICapability(kPEX8733DMAChannelCapabilityID, 0, &(ivars->vendorCapabilityOffset)); | |
| // for now only allow 1 channel | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelGlobalControlOffset, | |
| kPEX8733DMAChannelGlobalControlModeOne); | |
| if(CopyDispatchQueue("Default", &(ivars->defaultQueue)) != kIOReturnSuccess) | |
| { | |
| debugLog("failed to copy queue"); | |
| Stop(provider); | |
| return false; | |
| } | |
| if(IOInterruptDispatchSource::Create(ivars->pciDevice, 1, ivars->defaultQueue, &(ivars->interruptSource)) != kIOReturnSuccess) | |
| { | |
| debugLog("failed to create interrupt dispatch source"); | |
| Stop(provider); | |
| return false; | |
| } | |
| OSAction* action; | |
| if(CreateActionInterruptOccurred(sizeof(void*), &action) != kIOReturnSuccess) | |
| { | |
| debugLog("failed to create interrupt action"); | |
| Stop(provider); | |
| return false; | |
| } | |
| if(ivars->interruptSource->SetHandler(action) != kIOReturnSuccess) | |
| { | |
| debugLog("failed to set interrupt handler"); | |
| Stop(provider); | |
| return false; | |
| } | |
| ivars->interruptSource->SetEnable(true); | |
| // temporary hack to synchronize the bridge bus mastering is enabled before issue'ing DMA's | |
| IOSleep(1000); | |
| dmaBlockTransferTest(); | |
| // dmaDescriptorTransferTest(); | |
| return result; | |
| } | |
| kern_return_t | |
| IMPL(PCIDriverKitPEX8733, Stop) | |
| { | |
| debugLog("disabling bus master and memory space"); | |
| if(ivars->pciDevice != NULL) | |
| { | |
| uint16_t command; | |
| ivars->pciDevice->ConfigurationRead16(kIOPCIConfigurationOffsetCommand, &command); | |
| ivars->pciDevice->ConfigurationWrite16(kIOPCIConfigurationOffsetCommand, | |
| command & ~(kIOPCICommandBusMaster | kIOPCICommandMemorySpace)); | |
| } | |
| OSSafeReleaseNULL(ivars->pciDevice); | |
| return Stop(provider, SUPERDISPATCH); | |
| } | |
| void | |
| IMPL(PCIDriverKitPEX8733, InterruptOccurred) | |
| { | |
| uint32_t interruptControlStatus = 0; | |
| // Wait for transfer to complete | |
| ivars->pciDevice->ConfigurationRead32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelInterruptControlStatusRegisterOffset, | |
| &interruptControlStatus); | |
| debugLog("interrupt control status 0x%x\n", interruptControlStatus); | |
| if((interruptControlStatus & (kPEX8733DMAChannelInterruptControlStatusDescriptorDoneInterruptStatus | |
| | kPEX8733DMAChannelInterruptControlStatusErrorInterruptStatus | |
| | kPEX8733DMAChannelInterruptControlStatusInvalidDescriptorInterruptStatus | |
| | kPEX8733DMAChannelInterruptControlStatusGracefulPauseDoneInterruptStatus | |
| | kPEX8733DMAChannelInterruptControlStatusImmediatePauseDoneInterruptStatus)) != 0) | |
| { | |
| switch(ivars->currentTest) | |
| { | |
| case kPEX8733TestModeBlock: | |
| { | |
| if (ivars->blockTransferDMA) | |
| { | |
| ivars->blockTransferDMA->CompleteDMA(kIODMACommandCompleteDMANoOptions); | |
| } | |
| IOAddressSegment virtualAddressSegment = { 0 }; | |
| ivars->blockTransferBuffer->GetAddressRange(&virtualAddressSegment); | |
| if(memcmp(reinterpret_cast<void*>(virtualAddressSegment.address), | |
| reinterpret_cast<void*>(virtualAddressSegment.address + (IOVMPageSize * kPEX8733DefaultTestTransferSizeNumPages / 2)), | |
| (IOVMPageSize * kPEX8733DefaultTestTransferSizeNumPages / 2)) != 0) | |
| { | |
| debugLog("source and destination do not match\n"); | |
| } | |
| else | |
| { | |
| debugLog("dma successful\n"); | |
| } | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelSourceAddressLowerOffset, | |
| 0); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelSourceAddressUpperOffset, | |
| 0); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDestinationAddressLowerOffset, | |
| 0); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDestinationAddressUpperOffset, | |
| 0); | |
| OSSafeReleaseNULL(ivars->blockTransferDMA); | |
| OSSafeReleaseNULL(ivars->blockTransferBuffer); | |
| ivars->currentTest = kPEX8733TestModeNone; | |
| // start the next test | |
| dmaDescriptorTransferTest(); | |
| break; | |
| } | |
| case kPEX8733TestModeDescriptor: | |
| { | |
| for(int j = 0; j < kPEX8733DefaultNumDMADescriptors; j++) | |
| { | |
| for(unsigned int i = 0; i < kPEX8733DefaultNumDMADescriptors; i++) | |
| { | |
| if (ivars->descriptorTransferDMAs[i]) | |
| { | |
| ivars->descriptorTransferDMAs[i]->CompleteDMA(kIODMACommandCompleteDMANoOptions); | |
| } | |
| } | |
| IOAddressSegment descriptorBufferVirtualAddressSegment = { 0 }; | |
| ivars->descriptorTransferBuffers[j]->GetAddressRange(&descriptorBufferVirtualAddressSegment); | |
| if(memcmp(reinterpret_cast<void*>(descriptorBufferVirtualAddressSegment.address), | |
| reinterpret_cast<void*>(descriptorBufferVirtualAddressSegment.address + (descriptorBufferVirtualAddressSegment.length / 2)), | |
| (descriptorBufferVirtualAddressSegment.length / 2)) != 0) | |
| { | |
| debugLog("descriptor [%u]: source and destination do not match\n", j); | |
| } | |
| else | |
| { | |
| debugLog("dma[%u] successful\n", j); | |
| } | |
| } | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingAddressLowerOffset, | |
| 0); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingAddressUpperOffset, | |
| 0); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingNextDescriptorAddressLowerOffset, | |
| 0); | |
| OSSafeReleaseNULL(ivars->ringBufferDMA); | |
| OSSafeReleaseNULL(ivars->ringBuffer); | |
| for(unsigned int i = 0; i < kPEX8733DefaultNumDMADescriptors; i++) | |
| { | |
| OSSafeReleaseNULL(ivars->descriptorTransferDMAs[i]); | |
| OSSafeReleaseNULL(ivars->descriptorTransferBuffers[i]); | |
| } | |
| IODelete(ivars->descriptorTransferBuffers, IOBufferMemoryDescriptor*, kPEX8733DefaultNumDMADescriptors); | |
| IODelete(ivars->descriptorTransferDMAs, IODMACommand*, kPEX8733DefaultNumDMADescriptors); | |
| ivars->currentTest = kPEX8733TestModeNone; | |
| debugLog("Tests complete"); | |
| break; | |
| } | |
| default: | |
| { | |
| debugLog("unkown test"); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| kern_return_t | |
| PCIDriverKitPEX8733::dmaBlockTransferTest() | |
| { | |
| ivars->currentTest = kPEX8733TestModeBlock; | |
| debugLog("starting dmaBlockTransferTest\n"); | |
| kern_return_t result = kIOReturnSuccess; | |
| uint64_t bufferCapacity = IOVMPageSize * kPEX8733DefaultTestTransferSizeNumPages; | |
| uint64_t bufferAlignment = IOVMPageSize; | |
| IOAddressSegment virtualAddressSegment = { 0 }; | |
| IOAddressSegment physicalAddressSegment = { 0 }; | |
| uint64_t dmaFlags = 0; | |
| uint32_t dmaSegmentCount = 1; | |
| IOBufferMemoryDescriptor::Create(kIOMemoryDirectionOutIn, | |
| bufferCapacity, | |
| bufferAlignment, | |
| &(ivars->blockTransferBuffer)); | |
| ivars->blockTransferBuffer->SetLength(bufferCapacity); | |
| ivars->blockTransferBuffer->GetAddressRange(&virtualAddressSegment); | |
| // Populate the first half of the buffer with data to be written to the 2nd half | |
| uint64_t transferSize = virtualAddressSegment.length / 2; | |
| for(unsigned int i = 0; i < transferSize; i++) | |
| { | |
| reinterpret_cast<uint8_t*>(virtualAddressSegment.address)[i] = i % 0xFF; | |
| } | |
| IODMACommandSpecification dmaSpecification; | |
| bzero(&dmaSpecification, sizeof(dmaSpecification)); | |
| dmaSpecification.options = kIODMACommandSpecificationNoOptions; | |
| dmaSpecification.maxAddressBits = 64; | |
| IODMACommand::Create(ivars->pciDevice, kIODMACommandCreateNoOptions, &dmaSpecification, &(ivars->blockTransferDMA)); | |
| ivars->blockTransferDMA->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, | |
| ivars->blockTransferBuffer, | |
| 0, | |
| 0, | |
| &dmaFlags, | |
| &dmaSegmentCount, | |
| &physicalAddressSegment); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelSourceAddressLowerOffset, | |
| static_cast<uint32_t>(physicalAddressSegment.address)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelSourceAddressUpperOffset, | |
| static_cast<uint32_t>(physicalAddressSegment.address >> 32)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDestinationAddressLowerOffset, | |
| static_cast<uint32_t>(physicalAddressSegment.address + transferSize)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDestinationAddressUpperOffset, | |
| static_cast<uint32_t>((physicalAddressSegment.address + transferSize) >> 32)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelTransferSizeOffset, | |
| kPEX8733DMAChannelTransferSizeRegisterDMAValid | |
| | kPEX8733DMAChannelTransferSizeRegisterDoneInterruptEnable | |
| | (transferSize & kPEX8733DMAChannelTransferSizeRegisterTransferSizeRange)); | |
| uint32_t interruptControlStatus = 0; | |
| ivars->pciDevice->ConfigurationRead32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelInterruptControlStatusRegisterOffset, | |
| &interruptControlStatus); | |
| // clear interrupts (clear on write) | |
| interruptControlStatus |= kPEX8733DMAChannelInterruptControlStatusInterruptStatusRange; | |
| // enable interrupts | |
| interruptControlStatus |= kPEX8733DMAChannelInterruptControlStatusErrorInterruptEnable | |
| | kPEX8733DMAChannelInterruptControlStatusInvalidDescriptorInterruptEnable | |
| | kPEX8733DMAChannelInterruptControlStatusGracefulPauseDoneInterruptEnable | |
| | kPEX8733DMAChannelInterruptControlStatusImmediatePauseDoneInterruptEnable; | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelInterruptControlStatusRegisterOffset, | |
| interruptControlStatus); | |
| // Enable DMA Block Mode, disable descriptor completion status writeback, and clear any active status bits | |
| uint32_t controlStatus = 0; | |
| ivars->pciDevice->ConfigurationRead32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelControlStatusRegisterOffset, | |
| &controlStatus); | |
| controlStatus &= (~kPEX8733DMAChannelControlStatusDescriptorModeSelectRange); | |
| controlStatus &= ~kPEX8733DMAChannelControlStatusCompletionStatusWriteBackEnable; | |
| controlStatus |= kPEX8733DMAChannelControlStatusStart | kPEX8733DMAChannelControlStatusDescriptorModeSelectBlockMode; | |
| // clear any active status bits | |
| controlStatus |= kPEX8733DMAChannelControlStatusRange | kPEX8733DMAChannelControlStatusHeaderLoggingValid; | |
| // start DMA transfer | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelControlStatusRegisterOffset, | |
| controlStatus); | |
| return result; | |
| } | |
| kern_return_t | |
| PCIDriverKitPEX8733::dmaDescriptorTransferTest() | |
| { | |
| ivars->currentTest = kPEX8733TestModeDescriptor; | |
| debugLog("starting dmaDescriptorTransferTest\n"); | |
| kern_return_t result = kIOReturnSuccess; | |
| unsigned int numDescriptors = kPEX8733DefaultNumDMADescriptors; | |
| uint64_t transferBufferSize = IOVMPageSize * kPEX8733DefaultTestTransferSizeNumPages; | |
| uint64_t transferBufferAlignment = IOVMPageSize; | |
| IOAddressSegment ringBufferVirtualAddressSegment = { 0 }; | |
| IOAddressSegment ringBufferPhysicalAddressSegment = { 0 }; | |
| uint64_t ringDmaFlags = 0; | |
| uint32_t ringDmaSegmentCount = 1; | |
| ivars->descriptorTransferBuffers = IONew(IOBufferMemoryDescriptor*, numDescriptors); | |
| ivars->descriptorTransferDMAs = IONew(IODMACommand*, numDescriptors); | |
| IOBufferMemoryDescriptor::Create(kIOMemoryDirectionOut, | |
| numDescriptors * sizeof(DMAStandardDescriptor), | |
| transferBufferAlignment, | |
| &ivars->ringBuffer); | |
| ivars->ringBuffer->SetLength(numDescriptors * sizeof(DMAStandardDescriptor)); | |
| ivars->ringBuffer->GetAddressRange(&ringBufferVirtualAddressSegment); | |
| IODMACommandSpecification dmaSpecification; | |
| bzero(&dmaSpecification, sizeof(dmaSpecification)); | |
| dmaSpecification.options = kIODMACommandSpecificationNoOptions; | |
| dmaSpecification.maxAddressBits = 64; | |
| IODMACommand::Create(ivars->pciDevice, kIODMACommandCreateNoOptions, &dmaSpecification, &(ivars->ringBufferDMA)); | |
| ivars->ringBufferDMA->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, | |
| ivars->ringBuffer, | |
| 0, | |
| 0, | |
| &ringDmaFlags, | |
| &ringDmaSegmentCount, | |
| &ringBufferPhysicalAddressSegment); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingAddressLowerOffset, | |
| static_cast<uint32_t>(ringBufferPhysicalAddressSegment.address)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingAddressUpperOffset, | |
| static_cast<uint32_t>(ringBufferPhysicalAddressSegment.address >> 32)); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingNextDescriptorAddressLowerOffset, | |
| static_cast<uint32_t>(ringBufferPhysicalAddressSegment.address)); | |
| DMAStandardDescriptor* descriptorRing = reinterpret_cast<DMAStandardDescriptor*>(ringBufferVirtualAddressSegment.address); | |
| for(unsigned int i = 0; i < numDescriptors; i++) | |
| { | |
| IOAddressSegment descriptorBufferVirtualAddressSegment = { 0 }; | |
| IOAddressSegment descriptorBufferPhysicalAddressSegment = { 0 }; | |
| uint64_t dmaFlags = 0; | |
| uint32_t dmaSegmentCount = 1; | |
| IOBufferMemoryDescriptor::Create(kIOMemoryDirectionOutIn, | |
| transferBufferSize, | |
| transferBufferAlignment, | |
| &ivars->descriptorTransferBuffers[i]); | |
| ivars->descriptorTransferBuffers[i]->SetLength(transferBufferSize); | |
| ivars->descriptorTransferBuffers[i]->GetAddressRange(&descriptorBufferVirtualAddressSegment); | |
| IODMACommandSpecification dmaSpecification; | |
| bzero(&dmaSpecification, sizeof(dmaSpecification)); | |
| dmaSpecification.options = kIODMACommandSpecificationNoOptions; | |
| dmaSpecification.maxAddressBits = 64; | |
| IODMACommand::Create(ivars->pciDevice, kIODMACommandCreateNoOptions, &dmaSpecification, &(ivars->descriptorTransferDMAs[i])); | |
| ivars->descriptorTransferDMAs[i]->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, | |
| ivars->descriptorTransferBuffers[i], | |
| 0, | |
| 0, | |
| &dmaFlags, | |
| &dmaSegmentCount, | |
| &descriptorBufferPhysicalAddressSegment); | |
| // Populate the first half of the buffer with data to be written to the 2nd half | |
| uint64_t transferSize = descriptorBufferVirtualAddressSegment.length / 2; | |
| for(unsigned int j = 0; j < transferSize; j++) | |
| { | |
| reinterpret_cast<uint8_t*>(descriptorBufferVirtualAddressSegment.address)[j] = j % 0xFF; | |
| } | |
| // setup the descriptor in the ring | |
| descriptorRing[i] = { 0 }; | |
| descriptorRing[i].transferSize = transferSize & 0x7FFFFFF; | |
| descriptorRing[i].descriptorValid = 1; | |
| descriptorRing[i].lowerSourceAddress = static_cast<uint32_t>(descriptorBufferPhysicalAddressSegment.address); | |
| descriptorRing[i].upperSourceAddress = ((descriptorBufferPhysicalAddressSegment.address >> 32) & 0xFFFF); | |
| descriptorRing[i].lowerDestinationAddress = static_cast<uint32_t>(descriptorBufferPhysicalAddressSegment.address + transferSize); | |
| descriptorRing[i].upperDestinationAddress = (((descriptorBufferPhysicalAddressSegment.address + transferSize) >> 32) & 0xFFFF); | |
| if(i == (numDescriptors - 1)) | |
| { | |
| // interrupt when the last descriptor is done | |
| descriptorRing[i].interruptWhenDoneWithDescriptor = 1; | |
| } | |
| } | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelDescriptorRingRingSizeOffset, | |
| numDescriptors); | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelMaximumPrefetchLimitOffset, | |
| kPEX8733DefaultDMADescriptorPrefetchLimit); | |
| uint32_t interruptControlStatus = 0; | |
| ivars->pciDevice->ConfigurationRead32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelInterruptControlStatusRegisterOffset, | |
| &interruptControlStatus); | |
| // clear interrupts (clear on write) | |
| interruptControlStatus |= kPEX8733DMAChannelInterruptControlStatusInterruptStatusRange; | |
| // enable interrupts | |
| interruptControlStatus |= kPEX8733DMAChannelInterruptControlStatusEnableRange; | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelInterruptControlStatusRegisterOffset, | |
| interruptControlStatus); | |
| // Enable DMA Block Mode, disable descriptor completion status writeback, and clear any active status bits | |
| uint32_t controlStatus = 0; | |
| ivars->pciDevice->ConfigurationRead32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelControlStatusRegisterOffset, | |
| &controlStatus); | |
| controlStatus &= (~kPEX8733DMAChannelControlStatusDescriptorModeSelectRange); | |
| controlStatus &= ~kPEX8733DMAChannelControlStatusCompletionStatusWriteBackEnable; | |
| controlStatus |= kPEX8733DMAChannelControlStatusStart | kPEX8733DMAChannelControlStatusRingStopMode | kPEX8733DMAChannelControlStatusDescriptorModeSelectOffChip; | |
| // clear any active status bits | |
| controlStatus |= kPEX8733DMAChannelControlStatusRange; | |
| // start DMA transfer | |
| ivars->pciDevice->ConfigurationWrite32(ivars->vendorCapabilityOffset + kPEX8733DMAChannelControlStatusRegisterOffset, | |
| controlStatus); | |
| return result; | |
| } |