- Update to r53061
[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 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 }