mirror of
https://github.com/arehnman/yttrium-virtio-gpu.git
synced 2026-11-07 02:06:32 +00:00
The driver now uses the new API implemented in VirtioLib-WDF instead of the raw VirtioLib. This massively simplified the VIOSerialEvtDevicePrepareHardware callback as there's no need to do any resource enumeration anymore.
203 lines
5.2 KiB
C
203 lines
5.2 KiB
C
#include "precomp.h"
|
|
#include "vioser.h"
|
|
|
|
#if defined(EVENT_TRACING)
|
|
#include "IsrDpc.tmh"
|
|
#endif
|
|
|
|
BOOLEAN
|
|
VIOSerialInterruptIsr(
|
|
IN WDFINTERRUPT Interrupt,
|
|
IN ULONG MessageID)
|
|
{
|
|
PPORTS_DEVICE pContext = GetPortsDevice(WdfInterruptGetDevice(Interrupt));
|
|
WDF_INTERRUPT_INFO info;
|
|
BOOLEAN serviced;
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);
|
|
|
|
WDF_INTERRUPT_INFO_INIT(&info);
|
|
WdfInterruptGetInfo(Interrupt, &info);
|
|
|
|
// Schedule a DPC if the device is using message-signaled interrupts, or
|
|
// if the device ISR status is enabled.
|
|
if (info.MessageSignaled || VirtIOWdfGetISRStatus(&pContext->VDevice))
|
|
{
|
|
WdfInterruptQueueDpcForIsr(Interrupt);
|
|
serviced = TRUE;
|
|
}
|
|
else
|
|
{
|
|
serviced = FALSE;
|
|
}
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT,
|
|
"<-- %s Serviced: %d\n", __FUNCTION__, serviced);
|
|
|
|
return serviced;
|
|
}
|
|
|
|
VOID
|
|
VIOSerialInterruptDpc(
|
|
IN WDFINTERRUPT Interrupt,
|
|
IN WDFOBJECT AssociatedObject)
|
|
{
|
|
WDFDEVICE Device = WdfInterruptGetDevice(Interrupt);
|
|
PPORTS_DEVICE Context = GetPortsDevice(Device);
|
|
WDF_INTERRUPT_INFO info;
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> %s\n", __FUNCTION__);
|
|
|
|
VIOSerialCtrlWorkHandler(Device);
|
|
|
|
WDF_INTERRUPT_INFO_INIT(&info);
|
|
WdfInterruptGetInfo(Context->QueuesInterrupt, &info);
|
|
|
|
// Using the queues' DPC if only one interrupt is available.
|
|
if (info.Vector == 0)
|
|
{
|
|
VIOSerialQueuesInterruptDpc(Interrupt, AssociatedObject);
|
|
}
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %s\n", __FUNCTION__);
|
|
}
|
|
|
|
VOID VIOSerialQueuesInterruptDpc(IN WDFINTERRUPT Interrupt,
|
|
IN WDFOBJECT AssociatedObject)
|
|
{
|
|
NTSTATUS status;
|
|
WDFCHILDLIST PortList;
|
|
WDFDEVICE Device;
|
|
WDF_CHILD_LIST_ITERATOR iterator;
|
|
WDF_CHILD_RETRIEVE_INFO PortInfo;
|
|
VIOSERIAL_PORT VirtPort;
|
|
VIOSERIAL_PORT *Port;
|
|
|
|
UNREFERENCED_PARAMETER(AssociatedObject);
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> %s\n", __FUNCTION__);
|
|
|
|
PortList = WdfFdoGetDefaultChildList(WdfInterruptGetDevice(Interrupt));
|
|
WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren);
|
|
|
|
WdfChildListBeginIteration(PortList, &iterator);
|
|
for (;;)
|
|
{
|
|
WDF_CHILD_RETRIEVE_INFO_INIT(&PortInfo, &VirtPort.Header);
|
|
WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&VirtPort.Header,
|
|
sizeof(VirtPort));
|
|
|
|
status = WdfChildListRetrieveNextDevice(PortList, &iterator, &Device,
|
|
&PortInfo);
|
|
|
|
if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Port = RawPdoSerialPortGetData(Device)->port;
|
|
|
|
// handle the read queue
|
|
VIOSerialProcessInputBuffers(Port);
|
|
|
|
// handle the write queue
|
|
VIOSerialReclaimConsumedBuffers(Port);
|
|
}
|
|
WdfChildListEndIteration(PortList, &iterator);
|
|
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %s\n", __FUNCTION__);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
VIOSerialEnableInterrupt(PPORTS_DEVICE pContext)
|
|
{
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s enable\n", __FUNCTION__);
|
|
|
|
if(!pContext)
|
|
return;
|
|
|
|
if(pContext->c_ivq)
|
|
{
|
|
virtqueue_enable_cb(pContext->c_ivq);
|
|
virtqueue_kick(pContext->c_ivq);
|
|
}
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s enable\n", __FUNCTION__);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
VIOSerialDisableInterrupt(PPORTS_DEVICE pContext)
|
|
{
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s disable\n", __FUNCTION__);
|
|
|
|
if(!pContext)
|
|
return;
|
|
|
|
if(pContext->c_ivq)
|
|
{
|
|
virtqueue_disable_cb(pContext->c_ivq);
|
|
}
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s disable\n", __FUNCTION__);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
VIOSerialInterruptEnable(
|
|
IN WDFINTERRUPT Interrupt,
|
|
IN WDFDEVICE AssociatedDevice)
|
|
{
|
|
UNREFERENCED_PARAMETER(AssociatedDevice);
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);
|
|
VIOSerialEnableInterrupt(GetPortsDevice(WdfInterruptGetDevice(Interrupt)));
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
VIOSerialInterruptDisable(
|
|
IN WDFINTERRUPT Interrupt,
|
|
IN WDFDEVICE AssociatedDevice)
|
|
{
|
|
UNREFERENCED_PARAMETER(AssociatedDevice);
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "--> %s\n", __FUNCTION__);
|
|
VIOSerialDisableInterrupt(GetPortsDevice(WdfInterruptGetDevice(Interrupt)));
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
VIOSerialEnableInterruptQueue(IN struct virtqueue *vq)
|
|
{
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %s enable\n", __FUNCTION__);
|
|
|
|
if(!vq)
|
|
return;
|
|
|
|
virtqueue_enable_cb(vq);
|
|
virtqueue_kick(vq);
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);
|
|
}
|
|
|
|
VOID
|
|
VIOSerialDisableInterruptQueue(IN struct virtqueue *vq)
|
|
{
|
|
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %s disable\n", __FUNCTION__);
|
|
|
|
if(!vq)
|
|
return;
|
|
|
|
virtqueue_disable_cb(vq);
|
|
|
|
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "<-- %s\n", __FUNCTION__);
|
|
}
|
|
|