[FASTFAT] Lock DirResource when modifying an entry on disk.
[reactos.git] / drivers / input / sermouse / readmouse.c
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 }