// 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 VIOSerialPortRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); size_t length; NTSTATUS status; PVOID systemBuffer; BOOLEAN nonBlock; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "-->%s\n", __FUNCTION__); nonBlock = ((WdfFileObjectGetFlags(WdfRequestGetFileObject(Request)) & FO_SYNCHRONOUS_IO) != FO_SYNCHRONOUS_IO); status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &length); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } WdfSpinLockAcquire(pdoData->port->InBufLock); if (!VIOSerialPortHasDataLocked(pdoData->port)) { if (!pdoData->port->HostConnected) { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } else { ASSERT (pdoData->port->PendingReadRequest == NULL); status = WdfRequestMarkCancelableEx(Request, VIOSerialPortReadRequestCancel); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); } else { pdoData->port->PendingReadRequest = Request; } } } else { length = (ULONG)VIOSerialFillReadBufLocked(pdoData->port, systemBuffer, length); if (length) { WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR)length); } else { WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } } WdfSpinLockRelease(pdoData->port->InBufLock); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ,"<-- %s\n", __FUNCTION__); return; }
VOID VIOSerialPortRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length ) { PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue)); PVIOSERIAL_PORT pport = pdoData->port; size_t length; NTSTATUS status; PVOID systemBuffer; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "-->%s\n", __FUNCTION__); status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &length); if (!NT_SUCCESS(status)) { WdfRequestComplete(Request, status); return; } WdfSpinLockAcquire(pport->InBufLock); if (!VIOSerialPortHasDataLocked(pport)) { if (!pport->HostConnected) { status = STATUS_INSUFFICIENT_RESOURCES; length = 0; } else { ASSERT (pport->PendingReadRequest == NULL); status = WdfRequestMarkCancelableEx(Request, VIOSerialPortReadRequestCancel); if (!NT_SUCCESS(status)) { length = 0; } else { pport->PendingReadRequest = Request; Request = NULL; } } } else { length = (ULONG)VIOSerialFillReadBufLocked(pport, systemBuffer, length); if (!length) { status = STATUS_INSUFFICIENT_RESOURCES; } } WdfSpinLockRelease(pport->InBufLock); if (Request != NULL) { // we are completing the request right here, either because of // an error or because data was available in the input buffer WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR)length); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ,"<-- %s\n", __FUNCTION__); }