2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Serial mouse driver
4 * FILE: drivers/input/sermouse/readmouse.c
5 * PURPOSE: Read mouse moves and send them to mouclass
7 * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
8 * Filip Navara (xnavara@volny.cz)
9 * Hervé Poussineau (hpoussin@reactos.org)
18 SermouseDeviceIoControl(
19 IN PDEVICE_OBJECT DeviceObject
,
21 IN PVOID InputBuffer OPTIONAL
,
22 IN ULONG InputBufferSize
,
23 IN OUT PVOID OutputBuffer OPTIONAL
,
24 IN OUT PULONG OutputBufferSize
)
28 IO_STATUS_BLOCK IoStatus
;
31 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
33 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
38 (OutputBufferSize
) ? *OutputBufferSize
: 0,
44 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
45 return STATUS_INSUFFICIENT_RESOURCES
;
48 Status
= IoCallDriver(DeviceObject
, Irp
);
50 if (Status
== STATUS_PENDING
)
52 DPRINT("Operation pending\n");
53 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
54 Status
= IoStatus
.Status
;
59 *OutputBufferSize
= IoStatus
.Information
;
69 PSERMOUSE_DEVICE_EXTENSION DeviceExtension
;
70 PDEVICE_OBJECT LowerDevice
;
71 UCHAR Buffer
[PACKET_BUFFER_SIZE
];
73 IO_STATUS_BLOCK ioStatus
;
78 PMOUSE_INPUT_DATA Input
;
79 ULONG ButtonsDifference
;
84 SERIAL_TIMEOUTS Timeouts
;
85 SERIAL_LINE_CONTROL LCR
;
89 DPRINT("SermouseDeviceWorker() called\n");
91 DeviceExtension
= (PSERMOUSE_DEVICE_EXTENSION
)((PDEVICE_OBJECT
)Context
)->DeviceExtension
;
92 LowerDevice
= DeviceExtension
->LowerDevice
;
94 PacketBuffer
= DeviceExtension
->PacketBuffer
;
98 /* Initialize device extension */
99 DeviceExtension
->ActiveQueue
= 0;
100 DeviceExtension
->PacketBufferPosition
= 0;
101 DeviceExtension
->PreviousButtons
= 0;
103 /* Initialize serial port */
105 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_FIFO_CONTROL
,
106 &Fcr
, sizeof(Fcr
), NULL
, NULL
);
107 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
108 /* Set serial port speed */
109 BaudRate
= DeviceExtension
->DriverExtension
->SampleRate
;
110 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
111 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
112 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
115 LCR
.Parity
= NO_PARITY
;
116 LCR
.StopBits
= STOP_BIT_1
;
117 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
118 &LCR
, sizeof(LCR
), NULL
, NULL
);
119 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
122 Timeouts
.ReadTotalTimeoutConstant
= Timeouts
.ReadTotalTimeoutMultiplier
= 0;
123 Timeouts
.ReadIntervalTimeout
= 100;
124 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
125 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
126 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
127 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
132 Status
= KeWaitForSingleObject(
133 &DeviceExtension
->StopWorkerThreadEvent
,
138 if (Status
!= STATUS_TIMEOUT
)
140 /* we need to stop the worker thread */
141 KeResetEvent(&DeviceExtension
->StopWorkerThreadEvent
);
145 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
146 Irp
= IoBuildSynchronousFsdRequest(
149 Buffer
, PACKET_BUFFER_SIZE
,
155 /* no memory actually, try later */
157 KeStallExecutionProcessor(10);
161 Status
= IoCallDriver(LowerDevice
, Irp
);
162 if (Status
== STATUS_PENDING
)
164 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
165 Status
= ioStatus
.Status
;
168 if (!NT_SUCCESS(Status
))
171 /* Read all available data and process */
172 for (i
= 0; i
< ioStatus
.Information
; i
++)
174 ReceivedByte
= Buffer
[i
];
175 DPRINT1("ReceivedByte 0x%02x\n", ReceivedByte
);
178 if ((ReceivedByte
& 0x40) == 0x40)
179 DeviceExtension
->PacketBufferPosition
= 0;
181 PacketBuffer
[DeviceExtension
->PacketBufferPosition
] = ReceivedByte
& 0x7f;
182 DeviceExtension
->PacketBufferPosition
++;
184 /* Process packet if complete */
185 if (DeviceExtension
->PacketBufferPosition
>= 3)
187 Queue
= DeviceExtension
->ActiveQueue
% 2;
189 /* Prevent buffer overflow */
190 if (DeviceExtension
->InputDataCount
[Queue
] == DeviceExtension
->DriverExtension
->MouseDataQueueSize
)
193 Input
= &DeviceExtension
->MouseInputData
[Queue
][DeviceExtension
->InputDataCount
[Queue
]];
195 if (DeviceExtension
->PacketBufferPosition
== 3)
197 /* Retrieve change in x and y from packet */
198 Input
->LastX
= (signed char)(PacketBuffer
[1] | ((PacketBuffer
[0] & 0x03) << 6));
199 Input
->LastY
= (signed char)(PacketBuffer
[2] | ((PacketBuffer
[0] & 0x0c) << 4));
201 /* Determine the current state of the buttons */
202 Input
->RawButtons
= (DeviceExtension
->PreviousButtons
& MOUSE_BUTTON_MIDDLE
) |
203 ((UCHAR
)(PacketBuffer
[0] & LEFT_BUTTON_MASK
) >> LEFT_BUTTON_SHIFT
) |
204 ((UCHAR
)(PacketBuffer
[0] & RIGHT_BUTTON_MASK
) >> RIGHT_BUTTON_SHIFT
);
206 else if (DeviceExtension
->PacketBufferPosition
== 4)
208 DeviceExtension
->PacketBufferPosition
= 0;
209 /* If middle button state changed than report event */
210 if (((UCHAR
)(PacketBuffer
[3] & MIDDLE_BUTTON_MASK
) >> MIDDLE_BUTTON_SHIFT
) ^
211 (DeviceExtension
->PreviousButtons
& MOUSE_BUTTON_MIDDLE
))
213 Input
->RawButtons
^= MOUSE_BUTTON_MIDDLE
;
223 /* Determine ButtonFlags */
224 Input
->ButtonFlags
= 0;
225 ButtonsDifference
= DeviceExtension
->PreviousButtons
^ Input
->RawButtons
;
227 if (ButtonsDifference
!= 0)
229 if (ButtonsDifference
& MOUSE_BUTTON_LEFT
230 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 1)
232 if (Input
->RawButtons
& MOUSE_BUTTON_LEFT
)
233 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_DOWN
;
235 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_UP
;
238 if (ButtonsDifference
& MOUSE_BUTTON_RIGHT
239 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 2)
241 if (Input
->RawButtons
& MOUSE_BUTTON_RIGHT
)
242 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_DOWN
;
244 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_UP
;
247 if (ButtonsDifference
& MOUSE_BUTTON_MIDDLE
248 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 3)
250 if (Input
->RawButtons
& MOUSE_BUTTON_MIDDLE
)
251 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_DOWN
;
253 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_UP
;
257 /* Send the Input data to the Mouse Class driver */
258 DeviceExtension
->InputDataCount
[Queue
]++;
260 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
261 InterlockedIncrement((PLONG
)&DeviceExtension
->ActiveQueue
);
262 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ConnectData
.ClassService
)(
263 DeviceExtension
->ConnectData
.ClassDeviceObject
,
264 DeviceExtension
->MouseInputData
[Queue
],
265 DeviceExtension
->MouseInputData
[Queue
] + 1,
266 &DeviceExtension
->InputDataCount
[Queue
]);
267 KeLowerIrql(OldIrql
);
268 DeviceExtension
->InputDataCount
[Queue
] = 0;
270 /* Copy RawButtons to Previous Buttons for Input */
271 DeviceExtension
->PreviousButtons
= Input
->RawButtons
;
276 PsTerminateSystemThread(STATUS_SUCCESS
);