VOID NTAPI SerialReceiveByte( 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->InputBufferLock, &Irql); while (READ_PORT_UCHAR(SER_LSR(ComPortBase)) & SR_LSR_DATA_RECEIVED) { Byte = READ_PORT_UCHAR(SER_RBR(ComPortBase)); INFO_(SERIAL, "Byte received on COM%lu: 0x%02x\n", DeviceExtension->ComPort, Byte); Status = PushCircularBufferEntry(&DeviceExtension->InputBuffer, Byte); if (NT_SUCCESS(Status)) DeviceExtension->SerialPerfStats.ReceivedCount++; else DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++; } KeSetEvent(&DeviceExtension->InputBufferNotEmpty, 0, FALSE); KeReleaseSpinLock(&DeviceExtension->InputBufferLock, Irql); /* allow new interrupts */ IER = READ_PORT_UCHAR(SER_IER(ComPortBase)); WRITE_PORT_UCHAR(SER_IER(ComPortBase), IER | SR_IER_DATA_RECEIVED); }
NTSTATUS NTAPI SerialWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION Stack; PSERIAL_DEVICE_EXTENSION DeviceExtension; ULONG Length; ULONG_PTR Information = 0; PUCHAR Buffer; KIRQL Irql; NTSTATUS Status = STATUS_SUCCESS; TRACE_(SERIAL, "IRP_MJ_WRITE\n"); /* FIXME: pend operation if possible */ /* FIXME: use write timeouts */ Stack = IoGetCurrentIrpStackLocation(Irp); Length = Stack->Parameters.Write.Length; Buffer = SerialGetUserBuffer(Irp); DeviceExtension = (PSERIAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension; if (Stack->Parameters.Write.ByteOffset.QuadPart != 0 || Buffer == NULL) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (!NT_SUCCESS(Status)) goto ByeBye; /* push bytes into output buffer */ KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); while (Information < Length) { Status = PushCircularBufferEntry(&DeviceExtension->OutputBuffer, Buffer[Information]); if (!NT_SUCCESS(Status)) { if (Status == STATUS_BUFFER_TOO_SMALL) { KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); SerialSendByte(NULL, DeviceExtension, NULL, NULL); KeAcquireSpinLock(&DeviceExtension->OutputBufferLock, &Irql); continue; } else { WARN_(SERIAL, "Buffer overrun on COM%lu\n", DeviceExtension->ComPort); DeviceExtension->SerialPerfStats.BufferOverrunErrorCount++; break; } } Information++; } KeReleaseSpinLock(&DeviceExtension->OutputBufferLock, Irql); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); /* send bytes */ SerialSendByte(NULL, DeviceExtension, NULL, NULL); ByeBye: Irp->IoStatus.Information = Information; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }