Пример #1
0
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);
}
Пример #2
0
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;
}