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)
14 SermouseDeviceIoControl(
15 IN PDEVICE_OBJECT DeviceObject
,
17 IN PVOID InputBuffer OPTIONAL
,
18 IN ULONG InputBufferSize
,
19 IN OUT PVOID OutputBuffer OPTIONAL
,
20 IN OUT PULONG OutputBufferSize
)
24 IO_STATUS_BLOCK IoStatus
;
27 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
29 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
34 (OutputBufferSize
) ? *OutputBufferSize
: 0,
40 WARN_(SERMOUSE
, "IoBuildDeviceIoControlRequest() failed\n");
41 return STATUS_INSUFFICIENT_RESOURCES
;
44 Status
= IoCallDriver(DeviceObject
, Irp
);
46 if (Status
== STATUS_PENDING
)
48 INFO_(SERMOUSE
, "Operation pending\n");
49 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
50 Status
= IoStatus
.Status
;
55 *OutputBufferSize
= (ULONG
)IoStatus
.Information
;
65 PSERMOUSE_DEVICE_EXTENSION DeviceExtension
;
66 PDEVICE_OBJECT LowerDevice
;
67 UCHAR Buffer
[PACKET_BUFFER_SIZE
];
69 IO_STATUS_BLOCK ioStatus
;
74 PMOUSE_INPUT_DATA Input
;
75 ULONG ButtonsDifference
;
80 SERIAL_TIMEOUTS Timeouts
;
81 SERIAL_LINE_CONTROL LCR
;
85 TRACE_(SERMOUSE
, "SermouseDeviceWorker() called\n");
87 DeviceExtension
= (PSERMOUSE_DEVICE_EXTENSION
)((PDEVICE_OBJECT
)Context
)->DeviceExtension
;
88 LowerDevice
= DeviceExtension
->LowerDevice
;
90 PacketBuffer
= DeviceExtension
->PacketBuffer
;
94 /* Initialize device extension */
95 DeviceExtension
->ActiveQueue
= 0;
96 DeviceExtension
->PacketBufferPosition
= 0;
97 DeviceExtension
->PreviousButtons
= 0;
99 /* Initialize serial port */
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
);
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
);
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
);
126 RtlZeroMemory(Buffer
, PACKET_BUFFER_SIZE
);
129 Status
= KeWaitForSingleObject(
130 &DeviceExtension
->StopWorkerThreadEvent
,
135 if (Status
!= STATUS_TIMEOUT
)
137 /* we need to stop the worker thread */
138 KeResetEvent(&DeviceExtension
->StopWorkerThreadEvent
);
142 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
143 Irp
= IoBuildSynchronousFsdRequest(
146 Buffer
, PACKET_BUFFER_SIZE
,
152 /* No memory actually, try later */
153 INFO_(SERMOUSE
, "No memory actually, trying again\n");
154 KeStallExecutionProcessor(10);
158 Status
= IoCallDriver(LowerDevice
, Irp
);
159 if (Status
== STATUS_PENDING
)
161 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
162 Status
= ioStatus
.Status
;
165 if (!NT_SUCCESS(Status
))
168 /* Read all available data and process */
169 for (i
= 0; i
< ioStatus
.Information
; i
++)
171 ReceivedByte
= Buffer
[i
];
172 INFO_(SERMOUSE
, "ReceivedByte 0x%02x\n", ReceivedByte
);
175 if ((ReceivedByte
& 0x40) == 0x40)
176 DeviceExtension
->PacketBufferPosition
= 0;
178 PacketBuffer
[DeviceExtension
->PacketBufferPosition
] = ReceivedByte
& 0x7f;
179 DeviceExtension
->PacketBufferPosition
++;
181 /* Process packet if complete */
182 if (DeviceExtension
->PacketBufferPosition
>= 3)
184 Queue
= DeviceExtension
->ActiveQueue
% 2;
186 /* Prevent buffer overflow */
187 if (DeviceExtension
->InputDataCount
[Queue
] == 1)
190 Input
= &DeviceExtension
->MouseInputData
[Queue
];
192 if (DeviceExtension
->PacketBufferPosition
== 3)
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));
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
);
203 else if (DeviceExtension
->PacketBufferPosition
== 4)
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
))
210 Input
->RawButtons
^= MOUSE_BUTTON_MIDDLE
;
220 /* Determine ButtonFlags */
221 Input
->ButtonFlags
= 0;
222 ButtonsDifference
= DeviceExtension
->PreviousButtons
^ Input
->RawButtons
;
224 if (ButtonsDifference
!= 0)
226 if (ButtonsDifference
& MOUSE_BUTTON_LEFT
227 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 1)
229 if (Input
->RawButtons
& MOUSE_BUTTON_LEFT
)
230 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_DOWN
;
232 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_UP
;
235 if (ButtonsDifference
& MOUSE_BUTTON_RIGHT
236 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 2)
238 if (Input
->RawButtons
& MOUSE_BUTTON_RIGHT
)
239 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_DOWN
;
241 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_UP
;
244 if (ButtonsDifference
& MOUSE_BUTTON_MIDDLE
245 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 3)
247 if (Input
->RawButtons
& MOUSE_BUTTON_MIDDLE
)
248 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_DOWN
;
250 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_UP
;
254 /* Send the Input data to the Mouse Class driver */
255 DeviceExtension
->InputDataCount
[Queue
]++;
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;
267 /* Copy RawButtons to Previous Buttons for Input */
268 DeviceExtension
->PreviousButtons
= Input
->RawButtons
;
273 PsTerminateSystemThread(STATUS_SUCCESS
);