NTSTATUS PLxInitializeDMA( IN PDEVICE_EXTENSION DevExt ) /*++ Routine Description: Initializes the DMA adapter. Arguments: DevExt Pointer to our DEVICE_EXTENSION Return Value: None --*/ { NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; PAGED_CODE(); // // PLx PCI9656 DMA_TRANSFER_ELEMENTS must be 16-byte aligned // WdfDeviceSetAlignmentRequirement( DevExt->Device, PCI9656_DTE_ALIGNMENT_16 ); // // Create a new DMA Enabler instance. // Use Scatter/Gather, 64-bit Addresses, Duplex-type profile. // { WDF_DMA_ENABLER_CONFIG dmaConfig; WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, WdfDmaProfileScatterGather64Duplex, DevExt->MaximumTransferLength ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " - The DMA Profile is WdfDmaProfileScatterGather64Duplex"); status = WdfDmaEnablerCreate( DevExt->Device, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->DmaEnabler ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDmaEnablerCreate failed: %!STATUS!", status); return status; } } // // Allocate common buffer for building writes // // NOTE: This common buffer will not be cached. // Perhaps in some future revision, cached option could // be used. This would have faster access, but requires // flushing before starting the DMA in PLxStartWriteDma. // DevExt->WriteCommonBufferSize = sizeof(DMA_TRANSFER_ELEMENT) * DevExt->WriteTransferElements; _Analysis_assume_(DevExt->WriteCommonBufferSize > 0); status = WdfCommonBufferCreate( DevExt->DmaEnabler, DevExt->WriteCommonBufferSize, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->WriteCommonBuffer ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfCommonBufferCreate (write) failed: %!STATUS!", status); return status; } DevExt->WriteCommonBufferBase = WdfCommonBufferGetAlignedVirtualAddress(DevExt->WriteCommonBuffer); DevExt->WriteCommonBufferBaseLA = WdfCommonBufferGetAlignedLogicalAddress(DevExt->WriteCommonBuffer); RtlZeroMemory( DevExt->WriteCommonBufferBase, DevExt->WriteCommonBufferSize); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "WriteCommonBuffer 0x%p (#0x%I64X), length %I64d", DevExt->WriteCommonBufferBase, DevExt->WriteCommonBufferBaseLA.QuadPart, WdfCommonBufferGetLength(DevExt->WriteCommonBuffer) ); // // Allocate common buffer for building reads // // NOTE: This common buffer will not be cached. // Perhaps in some future revision, cached option could // be used. This would have faster access, but requires // flushing before starting the DMA in PLxStartReadDma. // DevExt->ReadCommonBufferSize = sizeof(DMA_TRANSFER_ELEMENT) * DevExt->ReadTransferElements; _Analysis_assume_(DevExt->ReadCommonBufferSize > 0); status = WdfCommonBufferCreate( DevExt->DmaEnabler, DevExt->ReadCommonBufferSize, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->ReadCommonBuffer ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfCommonBufferCreate (read) failed %!STATUS!", status); return status; } DevExt->ReadCommonBufferBase = WdfCommonBufferGetAlignedVirtualAddress(DevExt->ReadCommonBuffer); DevExt->ReadCommonBufferBaseLA = WdfCommonBufferGetAlignedLogicalAddress(DevExt->ReadCommonBuffer); RtlZeroMemory( DevExt->ReadCommonBufferBase, DevExt->ReadCommonBufferSize); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "ReadCommonBuffer 0x%p (#0x%I64X), length %I64d", DevExt->ReadCommonBufferBase, DevExt->ReadCommonBufferBaseLA.QuadPart, WdfCommonBufferGetLength(DevExt->ReadCommonBuffer) ); // // Since we are using sequential queue and processing one request // at a time, we will create transaction objects upfront and reuse // them to do DMA transfer. Transactions objects are parented to // DMA enabler object by default. They will be deleted along with // along with the DMA enabler object. So need to delete them // explicitly. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT); status = WdfDmaTransactionCreate( DevExt->DmaEnabler, &attributes, &DevExt->ReadDmaTransaction); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionCreate(read) failed: %!STATUS!", status); return status; } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT); // // Create a new DmaTransaction. // status = WdfDmaTransactionCreate( DevExt->DmaEnabler, &attributes, &DevExt->WriteDmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionCreate(write) failed: %!STATUS!", status); return status; } return status; }
NTSTATUS AmccPciEvtDevicePrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST Resources, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDevicePrepareHardware event callback performs operations that are necessary to use the device's control registers. Arguments: Device - Handle to a framework device object. Resources - Handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: WDF status code. Let us not worry about cleaning up the resources here if we fail start, because the PNP manager will send a remove-request and we will free all the allocated resources in AmccPciEvtDeviceReleaseHardware. --*/ { ULONG i; NTSTATUS status = STATUS_SUCCESS; PAMCC_DEVICE_EXTENSION devExt = NULL; BOOLEAN foundPort = FALSE; PHYSICAL_ADDRESS portBasePA = {0}; ULONG portCount = 0; WDF_DMA_ENABLER_CONFIG dmaConfig; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; PAGED_CODE(); // // The Resources collection is not used for PCI devices, since the PCI // bus driver manages the device's PCI Base Address Registers. // UNREFERENCED_PARAMETER( Resources ); devExt = AmccPciGetDevExt(Device); // // Parse the resource list and save the resource information. // for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfResourceCmGetDescriptor failed"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypePort: portBasePA = desc->u.Port.Start; portCount = desc->u.Port.Length; devExt->PortMapped = (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; foundPort = TRUE; // // Map in the single IO Space resource. // if (devExt->PortMapped) { devExt->PortBase = (PUCHAR) MmMapIoSpace( portBasePA, portCount, MmNonCached ); if (!devExt->PortBase) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Unable to map port range 0x%p, length %d", devExt->PortBase, devExt->PortCount); return STATUS_INSUFFICIENT_RESOURCES; } devExt->PortCount = portCount; } else { devExt->PortBase = (PUCHAR)(ULONG_PTR) portBasePA.QuadPart; devExt->PortCount = portCount; } devExt->Regs = (PREG5933) devExt->PortBase; break; default: TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_INIT, "Unknown resource type %d", desc->Type); break; } } if (!foundPort) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Missing hardware resources"); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // Configure the DMA object // WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, WdfDmaProfilePacket, devExt->MaximumTransferLength ); status = WdfDmaEnablerCreate( devExt->Device, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &devExt->DmaEnabler ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfDmaEnablerCreate failed %08X", status); return status; } return STATUS_SUCCESS; }
NTSTATUS UfxClientDeviceCreate( _In_ WDFDRIVER Driver, _In_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: Driver - WDF driver object DeviceInit - Pointer to an opaque init structure. Memory for this structure will be freed by the framework when the WdfDeviceCreate succeeds. So don't access the structure after that point. Return Value: Appropriate NTSTATUS value --*/ { WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE WdfDevice; NTSTATUS Status; WDF_PNPPOWER_EVENT_CALLBACKS PnpCallbacks; WDF_DMA_ENABLER_CONFIG DmaConfig; PCONTROLLER_CONTEXT ControllerContext; PAGED_CODE(); TraceEntry(); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, CONTROLLER_CONTEXT); // // Do UFX-specific initialization // Status = UfxFdoInit(Driver, DeviceInit, &DeviceAttributes); CHK_NT_MSG(Status, "Failed UFX initialization"); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpCallbacks); PnpCallbacks.EvtDevicePrepareHardware = OnEvtDevicePrepareHardware; PnpCallbacks.EvtDeviceReleaseHardware = OnEvtDeviceReleaseHardware; PnpCallbacks.EvtDeviceD0Entry = OnEvtDeviceD0Entry; PnpCallbacks.EvtDeviceD0Exit = OnEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpCallbacks); Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &WdfDevice); CHK_NT_MSG(Status, "Failed to create wdf device"); ControllerContext = DeviceGetControllerContext(WdfDevice); KeInitializeEvent(&ControllerContext->DetachEvent, NotificationEvent, FALSE); WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&ControllerContext->IdleSettings, IdleCanWakeFromS0); ControllerContext->IdleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; ControllerContext->IdleSettings.IdleTimeout = IDLE_TIMEOUT; ControllerContext->IdleSettings.DxState = PowerDeviceD3; Status = WdfDeviceAssignS0IdleSettings(WdfDevice, &ControllerContext->IdleSettings); LOG_NT_MSG(Status, "Failed to set S0 Idle Settings"); // // Create and initialize device's default queue // Status = DefaultQueueCreate(WdfDevice); CHK_NT_MSG(Status, "Failed to intialize default queue"); // // Set alignment required by controller // WdfDeviceSetAlignmentRequirement(WdfDevice, UFX_CLIENT_ALIGNMENT); // // Create and Initialize DMA Enabler object for the device. // WDF_DMA_ENABLER_CONFIG_INIT( &DmaConfig, WdfDmaProfileScatterGatherDuplex, MAX_DMA_LENGTH); // // Version 3 is required to perform multiple // simultaneous transfers. // DmaConfig.WdmDmaVersionOverride = 3; Status = WdfDmaEnablerCreate( WdfDevice, &DmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->DmaEnabler); CHK_NT_MSG(Status, "Failed to create DMA enabler object"); // // Create UFXDEVICE object // Status = UfxDevice_DeviceCreate(WdfDevice); CHK_NT_MSG(Status, "Failed to create UFX Device object"); // // Create DPC Lock // Status = WdfSpinLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->DpcLock); CHK_NT_MSG(Status, "Failed to create DPC lock"); Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->InitializeDefaultEndpointLock); CHK_NT_MSG(Status, "Failed to create Ep0 init lock"); End: TraceExit(); return Status; }