xref: /reactos/drivers/input/sermouse/readmouse.c (revision 23373acb)
1 /*
2  * PROJECT:     ReactOS Serial mouse driver
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/input/sermouse/fdo.c
5  * PURPOSE:     Read mouse moves and send them to mouclass
6  * PROGRAMMERS: Copyright Jason Filby (jasonfilby@yahoo.com)
7                 Copyright Filip Navara (xnavara@volny.cz)
8                 Copyright 2005-2006 Herv� Poussineau (hpoussin@reactos.org)
9  */
10 
11 #include "sermouse.h"
12 
13 #include <debug.h>
14 
15 static NTSTATUS
16 SermouseDeviceIoControl(
17 	IN PDEVICE_OBJECT DeviceObject,
18 	IN ULONG CtlCode,
19 	IN PVOID InputBuffer OPTIONAL,
20 	IN ULONG InputBufferSize,
21 	IN OUT PVOID OutputBuffer OPTIONAL,
22 	IN OUT PULONG OutputBufferSize)
23 {
24 	KEVENT Event;
25 	PIRP Irp;
26 	IO_STATUS_BLOCK IoStatus;
27 	NTSTATUS Status;
28 
29 	KeInitializeEvent(&Event, NotificationEvent, FALSE);
30 
31 	Irp = IoBuildDeviceIoControlRequest(CtlCode,
32 		DeviceObject,
33 		InputBuffer,
34 		InputBufferSize,
35 		OutputBuffer,
36 		(OutputBufferSize) ? *OutputBufferSize : 0,
37 		FALSE,
38 		&Event,
39 		&IoStatus);
40 	if (Irp == NULL)
41 	{
42 		WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n");
43 		return STATUS_INSUFFICIENT_RESOURCES;
44 	}
45 
46 	Status = IoCallDriver(DeviceObject, Irp);
47 
48 	if (Status == STATUS_PENDING)
49 	{
50 		INFO_(SERMOUSE, "Operation pending\n");
51 		KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
52 		Status = IoStatus.Status;
53 	}
54 
55 	if (OutputBufferSize)
56 	{
57 		*OutputBufferSize = (ULONG)IoStatus.Information;
58 	}
59 
60 	return Status;
61 }
62 
63 VOID NTAPI
64 SermouseDeviceWorker(
65 	PVOID Context)
66 {
67 	PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
68 	PDEVICE_OBJECT LowerDevice;
69 	UCHAR Buffer[PACKET_BUFFER_SIZE];
70 	PIRP Irp;
71 	IO_STATUS_BLOCK ioStatus;
72 	KEVENT event;
73 	PUCHAR PacketBuffer;
74 	UCHAR ReceivedByte;
75 	ULONG Queue;
76 	PMOUSE_INPUT_DATA Input;
77 	ULONG ButtonsDifference;
78 	KIRQL OldIrql;
79 	ULONG i;
80 	ULONG Fcr;
81 	ULONG BaudRate;
82 	SERIAL_TIMEOUTS Timeouts;
83 	SERIAL_LINE_CONTROL LCR;
84 	LARGE_INTEGER Zero;
85 	NTSTATUS Status;
86 
87 	TRACE_(SERMOUSE, "SermouseDeviceWorker() called\n");
88 
89 	DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
90 	LowerDevice = DeviceExtension->LowerDevice;
91 	Zero.QuadPart = 0;
92 	PacketBuffer = DeviceExtension->PacketBuffer;
93 
94 	ASSERT(LowerDevice);
95 
96 	/* Initialize device extension */
97 	DeviceExtension->ActiveQueue = 0;
98 	DeviceExtension->PacketBufferPosition = 0;
99 	DeviceExtension->PreviousButtons = 0;
100 
101 	/* Initialize serial port */
102 	Fcr = 0;
103 	Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
104 		&Fcr, sizeof(Fcr), NULL, NULL);
105 	if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
106 	/* Set serial port speed */
107 	BaudRate = DeviceExtension->AttributesInformation.SampleRate * 8;
108 	Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
109 		&BaudRate, sizeof(BaudRate), NULL, NULL);
110 	if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
111 	/* Set LCR */
112 	LCR.WordLength = 7;
113 	LCR.Parity = NO_PARITY;
114 	LCR.StopBits = STOP_BIT_1;
115 	Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
116 		&LCR, sizeof(LCR), NULL, NULL);
117 	if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
118 
119 	/* Set timeouts */
120 	Timeouts.ReadTotalTimeoutConstant = Timeouts.ReadTotalTimeoutMultiplier = 0;
121 	Timeouts.ReadIntervalTimeout = 100;
122 	Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
123 	Status = SermouseDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
124 		&Timeouts, sizeof(Timeouts), NULL, NULL);
125 	if (!NT_SUCCESS(Status)) PsTerminateSystemThread(Status);
126 
127 	/* main read loop */
128 	RtlZeroMemory(Buffer, PACKET_BUFFER_SIZE);
129 	while (TRUE)
130 	{
131 		Status = KeWaitForSingleObject(
132 			&DeviceExtension->StopWorkerThreadEvent,
133 			Executive,
134 			KernelMode,
135 			TRUE,
136 			&Zero);
137 		if (Status != STATUS_TIMEOUT)
138 		{
139 			/* we need to stop the worker thread */
140 			KeClearEvent(&DeviceExtension->StopWorkerThreadEvent);
141 			break;
142 		}
143 
144 		KeInitializeEvent(&event, NotificationEvent, FALSE);
145 		Irp = IoBuildSynchronousFsdRequest(
146 			IRP_MJ_READ,
147 			LowerDevice,
148 			Buffer, PACKET_BUFFER_SIZE,
149 			&Zero,
150 			&event,
151 			&ioStatus);
152 		if (!Irp)
153 		{
154 			/* No memory actually, try later */
155 			INFO_(SERMOUSE, "No memory actually, trying again\n");
156 			KeStallExecutionProcessor(10);
157 			continue;
158 		}
159 
160 		Status = IoCallDriver(LowerDevice, Irp);
161 		if (Status == STATUS_PENDING)
162 		{
163 			KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
164 			Status = ioStatus.Status;
165 		}
166 
167 		if (!NT_SUCCESS(Status))
168 			continue;
169 
170 		/* Read all available data and process */
171 		for (i = 0; i < ioStatus.Information; i++)
172 		{
173 			ReceivedByte = Buffer[i];
174 			INFO_(SERMOUSE, "ReceivedByte 0x%02x\n", ReceivedByte);
175 
176 			/* Synchronize */
177 			if ((ReceivedByte & 0x40) == 0x40)
178 				DeviceExtension->PacketBufferPosition = 0;
179 
180 			PacketBuffer[DeviceExtension->PacketBufferPosition] = ReceivedByte & 0x7f;
181 			DeviceExtension->PacketBufferPosition++;
182 
183 			/* Process packet if complete */
184 			if (DeviceExtension->PacketBufferPosition >= 3)
185 			{
186 				Queue = DeviceExtension->ActiveQueue % 2;
187 
188 				/* Prevent buffer overflow */
189 				if (DeviceExtension->InputDataCount[Queue] == 1)
190 					continue;
191 
192 				Input = &DeviceExtension->MouseInputData[Queue];
193 
194 				if (DeviceExtension->PacketBufferPosition == 3)
195 				{
196 					/* Retrieve change in x and y from packet */
197 					Input->LastX = (signed char)(PacketBuffer[1] | ((PacketBuffer[0] & 0x03) << 6));
198 					Input->LastY = (signed char)(PacketBuffer[2] | ((PacketBuffer[0] & 0x0c) << 4));
199 
200 					/* Determine the current state of the buttons */
201 					Input->RawButtons = (DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE) |
202 						((UCHAR)(PacketBuffer[0] & LEFT_BUTTON_MASK) >> LEFT_BUTTON_SHIFT) |
203 						((UCHAR)(PacketBuffer[0] & RIGHT_BUTTON_MASK) >> RIGHT_BUTTON_SHIFT);
204 				}
205 				else if (DeviceExtension->PacketBufferPosition == 4)
206 				{
207 					DeviceExtension->PacketBufferPosition = 0;
208 					/* If middle button state changed than report event */
209 					if (((UCHAR)(PacketBuffer[3] & MIDDLE_BUTTON_MASK) >> MIDDLE_BUTTON_SHIFT) ^
210 						(DeviceExtension->PreviousButtons & MOUSE_BUTTON_MIDDLE))
211 					{
212 						Input->RawButtons ^= MOUSE_BUTTON_MIDDLE;
213 						Input->LastX = 0;
214 						Input->LastY = 0;
215 					}
216 					else
217 					{
218 						continue;
219 					}
220 				}
221 
222 				/* Determine ButtonFlags */
223 				Input->ButtonFlags = 0;
224 				ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons;
225 
226 				if (ButtonsDifference != 0)
227 				{
228 					if (ButtonsDifference & MOUSE_BUTTON_LEFT
229 						&& DeviceExtension->AttributesInformation.NumberOfButtons >= 1)
230 					{
231 						if (Input->RawButtons & MOUSE_BUTTON_LEFT)
232 							Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
233 						else
234 							Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
235 					}
236 
237 					if (ButtonsDifference & MOUSE_BUTTON_RIGHT
238 						&& DeviceExtension->AttributesInformation.NumberOfButtons >= 2)
239 					{
240 						if (Input->RawButtons & MOUSE_BUTTON_RIGHT)
241 							Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
242 						else
243 							Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
244 					}
245 
246 					if (ButtonsDifference & MOUSE_BUTTON_MIDDLE
247 						&& DeviceExtension->AttributesInformation.NumberOfButtons >= 3)
248 					{
249 						if (Input->RawButtons & MOUSE_BUTTON_MIDDLE)
250 							Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
251 						else
252 							Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
253 					}
254 				}
255 
256 				/* Send the Input data to the Mouse Class driver */
257 				DeviceExtension->InputDataCount[Queue]++;
258 
259 				KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
260 				InterlockedIncrement((PLONG)&DeviceExtension->ActiveQueue);
261 				(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ConnectData.ClassService)(
262 					DeviceExtension->ConnectData.ClassDeviceObject,
263 					&DeviceExtension->MouseInputData[Queue],
264 					&DeviceExtension->MouseInputData[Queue] + 1,
265 					&DeviceExtension->InputDataCount[Queue]);
266 				KeLowerIrql(OldIrql);
267 				DeviceExtension->InputDataCount[Queue] = 0;
268 
269 				/* Copy RawButtons to Previous Buttons for Input */
270 				DeviceExtension->PreviousButtons = Input->RawButtons;
271 			}
272 		}
273 	}
274 
275 	PsTerminateSystemThread(STATUS_SUCCESS);
276 }
277