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