VOID NTAPI SerialSendByte( IN PKDPC Dpc, IN PVOID pDeviceExtension, // real type PSERIAL_DEVICE_EXTENSION IN PVOID Unused1, IN PVOID Unused2) { PSERIAL_DEVICE_EXTENSION DeviceExtension; PUCHAR ComPortBase; UCHAR Byte; KIRQL Irql; UCHAR IER; NTSTATUS Status; DeviceExtension = (PSERIAL_DEVICE_EXTENSION)pDeviceExtension; ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); while (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer) && READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_THR_EMPTY) { Status = PopCircularBufferEntry(&DeviceExtension->OutputBuffer, &Byte); if (!NT_SUCCESS(Status)) break; WRITE_PORT_UCHAR(SER_THR(ComPortBase), Byte); INFO_(SERIAL, "Byte sent to COM%lu: 0x%02x\n", DeviceExtension->ComPort, Byte); DeviceExtension->SerialPerfStats.TransmittedCount++; } if (!IsCircularBufferEmpty(&DeviceExtension->OutputBuffer)) { /* allow new interrupts */ IER = READ_PORT_UCHAR(SER_IER(ComPortBase)); WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER | SR_IER_THR_EMPTY); } KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); }
static VOID ReadBytes( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, PWORKITEM_DATA WorkItemData) { PSERIAL_DEVICE_EXTENSION DeviceExtension; ULONG Length; PUCHAR Buffer; UCHAR ReceivedByte; KTIMER TotalTimeoutTimer; KIRQL Irql; ULONG ObjectCount; PVOID ObjectsArray[2]; ULONG_PTR Information = 0; NTSTATUS Status; ASSERT(DeviceObject); ASSERT(WorkItemData); DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length; Buffer = SerialGetUserBuffer(Irp); INFO_(SERIAL, "UseIntervalTimeout = %s, IntervalTimeout = %lu\n", WorkItemData->UseIntervalTimeout ? "YES" : "NO", WorkItemData->UseIntervalTimeout ? WorkItemData->IntervalTimeout.QuadPart : 0); INFO_(SERIAL, "UseTotalTimeout = %s\n", WorkItemData->UseTotalTimeout ? "YES" : "NO"); ObjectCount = 1; ObjectsArray[0] = &DeviceExtension->InputBufferNotEmpty; if (WorkItemData->UseTotalTimeout) { KeInitializeTimer(&TotalTimeoutTimer); KeSetTimer(&TotalTimeoutTimer, WorkItemData->TotalTimeoutTime, NULL); ObjectsArray[ObjectCount] = &TotalTimeoutTimer; ObjectCount++; } /* while buffer is not fully filled */ while (Length > 0) { /* read already received bytes from buffer */ KeAcquireSpinLock(&DeviceExtension->InputBufferLock, &Irql); while (!IsCircularBufferEmpty(&DeviceExtension->InputBuffer) && Length > 0) { PopCircularBufferEntry(&DeviceExtension->InputBuffer, &ReceivedByte); INFO_(SERIAL, "Reading byte from buffer: 0x%02x\n", ReceivedByte); Buffer[Information++] = ReceivedByte; Length--; } KeClearEvent(&DeviceExtension->InputBufferNotEmpty); KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); if (WorkItemData->DontWait && !(WorkItemData->ReadAtLeastOneByte && Information == 0)) { INFO_(SERIAL, "Buffer empty. Don't wait more bytes\n"); break; } Status = KeWaitForMultipleObjects( ObjectCount, ObjectsArray, WaitAny, Executive, KernelMode, FALSE, (WorkItemData->UseIntervalTimeout && Information > 0) ? &WorkItemData->IntervalTimeout : NULL, NULL); if (Status == STATUS_TIMEOUT /* interval timeout */ || Status == STATUS_WAIT_1) /* total timeout */ { TRACE_(SERIAL, "Timeout when reading bytes. Status = 0x%08lx\n", Status); break; } } /* stop total timeout timer */ if (WorkItemData->UseTotalTimeout) KeCancelTimer(&TotalTimeoutTimer); Irp->IoStatus.Information = Information; if (Information == 0) Irp->IoStatus.Status = STATUS_TIMEOUT; else Irp->IoStatus.Status = STATUS_SUCCESS; }