Beispiel #1
0
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);
}
Beispiel #2
0
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;
}