Sample Code
Windows Driver Samples/ PLX9x5x PCI Driver/ C++/ sys/ IsrDpc.c/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: IsrDpc.c Abstract: Contains routines related to interrupt and dpc handling. Environment: Kernel mode --*/ #include "precomp.h" #include "IsrDpc.tmh" NTSTATUS PLxInterruptCreate( IN PDEVICE_EXTENSION DevExt ) /*++ Routine Description: Configure and create the WDFINTERRUPT object. This routine is called by EvtDeviceAdd callback. Arguments: DevExt Pointer to our DEVICE_EXTENSION Return Value: NTSTATUS code --*/ { NTSTATUS status; WDF_INTERRUPT_CONFIG InterruptConfig; WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig, PLxEvtInterruptIsr, PLxEvtInterruptDpc ); InterruptConfig.EvtInterruptEnable = PLxEvtInterruptEnable; InterruptConfig.EvtInterruptDisable = PLxEvtInterruptDisable; // JOHNR: Enable testing of the DpcForIsr Synchronization InterruptConfig.AutomaticSerialization = TRUE; // // Unlike WDM, framework driver should create interrupt object in EvtDeviceAdd and // let the framework do the resource parsing and registration of ISR with the kernel. // Framework connects the interrupt after invoking the EvtDeviceD0Entry callback // and disconnect before invoking EvtDeviceD0Exit. EvtInterruptEnable is called after // the interrupt interrupt is connected and EvtInterruptDisable before the interrupt is // disconnected. // status = WdfInterruptCreate( DevExt->Device, &InterruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->Interrupt ); if( !NT_SUCCESS(status) ) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfInterruptCreate failed: %!STATUS!", status); } return status; } BOOLEAN PLxEvtInterruptIsr( IN WDFINTERRUPT Interrupt, IN ULONG MessageID ) /*++ Routine Description: Interrupt handler for this driver. Called at DIRQL level when the device or another device sharing the same interrupt line asserts the interrupt. The driver first checks the device to make sure whether this interrupt is generated by its device and if so clear the interrupt register to disable further generation of interrupts and queue a DPC to do other I/O work related to interrupt - such as reading the device memory, starting a DMA transaction, coping it to the request buffer and completing the request, etc. Arguments: Interupt - Handle to WDFINTERRUPT Object for this device. MessageID - MSI message ID (always 0 in this configuration) Return Value: TRUE -- This device generated the interrupt. FALSE -- This device did not generated this interrupt. --*/ { PDEVICE_EXTENSION devExt; BOOLEAN isRecognized = FALSE; union { INT_CSR bits; ULONG ulong; } intCsr; UNREFERENCED_PARAMETER(MessageID); //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, // "--> PLxInterruptHandler"); devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); // // Read the Interrupt CSR register (INTCSR) // intCsr.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); // // Is DMA channel 0 (Write-side) Active? // if (intCsr.bits.DmaChan0IntActive) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, " Interrupt for DMA Channel 0 (write)"); devExt->IntCsr.bits.DmaChan0IntActive = TRUE; // // Clear this interrupt. // devExt->Dma0Csr.uchar = READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr ); devExt->Dma0Csr.bits.Clear = TRUE; WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr, devExt->Dma0Csr.uchar ); isRecognized = TRUE; } // // Is DMA channel 1 (Read-side) Active? // if (intCsr.bits.DmaChan1IntActive) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, " Interrupt for DMA Channel 1 (read)"); devExt->IntCsr.bits.DmaChan1IntActive = TRUE; // // Clear this interrupt. // devExt->Dma1Csr.uchar = READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr ); devExt->Dma1Csr.bits.Clear = TRUE; WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr, devExt->Dma1Csr.uchar ); isRecognized = TRUE; } if ((isRecognized) && ((devExt->Dma0Csr.bits.Done) || (devExt->Dma1Csr.bits.Done))) { // // A read or a write or both is done. Queue a DPC. // WdfInterruptQueueDpcForIsr( devExt->Interrupt ); } //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, // "<-- PLxInterruptHandler"); return isRecognized; } _Use_decl_annotations_ VOID PLxEvtInterruptDpc( WDFINTERRUPT Interrupt, WDFOBJECT Device ) /*++ Routine Description: DPC callback for ISR. Please note that on a multiprocessor system, you could have more than one DPCs running simulataneously on multiple processors. So if you are accesing any global resources make sure to synchrnonize the accesses with a spinlock. Arguments: Interupt - Handle to WDFINTERRUPT Object for this device. Device - WDFDEVICE object passed to InterruptCreate Return Value: --*/ { NTSTATUS status; WDFDMATRANSACTION dmaTransaction; PDEVICE_EXTENSION devExt; BOOLEAN writeInterrupt = FALSE; BOOLEAN readInterrupt = FALSE; UNREFERENCED_PARAMETER(Device); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc"); devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); // // Acquire this device's InterruptSpinLock. // WdfInterruptAcquireLock( Interrupt ); if ((devExt->IntCsr.bits.DmaChan0IntActive) && (devExt->Dma0Csr.bits.Done)) { // // If Dma0 channel 0 (write) is interrupting and the // Done bit is set in the Dma0 CSR, // we're interrupting because a WRITE is complete. // Clear the done bit and channel interrupting bit from // our copies... // devExt->IntCsr.bits.DmaChan0IntActive = FALSE; devExt->Dma0Csr.uchar = 0; writeInterrupt = TRUE; } if ((devExt->IntCsr.bits.DmaChan1IntActive) && (devExt->Dma1Csr.bits.Done)) { // // If DMA channel 1 is interrupting and the // DONE bit is set in the DMA1 control/status // register, we're interrupting because a READ // is complete. // Clear the done bit and channel interrupting bit from // our copies... // devExt->IntCsr.bits.DmaChan1IntActive = FALSE; devExt->Dma0Csr.uchar = 0; readInterrupt = TRUE; } // // Release our interrupt spinlock // WdfInterruptReleaseLock( Interrupt ); // // Did a Write DMA complete? // if (writeInterrupt) { BOOLEAN transactionComplete; // // Get the current Write DmaTransaction. // dmaTransaction = devExt->WriteDmaTransaction; // // Indicate this DMA operation has completed: // This may drive the transfer on the next packet if // there is still data to be transfered in the request. // transactionComplete = WdfDmaTransactionDmaCompleted( dmaTransaction, &status ); if (transactionComplete) { // // Complete this DmaTransaction. // TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "Completing Write request in the DpcForIsr"); PLxWriteRequestComplete( dmaTransaction, status ); } } // // Did a Read DMA complete? // if (readInterrupt) { BOOLEAN transactionComplete; PDMA_TRANSFER_ELEMENT dteVA; size_t length; // // Get the current Read DmaTransaction. // dmaTransaction = devExt->ReadDmaTransaction; // // Only on Read-side -- // Use "DMA Clear-Count Mode" to get complemetary // transferred byte count. // length = WdfDmaTransactionGetCurrentDmaTransferLength( dmaTransaction ); dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase; while(dteVA->DescPtr.LastElement == FALSE) { length -= dteVA->TransferSize; dteVA++; } length -= dteVA->TransferSize; // // Indicate this DMA operation has completed: // This may drive the transfer on the next packet if // there is still data to be transfered in the request. // transactionComplete = WdfDmaTransactionDmaCompletedWithLength( dmaTransaction, length, &status ); if (transactionComplete) { // // Complete this DmaTransaction. // TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "Completing Read request in the DpcForIsr"); PLxReadRequestComplete( dmaTransaction, status ); } } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc"); return; } NTSTATUS PLxEvtInterruptEnable( IN WDFINTERRUPT Interrupt, IN WDFDEVICE Device ) /*++ Routine Description: Called by the framework at DIRQL immediately after registering the ISR with the kernel by calling IoConnectInterrupt. Return Value: NTSTATUS --*/ { PDEVICE_EXTENSION devExt; union { INT_CSR bits; ULONG ulong; } intCSR; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "PLxEvtInterruptEnable: Interrupt 0x%p, Device 0x%p\n", Interrupt, Device); devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); intCSR.bits.PciIntEnable = TRUE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, intCSR.ulong ); return STATUS_SUCCESS; } NTSTATUS PLxEvtInterruptDisable( IN WDFINTERRUPT Interrupt, IN WDFDEVICE Device ) /*++ Routine Description: Called by the framework at DIRQL before Deregistering the ISR with the kernel by calling IoDisconnectInterrupt. Return Value: NTSTATUS --*/ { PDEVICE_EXTENSION devExt; union { INT_CSR bits; ULONG ulong; } intCSR; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "PLxEvtInterruptDisable: Interrupt 0x%p, Device 0x%p\n", Interrupt, Device); devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); intCSR.bits.PciIntEnable = FALSE; WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, intCSR.ulong ); return STATUS_SUCCESS; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials