kvm-guest-drivers-windows
179 строк · 5.7 Кб
1/*
2* Interrupt related functions
3*
4* Copyright (c) 2016-2017 Red Hat, Inc.
5*
6* Redistribution and use in source and binary forms, with or without
7* modification, are permitted provided that the following conditions
8* are met :
9* 1. Redistributions of source code must retain the above copyright
10* notice, this list of conditions and the following disclaimer.
11* 2. Redistributions in binary form must reproduce the above copyright
12* notice, this list of conditions and the following disclaimer in the
13* documentation and / or other materials provided with the distribution.
14* 3. Neither the names of the copyright holders nor the names of their contributors
15* may be used to endorse or promote products derived from this software
16* without specific prior written permission.
17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27* SUCH DAMAGE.
28*/
29
30#include "precomp.h"31#include "vioinput.h"32
33#if defined(EVENT_TRACING)34#include "IsrDpc.tmh"35#endif36
37static
38VOID
39VIOInputEnableInterrupt(PINPUT_DEVICE pContext)40{
41TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s enable\n", __FUNCTION__);42
43if (!pContext)44return;45
46if (pContext->EventQ)47{48virtqueue_enable_cb(pContext->EventQ);49virtqueue_kick(pContext->EventQ);50}51if (pContext->StatusQ)52{53virtqueue_enable_cb(pContext->StatusQ);54virtqueue_kick(pContext->StatusQ);55}56
57TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s enable\n", __FUNCTION__);58}
59
60static
61VOID
62VIOInputDisableInterrupt(PINPUT_DEVICE pContext)63{
64TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s disable\n", __FUNCTION__);65
66if (!pContext)67return;68
69if (pContext->EventQ)70{71virtqueue_disable_cb(pContext->EventQ);72}73if (pContext->StatusQ)74{75virtqueue_disable_cb(pContext->StatusQ);76}77
78TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s disable\n", __FUNCTION__);79}
80
81NTSTATUS
82VIOInputInterruptEnable(83IN WDFINTERRUPT Interrupt,84IN WDFDEVICE AssociatedDevice)85{
86UNREFERENCED_PARAMETER(AssociatedDevice);87
88TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);89VIOInputEnableInterrupt(GetDeviceContext(WdfInterruptGetDevice(Interrupt)));90TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);91return STATUS_SUCCESS;92}
93
94NTSTATUS
95VIOInputInterruptDisable(96IN WDFINTERRUPT Interrupt,97IN WDFDEVICE AssociatedDevice)98{
99UNREFERENCED_PARAMETER(AssociatedDevice);100
101TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);102VIOInputDisableInterrupt(GetDeviceContext(WdfInterruptGetDevice(Interrupt)));103TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);104return STATUS_SUCCESS;105}
106
107BOOLEAN
108VIOInputInterruptIsr(109IN WDFINTERRUPT Interrupt,110IN ULONG MessageID)111{
112PINPUT_DEVICE pContext = GetDeviceContext(WdfInterruptGetDevice(Interrupt));113WDF_INTERRUPT_INFO info;114BOOLEAN serviced;115
116TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);117
118WDF_INTERRUPT_INFO_INIT(&info);119WdfInterruptGetInfo(Interrupt, &info);120
121// Schedule a DPC if the device is using message-signaled interrupts, or122// if the device ISR status is enabled.123if (info.MessageSignaled || VirtIOWdfGetISRStatus(&pContext->VDevice))124{125WdfInterruptQueueDpcForIsr(Interrupt);126serviced = TRUE;127}128else129{130serviced = FALSE;131}132
133TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);134return serviced;135}
136
137VOID
138VIOInputQueuesInterruptDpc(139IN WDFINTERRUPT Interrupt,140IN WDFOBJECT AssociatedObject)141{
142WDFDEVICE Device = WdfInterruptGetDevice(Interrupt);143PINPUT_DEVICE pContext = GetDeviceContext(Device);144PVIRTIO_INPUT_EVENT pEvent;145PVIRTIO_INPUT_EVENT_WITH_REQUEST pEventReq;146UINT len;147
148TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> %s\n", __FUNCTION__);149
150WdfSpinLockAcquire(pContext->EventQLock);151while ((pEvent = virtqueue_get_buf(pContext->EventQ, &len)) != NULL)152{153// translate event to a HID report and complete a pending HID request154ProcessInputEvent(pContext, pEvent);155
156// add the buffer back to the queue157VIOInputAddInBuf(158pContext->EventQ,159pEvent,160VirtIOWdfDeviceGetPhysicalAddress(&pContext->VDevice.VIODevice, pEvent));161}162WdfSpinLockRelease(pContext->EventQLock);163
164WdfSpinLockAcquire(pContext->StatusQLock);165while ((pEventReq = virtqueue_get_buf(pContext->StatusQ, &len)) != NULL)166{167// complete the pending request168if (pEventReq->Request != NULL)169{170WdfRequestComplete(pEventReq->Request, STATUS_SUCCESS);171}172
173// free the buffer174pContext->StatusQMemBlock->return_slice(pContext->StatusQMemBlock, pEventReq);175}176WdfSpinLockRelease(pContext->StatusQLock);177
178TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %s\n", __FUNCTION__);179}
180