BOOLEAN DeviceInterrupt_EvtAttachDetachInterruptIsr ( _In_ WDFINTERRUPT Interrupt, _In_ ULONG MessageID ) /*++ Routine Description: 'EvtInterruptIsr' handler for the attach/detach interrupt object. http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx Arguments: Interrupt - Associated interrupt object. MessageID - Message IDs for MSI Return Value: BOOLEAN --*/ { PCONTROLLER_CONTEXT ControllerContext; UNREFERENCED_PARAMETER(MessageID); TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfInterruptGetDevice(Interrupt)); WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt); // // This is an ActiveBoth interrupt used for attach/detach. State is determined // by counting interrupts. Previous state was attached, so this is a detach. // if (!ControllerContext->Attached) { ControllerContext->Attached = TRUE; ControllerContext->GotAttachOrDetach = TRUE; (void) WdfInterruptQueueDpcForIsr(Interrupt); } else { ControllerContext->Attached = FALSE; ControllerContext->GotAttachOrDetach = TRUE; (void) WdfInterruptQueueDpcForIsr(Interrupt); } WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt); TraceExit(); return TRUE; }
BOOLEAN VirtRngEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId) { PDEVICE_CONTEXT context = GetDeviceContext( WdfInterruptGetDevice(Interrupt)); WDF_INTERRUPT_INFO info; BOOLEAN serviced; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %!FUNC! Interrupt: %p MessageId: %u", Interrupt, MessageId); WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(context->WdfInterrupt, &info); if ((info.MessageSignaled && (MessageId == 0)) || VirtIODeviceISR(&context->VirtDevice)) { WdfInterruptQueueDpcForIsr(Interrupt); serviced = TRUE; } else { serviced = FALSE; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- %!FUNC!"); return serviced; }
// // Routine Description: // // PL011EvtInterruptIsr is the interrupt service routine for // ARM PL011 UART. PL011EvtInterruptIsr calls PL011pInterruptIsr to do // incoming events ISR level processing, and schedules a DPC level // processing PL011EvtInterruptDpc if our device generated the interrupt. // // Arguments: // // WdfInterrupt - The WDF interrupt object the created for the ARM PL011 // interrupt. // // MessageID - The message ID, in case the device is using MSIs, otherwise 0. // // Return Value: // // TRUE if the interrupt originated from the PL011 device and was serviced, // otherwise FALSE. // _Use_decl_annotations_ BOOLEAN PL011EvtInterruptIsr( WDFINTERRUPT WdfInterrupt, ULONG MessageID ) { UNREFERENCED_PARAMETER(MessageID); WDFDEVICE wdfDevice = WdfInterruptGetDevice(WdfInterrupt); PL011_DEVICE_EXTENSION* devExtPtr = PL011DeviceGetExtension(wdfDevice); // // Get and process UART events (ISR level) // BOOLEAN isUartInterrupt = PL011pInterruptIsr(devExtPtr); if (!isUartInterrupt) { return FALSE; } PL011_ASSERT(WdfInterrupt == devExtPtr->WdfUartInterrupt); WdfInterruptQueueDpcForIsr(devExtPtr->WdfUartInterrupt); PL011_LOG_TRACE( "UART ISR, status 0x%04X", USHORT(devExtPtr->IntEventsForDpc) ); return TRUE; }
BOOLEAN NICEvtInterruptIsr( IN WDFINTERRUPT Interrupt, IN ULONG MessageID ) /*++ Routine Description: Interrupt handler for the device. Arguments: Interupt - Address of the framework interrupt object MessageID - Return Value: TRUE if our device is interrupting, FALSE otherwise. --*/ { BOOLEAN InterruptRecognized = FALSE; PFDO_DATA FdoData = NULL; USHORT IntStatus; UNREFERENCED_PARAMETER( MessageID ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> NICEvtInterruptIsr\n"); FdoData = FdoGetData(WdfInterruptGetDevice(Interrupt)); // // We process the interrupt if it's not disabled and it's active // if (!NIC_INTERRUPT_DISABLED(FdoData) && NIC_INTERRUPT_ACTIVE(FdoData)) { InterruptRecognized = TRUE; // // Disable the interrupt (will be re-enabled in NICEvtInterruptDpc // NICDisableInterrupt(FdoData); // // Acknowledge the interrupt(s) and get the interrupt status // NIC_ACK_INTERRUPT(FdoData, IntStatus); WdfInterruptQueueDpcForIsr( Interrupt ); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- NICEvtInterruptIsr\n"); return InterruptRecognized; }
/////////////////////////////////////////////////////////////////////////////// // Interrupt Service Routine (ISR) event callback function // processing on IRQL_DIRQL /////////////////////////////////////////////////////////////////////////////// BOOLEAN SmplInterruptEvtIsr( __in WDFINTERRUPT Interrupt, __in ULONG MessageID ) { WDFDEVICE Device = WdfInterruptGetDevice(Interrupt); PDEVICE_CONTEXT pSmplDeviceContext = DeviceGetContext(Device); BOOLEAN bReturnValue = FALSE; #pragma warning(push) #pragma warning(disable:4127) // warning C4127: conditional expression is constant while(TRUE) #pragma warning(pop) { // First check: Is it ours??? UCHAR rcvd; UCHAR IntId = READ_INTERRUPT_IDENTIFICATION(pSmplDeviceContext->pPortAddress); if (IntId & IIR_NOT_FIRED) { break; } DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"Interrupt\n"); bReturnValue = TRUE; switch (IntId) { case IIR_RECEIVER_FULL: rcvd = READ_RECEIVER_BUFFER (pSmplDeviceContext->pPortAddress); if (FALSE == RingbufferInsertCharacter(pSmplDeviceContext->pRingBuffer, rcvd)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"Ringbuffer overflow %x\n", rcvd); } break; case IIR_RECEIVER_ERROR: case IIR_TRANSMITTER_EMPTY: case IIR_STATUS_CHANGE: default: ; } // end switch } // end while if(TRUE == bReturnValue) WdfInterruptQueueDpcForIsr(Interrupt); return bReturnValue; } // end SmplInterruptEvtIsr
BOOLEAN DeviceInterrupt_EvtInterruptIsr( _In_ WDFINTERRUPT Interrupt, _In_ ULONG MessageID ) /*++ Routine Description: 'EvtInterruptIsr' handler for the device interrupt object. http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx Arguments: Interrupt - Associated interrupt object. MessageID - Message IDs for MSI Return Value: Appropriate NTSTATUS value --*/ { BOOLEAN PendingEvents; TraceEntry(); UNREFERENCED_PARAMETER(MessageID); // // #### TODO: Determine if controller has pending events. #### // // Sample will assume there is always a pending event for illustration purposes. PendingEvents = TRUE; if (PendingEvents) { // // Enqueue the DPC to handle the events. // WdfInterruptQueueDpcForIsr(Interrupt); } TraceExit(); return TRUE; }
/*++ 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. --*/ BOOLEAN PCIEEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageID) { PDEVICE_EXTENSION pDevExt; BOOLEAN IsRecognized = FALSE; UNREFERENCED_PARAMETER(MessageID); // Our ISR Routine will be called event if the test card hasn't trigger any interrupt signal. pDevExt = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt)); if (IsRecognized) { WdfInterruptQueueDpcForIsr(pDevExt->Interrupt); } return IsRecognized; }
BOOLEAN BalloonInterruptIsr( IN WDFINTERRUPT WdfInterrupt, IN ULONG MessageID ) { PDEVICE_CONTEXT devCtx = NULL; WDFDEVICE Device; UNREFERENCED_PARAMETER( MessageID ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__); Device = WdfInterruptGetDevice(WdfInterrupt); devCtx = GetDeviceContext(Device); if(VirtIODeviceISR(&devCtx->VDevice) > 0) { WdfInterruptQueueDpcForIsr( WdfInterrupt ); return TRUE; } return FALSE; }
BOOLEAN VioCryptInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId) { PDEVICE_CONTEXT context = GetDeviceContext( WdfInterruptGetDevice(Interrupt)); WDF_INTERRUPT_INFO info; BOOLEAN processed; WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(context->WdfInterrupt, &info); processed = ((info.MessageSignaled && (MessageId == 0)) || VirtIOWdfGetISRStatus(&context->VDevice)); if (processed) { WdfInterruptQueueDpcForIsr(Interrupt); } Trace(TRACE_LEVEL_VERBOSE, "[%s] %sprocessed", __FUNCTION__, processed ? "" : "not "); return processed; }
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; }
VOID VIOSerialHandleCtrlMsg( IN WDFDEVICE Device, IN PPORT_BUFFER buf ) { PPORTS_DEVICE pContext = GetPortsDevice(Device); PVIRTIO_CONSOLE_CONTROL cpkt; PVIOSERIAL_PORT port; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); cpkt = (PVIRTIO_CONSOLE_CONTROL)((ULONG_PTR)buf->va_buf + buf->offset); port = VIOSerialFindPortById(Device, cpkt->id); if (!port && (cpkt->event != VIRTIO_CONSOLE_PORT_ADD)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Invalid index %u in control packet\n", cpkt->id); } switch (cpkt->event) { case VIRTIO_CONSOLE_PORT_ADD: if (port) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_PORT_ADD id = %d\n", cpkt->id); break; } if (cpkt->id >= pContext->consoleConfig.max_nr_ports) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Out-of-bound id %u\n", cpkt->id); break; } VIOSerialAddPort(Device, cpkt->id); break; case VIRTIO_CONSOLE_PORT_REMOVE: if (!port) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_REMOVE invalid id = %d\n", cpkt->id); break; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_PORT_REMOVE id = %d\n", cpkt->id); VIOSerialRemovePort(Device, port); break; case VIRTIO_CONSOLE_CONSOLE_PORT: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_CONSOLE_PORT id = %d value = %u\n", cpkt->id, cpkt->value); if (cpkt->value) { VIOSerialInitPortConsole(Device,port); } break; case VIRTIO_CONSOLE_RESIZE: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_RESIZE id = %d\n", cpkt->id); break; case VIRTIO_CONSOLE_PORT_OPEN: if (port) { BOOLEAN Connected = (BOOLEAN)cpkt->value; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_OPEN id = %d, HostConnected = %d\n", cpkt->id, Connected); if (port->HostConnected != Connected) { VIOSerialPortPnpNotify(Device, port, Connected); } // Someone is listening. Trigger a check to see if we have // something waiting to be told. if (port->HostConnected) { WDF_INTERRUPT_INFO info; WDFINTERRUPT *interrupt; WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(pContext->QueuesInterrupt, &info); // Check if MSI is enabled and notify the right interrupt. interrupt = (info.Vector == 0) ? &pContext->WdfInterrupt : &pContext->QueuesInterrupt; WdfInterruptQueueDpcForIsr(*interrupt); } } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_OPEN invalid id = %d\n", cpkt->id); } break; case VIRTIO_CONSOLE_PORT_NAME: if (port) { VIOSerialPortCreateName(Device, port, buf); } break; default: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "%s UNKNOWN event = %d\n", __FUNCTION__, cpkt->event); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
BOOLEAN AmccPciEvtInterruptIsr( __in WDFINTERRUPT Interrupt, __in ULONG MessageID ) /*++ Routine Description: This routine assumes that only a single I/O can be completed at a time on the hardware (i.e. at most one I/O completed per interrupt). Arguments: Interupt - Address of the framework interrupt object MessageID - Return Value: TRUE - Interrupt belongs to this device. --*/ { PAMCC_DEVICE_EXTENSION devExt = NULL; WDFDEVICE hDevice; union { ULONG ulong; INTCSR_REG bits; } intcsr; union { ULONG ulong; MCSR_REG bits; } mcsr; UNREFERENCED_PARAMETER( MessageID ); hDevice = WdfInterruptGetDevice(Interrupt); devExt = AmccPciGetDevExt(hDevice); // // Read interrupt control/status register and see if an interrupt is pending. // If not, return FALSE immediately. // intcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->INTCSR); if (!intcsr.bits.InterruptAsserted) { return FALSE; } // // Disable bus-mastering // mcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->MCSR); mcsr.bits.WriteTransferEnable = FALSE; mcsr.bits.ReadTransferEnable = FALSE; WRITE_PORT_ULONG((PULONG) &devExt->Regs->MCSR, mcsr.ulong ); // // This will take effect when INTCSR is rewritten later. // intcsr.bits.IntOnWriteTransferComplete = FALSE; intcsr.bits.IntOnReadTransferComplete = FALSE; // // Process pending interrupts. We're expecting an interrupt due // to a transfer count going to zero, but we might be getting a // master or target abort instead. // while (intcsr.bits.InterruptAsserted) { // // Merge new interrupts with old // _InterlockedOr((PLONG) &devExt->Intcsr, (LONG) intcsr.ulong ); // // Interrupt flags on the S5933 are cleared by writing a "1" bit // to them, so clear all the interrupts just examined. // WRITE_PORT_ULONG((PULONG) &devExt->Regs->INTCSR, intcsr.ulong); // // Check for additional interrupts // intcsr.ulong = READ_PORT_ULONG((PULONG) &devExt->Regs->INTCSR); } // // Check if there is a current Request. If not, then this interrupt cannot // do anything. This driver design requires an I/O to be pending in order // to queue the DPC. If there is no I/O current, then there is no need // to have a DPC queued. This driver also assumes one I/O per interrupt. // // IMPORTANT: Before returning TRUE, the interrupt must have been cleared // on the device or the system will hang trying to service this level // sensitive interrupt. // if (!devExt->CurrentRequest) { TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_IO, "Hardware generated interrupt with no request pending"); return TRUE; } // // Request the DPC to complete the transfer. // WdfInterruptQueueDpcForIsr( Interrupt ); // // Indicate that this adapter was interrupting. // return TRUE; }