VOID AmccPciEvtIoDefault( __in WDFQUEUE Queue, __in WDFREQUEST Request ) /*++ Routine Description: Start the IRP on the device. This driver allows only one I/O to be active on the adapter at any one time. If multiple I/Os are sent to the driver, they will be queued and completed as they complete on the adapter (one IRP per interrupt). Arguments: Queue - Default queue handle Request - Handle to the write request Parameters - Contains current stack location information from the IRP Return Value: None --*/ { PAMCC_DEVICE_EXTENSION devExt; REQUEST_CONTEXT * transfer; NTSTATUS status; size_t length; WDF_DMA_DIRECTION direction; WDFDMATRANSACTION dmaTransaction; WDF_REQUEST_PARAMETERS params; WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Request, ¶ms ); // // Get the device extension. // devExt = AmccPciGetDevExt(WdfIoQueueGetDevice( Queue )); // // Validate and gather parameters. // switch (params.Type) { case WdfRequestTypeRead: length = params.Parameters.Read.Length; direction = WdfDmaDirectionReadFromDevice; break; case WdfRequestTypeWrite: length = params.Parameters.Write.Length; direction = WdfDmaDirectionWriteToDevice; break; default: TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO, "Request type not Read or Write\n"); WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Request %p: %s %d bytes", Request, (direction)?"Write":"Read", (ULONG)length); // // The length must be non-zero. // if (length == 0) { TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO, "Zero transfer length input to read/write"); WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } transfer = GetRequestContext(Request); // // Create new DmaRequst to conduct this DMA transaction. // status = WdfDmaTransactionCreate( devExt->DmaEnabler, WDF_NO_OBJECT_ATTRIBUTES, &dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaRequestCreate failed: %X", status); WdfRequestComplete(Request, status); return; } // // Create new DmaTransaction. // status = WdfDmaTransactionInitializeUsingRequest( dmaTransaction, Request, AmccPciProgramDma, direction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaRequestInitializeWithRequest failed: %X", status); WdfObjectDelete(dmaTransaction); WdfRequestComplete(Request, status); return; } // // Fill transfer context structure // transfer->Request = Request; transfer->DmaTransaction = dmaTransaction; // // Save the current Request as the "in-progress" request. // devExt->CurrentRequest = Request; // // Execute this dmaTransaction transaction. // status = WdfDmaTransactionExecute( dmaTransaction, WDF_NO_CONTEXT); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "WdfDmaTransactionExecute failed: %X", status); WdfObjectDelete(dmaTransaction); WdfRequestComplete(Request, status); return; } return; }
NTSTATUS NICInitiateDmaTransfer( IN PFDO_DATA FdoData, IN WDFREQUEST Request ) { WDFDMATRANSACTION dmaTransaction; NTSTATUS status; BOOLEAN bCreated = FALSE; do { // // Create a new DmaTransaction. // status = WdfDmaTransactionCreate( FdoData->WdfDmaEnabler, WDF_NO_OBJECT_ATTRIBUTES, &dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionCreate failed %X\n", status); break; } bCreated = TRUE; // // Initialize the new DmaTransaction. // status = WdfDmaTransactionInitializeUsingRequest( dmaTransaction, Request, NICEvtProgramDmaFunction, WdfDmaDirectionWriteToDevice ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionInitalizeUsingRequest failed %X\n", status); break; } // // Execute this DmaTransaction. // status = WdfDmaTransactionExecute( dmaTransaction, dmaTransaction ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfDmaTransactionExecute failed %X\n", status); break; } } WHILE (FALSE); if(!NT_SUCCESS(status)){ if(bCreated) { WdfObjectDelete( dmaTransaction ); } } 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; }