// 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; }
VOID VIOSerialCtrlWorkHandler( IN WDFDEVICE Device ) { struct virtqueue *vq; PPORT_BUFFER buf; UINT len; NTSTATUS status = STATUS_SUCCESS; PPORTS_DEVICE pContext = GetPortsDevice(Device); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> %s\n", __FUNCTION__); vq = pContext->c_ivq; ASSERT(vq); WdfSpinLockAcquire(pContext->CInVqLock); while ((buf = virtqueue_get_buf(vq, &len))) { WdfSpinLockRelease(pContext->CInVqLock); buf->len = len; buf->offset = 0; VIOSerialHandleCtrlMsg(Device, buf); WdfSpinLockAcquire(pContext->CInVqLock); status = VIOSerialAddInBuf(vq, buf); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "%s::%d Error adding buffer to queue\n", __FUNCTION__, __LINE__); VIOSerialFreeBuffer(buf); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- %s\n", __FUNCTION__); WdfSpinLockRelease(pContext->CInVqLock); }
NTSTATUS VIOSerialFillQueue( IN struct virtqueue *vq, IN WDFSPINLOCK Lock ) { NTSTATUS status = STATUS_SUCCESS; PPORT_BUFFER buf = NULL; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> %s\n", __FUNCTION__); for (;;) { buf = VIOSerialAllocateBuffer(PAGE_SIZE); if(buf == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "VIOSerialAllocateBuffer failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } WdfSpinLockAcquire(Lock); status = VIOSerialAddInBuf(vq, buf); if(!NT_SUCCESS(status)) { VIOSerialFreeBuffer(buf); WdfSpinLockRelease(Lock); break; } WdfSpinLockRelease(Lock); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
// 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__); }