MsgQueueConnection::EReceiveStatus MsgQueueConnection::Receive() { TRequestStatus dataStatus; GetInQueue().NotifyDataAvailable(dataStatus); TRequestStatus timerStatus; RTimer timer; timer.CreateLocal(); timer.After(timerStatus, 1000000); User::WaitForRequest(dataStatus, timerStatus); if (dataStatus == KRequestPending) { GetInQueue().CancelDataAvailable(); User::WaitForRequest(dataStatus); timer.Close(); return RS_TIME_OUT; } else { timer.Cancel(); User::WaitForRequest(timerStatus); timer.Close(); } if (KErrNone == GetInQueue().Receive(*(reinterpret_cast<message_buf*>(&m_cBuffer)))) { return RS_OK; } else return RS_ERROR; }
NTSTATUS VIOSerialPortEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) { PVIOSERIAL_PORT Port = RawPdoSerialPortGetData(Device)->port; PPORT_BUFFER buf; PSINGLE_LIST_ENTRY iter; UNREFERENCED_PARAMETER(TargetState); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__); WdfIoQueuePurge(Port->ReadQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); WdfIoQueuePurge(Port->WriteQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); WdfIoQueuePurge(Port->IoctlQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); VIOSerialDisableInterruptQueue(GetInQueue(Port)); WdfSpinLockAcquire(Port->InBufLock); VIOSerialDiscardPortDataLocked(Port); Port->InBuf = NULL; WdfSpinLockRelease(Port->InBufLock); WdfSpinLockAcquire(Port->OutVqLock); VIOSerialReclaimConsumedBuffers(Port); WdfSpinLockRelease(Port->OutVqLock); while (buf = (PPORT_BUFFER)VirtIODeviceDetachUnusedBuf(GetInQueue(Port))) { VIOSerialFreeBuffer(buf); } iter = PopEntryList(&Port->WriteBuffersList); while (iter != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); ExFreePoolWithTag(entry->Buffer, VIOSERIAL_DRIVER_MEMORY_TAG); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); iter = PopEntryList(&Port->WriteBuffersList); }; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
// this procedure must be called with port InBuf spinlock held SSIZE_T VIOSerialFillReadBufLocked( IN PVIOSERIAL_PORT port, IN PVOID outbuf, IN SIZE_T count ) { PPORT_BUFFER buf; NTSTATUS status = STATUS_SUCCESS; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "--> %s\n", __FUNCTION__); if (!count || !VIOSerialPortHasDataLocked(port)) return 0; buf = port->InBuf; count = min(count, buf->len - buf->offset); RtlCopyMemory(outbuf, (PVOID)((LONG_PTR)buf->va_buf + buf->offset), count); buf->offset += count; if (buf->offset == buf->len) { port->InBuf = NULL; status = VIOSerialAddInBuf(GetInQueue(port), buf); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_QUEUEING, "%s::%d VIOSerialAddInBuf failed\n", __FUNCTION__, __LINE__); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "<-- %s\n", __FUNCTION__); return count; }
NTSTATUS VIOSerialPortEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) { PVIOSERIAL_PORT Port = RawPdoSerialPortGetData(Device)->port; PPORT_BUFFER buf; PSINGLE_LIST_ENTRY iter; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s TargetState: %d\n", __FUNCTION__, TargetState); Port->Removed = TRUE; VIOSerialDisableInterruptQueue(GetInQueue(Port)); WdfSpinLockAcquire(Port->InBufLock); VIOSerialDiscardPortDataLocked(Port); Port->InBuf = NULL; WdfSpinLockRelease(Port->InBufLock); VIOSerialReclaimConsumedBuffers(Port); while (buf = (PPORT_BUFFER)virtqueue_detach_unused_buf(GetInQueue(Port))) { VIOSerialFreeBuffer(buf); } iter = PopEntryList(&Port->WriteBuffersList); while (iter != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); ExFreePoolWithTag(entry->Buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfObjectDelete(entry->EntryHandle); iter = PopEntryList(&Port->WriteBuffersList); }; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
NTSTATUS VIOSerialPortEvtDeviceD0Entry( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState) { PVIOSERIAL_PORT port = RawPdoSerialPortGetData(Device)->port; PPORTS_DEVICE pCtx = GetPortsDevice(port->BusDevice); NTSTATUS status; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); PAGED_CODE(); if ((pCtx->in_vqs == NULL) || (pCtx->in_vqs[port->PortId] == NULL)) { return STATUS_NOT_FOUND; } status = VIOSerialFillQueue(GetInQueue(port), port->InBufLock); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Error allocating input queue's buffers.\n"); return status; } VIOSerialSendCtrlMsg(port->BusDevice, port->PortId, VIRTIO_CONSOLE_PORT_READY, 1); if (port->GuestConnected) { VIOSerialSendCtrlMsg(port->BusDevice, port->PortId, VIRTIO_CONSOLE_PORT_OPEN, 1); } port->Removed = FALSE; VIOSerialEnableInterruptQueue(GetInQueue(port)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); return status; }
// this procedure must be called with port InBuf spinlock held VOID VIOSerialDiscardPortDataLocked( IN PVIOSERIAL_PORT port ) { struct virtqueue *vq; PPORT_BUFFER buf = NULL; UINT len; NTSTATUS status = STATUS_SUCCESS; UINT ret = 0; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); vq = GetInQueue(port); if (port->InBuf) { buf = port->InBuf; } else if (vq) { buf = (PPORT_BUFFER)vq->vq_ops->get_buf(vq, &len); } while (buf) { status = VIOSerialAddInBuf(vq, buf); if(!NT_SUCCESS(status)) { ++ret; VIOSerialFreeBuffer(buf); } buf = (PPORT_BUFFER)vq->vq_ops->get_buf(vq, &len); } port->InBuf = NULL; if (ret > 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "%s::%d Error adding %u buffers back to queue\n", __FUNCTION__, __LINE__, ret); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"<-- %s\n", __FUNCTION__); }
PVOID VIOSerialGetInBuf( IN PVIOSERIAL_PORT port ) { PPORT_BUFFER buf = NULL; struct virtqueue *vq = GetInQueue(port); UINT len; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "--> %s\n", __FUNCTION__); if (vq) { buf = virtqueue_get_buf(vq, &len); if (buf) { buf->len = len; buf->offset = 0; } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "<-- %s\n", __FUNCTION__); return buf; }
bool MsgQueueConnection::ReceiveMessage() { //GetInQueue().ReceiveBlocking(*(reinterpret_cast<message_buf*>(&m_cBuffer))); EReceiveStatus status; while ((status = Receive()) == RS_TIME_OUT) { if (!is_connected()) return false; // The MsgQueueNotifier may have called OnDisconnected } if (status == RS_ERROR) return false; //STTester_PROCESS_BUFFER(); if (m_cBuffer.len==KMaxQueueSlotSize) ///check for multipart msg { message_buf tmpBuf; bool done = false; while (!done) { //Call non-blocking version of Receive(), returns KErrUnderFlow if no msg in queue if (KErrNone==(GetInQueue().Receive(tmpBuf))) { int nBytes = min(tmpBuf.len, KMaxQueueSlotSize); Mem::Copy(m_cBuffer.msg+m_cBuffer.len, tmpBuf.buf, nBytes); m_cBuffer.len += nBytes; if (nBytes<KMaxQueueSlotSize) done = true; } else break; } } return true; }
VOID VIOSerialRenewAllPorts( IN WDFDEVICE Device ) { NTSTATUS status = STATUS_SUCCESS; WDFCHILDLIST list; WDF_CHILD_LIST_ITERATOR iterator; PPORTS_DEVICE pContext = GetPortsDevice(Device); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> %s\n", __FUNCTION__); if(pContext->isHostMultiport) { VIOSerialFillQueue(pContext->c_ivq, pContext->CVqLock); } list = WdfFdoGetDefaultChildList(Device); WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrievePresentChildren ); WdfChildListBeginIteration(list, &iterator); for (;;) { WDF_CHILD_RETRIEVE_INFO childInfo; VIOSERIAL_PORT vport; WDFDEVICE hChild; WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT( &vport.Header, sizeof(vport) ); WDF_CHILD_RETRIEVE_INFO_INIT(&childInfo, &vport.Header); status = WdfChildListRetrieveNextDevice( list, &iterator, &hChild, &childInfo ); if (!NT_SUCCESS(status) || status == STATUS_NO_MORE_ENTRIES) { break; } ASSERT(childInfo.Status == WdfChildListRetrieveDeviceSuccess); VIOSerialEnableInterruptQueue(GetInQueue(&vport)); WdfIoQueueStart(vport.ReadQueue); WdfIoQueueStart(vport.WriteQueue); WdfIoQueueStart(vport.IoctlQueue); if(vport.GuestConnected) { VIOSerialSendCtrlMsg(vport.BusDevice, vport.PortId, VIRTIO_CONSOLE_PORT_OPEN, 1); } } WdfChildListEndIteration(list, &iterator); WdfChildListUpdateAllChildDescriptionsAsPresent(list); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"<-- %s\n", __FUNCTION__); return; }