NTSTATUS PciDtfDeviceGetDma(IN WDFDEVICE Device, IN WDFREQUEST Request) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_INFO *ReqData; WDFCOMMONBUFFER CommonBuffer; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } CommonBuffer = PciDtfCommonBufferFind(DeviceData, ReqData->id, FALSE); if (CommonBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } ReqData->addr = WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart; ReqData->len = (int)WdfCommonBufferGetLength(CommonBuffer); WdfRequestSetInformation(Request, sizeof(PCIDTF_DMA_INFO)); } __finally { WdfRequestComplete(Request, Status); } return Status; }
NTSTATUS PciDtfDeviceReadWriteDma(IN WDFDEVICE Device, IN WDFREQUEST Request, IN BOOLEAN Read) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_DATA *ReqData; WDFCOMMONBUFFER CommonBuffer; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_DMA_DATA), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } TRACE_MSG(TRACE_LEVEL_VERBOSE, TRACE_FLAG_QUEUE, "id=%d, off=%d, len=%d, buf=0x%p, read=%u\n", ReqData->id, ReqData->off, ReqData->len, ReqData->buf, Read); CommonBuffer = PciDtfCommonBufferFind(DeviceData, ReqData->id, FALSE); if (CommonBuffer == NULL) { Status = STATUS_INVALID_PARAMETER; __leave; } Status = PciDtfDmaReadWrite(ReqData, WdfCommonBufferGetAlignedVirtualAddress (CommonBuffer), (ULONG) WdfCommonBufferGetLength (CommonBuffer), Read); } __finally { WdfRequestComplete(Request, Status); } return Status; }
NTSTATUS PciDtfDeviceAllocDma(IN WDFDEVICE Device, IN WDFREQUEST Request) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_INFO *ReqData; WDF_OBJECT_ATTRIBUTES ObjectAttributes; WDFCOMMONBUFFER CommonBuffer = NULL; PCOMMON_BUFFER_DATA CommonBufferData; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ObjectAttributes, COMMON_BUFFER_DATA); Status = WdfCommonBufferCreate(DeviceData->DmaEnabler, ReqData->len, &ObjectAttributes, &CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCommonBufferCreate", Status); __leave; } CommonBufferData = GetCommonBufferData(CommonBuffer); CommonBufferData->ID = PciDtfCommonBufferAssignId(DeviceData); Status = WdfCollectionAdd(DeviceData->CommonBuffers, CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCollectionAdd", Status); __leave; } ReqData->id = CommonBufferData->ID; ReqData->addr = WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart; WdfRequestSetInformation(Request, sizeof(PCIDTF_DMA_INFO)); TRACE_MSG(TRACE_LEVEL_VERBOSE, TRACE_FLAG_QUEUE, "va 0x%p, pa 0x%llX, len 0x%X\n", WdfCommonBufferGetAlignedVirtualAddress(CommonBuffer), WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart, WdfCommonBufferGetLength(CommonBuffer)); } __finally { if (!NT_SUCCESS(Status) && CommonBuffer != NULL) { WdfObjectDelete(CommonBuffer); } WdfRequestComplete(Request, Status); } return Status; }
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; }