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)
17 SermouseDeviceIoControl(
18 IN PDEVICE_OBJECT DeviceObject
,
20 IN PVOID InputBuffer OPTIONAL
,
21 IN ULONG InputBufferSize
,
22 IN OUT PVOID OutputBuffer OPTIONAL
,
23 IN OUT PULONG OutputBufferSize
)
27 IO_STATUS_BLOCK IoStatus
;
30 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
32 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
37 (OutputBufferSize
) ? *OutputBufferSize
: 0,
43 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
44 return STATUS_INSUFFICIENT_RESOURCES
;
47 Status
= IoCallDriver(DeviceObject
, Irp
);
49 if (Status
== STATUS_PENDING
)
51 DPRINT("Operation pending\n");
52 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
53 Status
= IoStatus
.Status
;
58 *OutputBufferSize
= IoStatus
.Information
;
68 PSERMOUSE_DEVICE_EXTENSION DeviceExtension
;
69 PDEVICE_OBJECT LowerDevice
;
70 UCHAR Buffer
[PACKET_BUFFER_SIZE
];
72 IO_STATUS_BLOCK ioStatus
;
77 PMOUSE_INPUT_DATA Input
;
78 ULONG ButtonsDifference
;
83 SERIAL_TIMEOUTS Timeouts
;
84 SERIAL_LINE_CONTROL LCR
;
88 DPRINT("SermouseDeviceWorker() called\n");
90 DeviceExtension
= (PSERMOUSE_DEVICE_EXTENSION
)((PDEVICE_OBJECT
)Context
)->DeviceExtension
;
91 LowerDevice
= DeviceExtension
->LowerDevice
;
93 PacketBuffer
= DeviceExtension
->PacketBuffer
;
97 /* Initialize device extension */
98 DeviceExtension
->ActiveQueue
= 0;
99 DeviceExtension
->PacketBufferPosition
= 0;
100 DeviceExtension
->PreviousButtons
= 0;
102 /* Initialize serial port */
104 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_FIFO_CONTROL
,
105 &Fcr
, sizeof(Fcr
), NULL
, NULL
);
106 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
107 /* Set serial port speed */
108 BaudRate
= DeviceExtension
->AttributesInformation
.SampleRate
* 8;
109 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
110 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
111 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
114 LCR
.Parity
= NO_PARITY
;
115 LCR
.StopBits
= STOP_BIT_1
;
116 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
117 &LCR
, sizeof(LCR
), NULL
, NULL
);
118 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
121 Timeouts
.ReadTotalTimeoutConstant
= Timeouts
.ReadTotalTimeoutMultiplier
= 0;
122 Timeouts
.ReadIntervalTimeout
= 100;
123 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
124 Status
= SermouseDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
125 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
126 if (!NT_SUCCESS(Status
)) PsTerminateSystemThread(Status
);
131 Status
= KeWaitForSingleObject(
132 &DeviceExtension
->StopWorkerThreadEvent
,
137 if (Status
!= STATUS_TIMEOUT
)
139 /* we need to stop the worker thread */
140 KeResetEvent(&DeviceExtension
->StopWorkerThreadEvent
);
144 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
145 Irp
= IoBuildSynchronousFsdRequest(
148 Buffer
, PACKET_BUFFER_SIZE
,
154 /* no memory actually, try later */
156 KeStallExecutionProcessor(10);
160 Status
= IoCallDriver(LowerDevice
, Irp
);
161 if (Status
== STATUS_PENDING
)
163 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
164 Status
= ioStatus
.Status
;
167 if (!NT_SUCCESS(Status
))
170 /* Read all available data and process */
171 for (i
= 0; i
< ioStatus
.Information
; i
++)
173 ReceivedByte
= Buffer
[i
];
174 DPRINT("ReceivedByte 0x%02x\n", ReceivedByte
);
177 if ((ReceivedByte
& 0x40) == 0x40)
178 DeviceExtension
->PacketBufferPosition
= 0;
180 PacketBuffer
[DeviceExtension
->PacketBufferPosition
] = ReceivedByte
& 0x7f;
181 DeviceExtension
->PacketBufferPosition
++;
183 /* Process packet if complete */
184 if (DeviceExtension
->PacketBufferPosition
>= 3)
186 Queue
= DeviceExtension
->ActiveQueue
% 2;
188 /* Prevent buffer overflow */
189 if (DeviceExtension
->InputDataCount
[Queue
] == 1)
192 Input
= &DeviceExtension
->MouseInputData
[Queue
];
194 if (DeviceExtension
->PacketBufferPosition
== 3)
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));
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
);
205 else if (DeviceExtension
->PacketBufferPosition
== 4)
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
))
212 Input
->RawButtons
^= MOUSE_BUTTON_MIDDLE
;
222 /* Determine ButtonFlags */
223 Input
->ButtonFlags
= 0;
224 ButtonsDifference
= DeviceExtension
->PreviousButtons
^ Input
->RawButtons
;
226 if (ButtonsDifference
!= 0)
228 if (ButtonsDifference
& MOUSE_BUTTON_LEFT
229 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 1)
231 if (Input
->RawButtons
& MOUSE_BUTTON_LEFT
)
232 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_DOWN
;
234 Input
->ButtonFlags
|= MOUSE_LEFT_BUTTON_UP
;
237 if (ButtonsDifference
& MOUSE_BUTTON_RIGHT
238 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 2)
240 if (Input
->RawButtons
& MOUSE_BUTTON_RIGHT
)
241 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_DOWN
;
243 Input
->ButtonFlags
|= MOUSE_RIGHT_BUTTON_UP
;
246 if (ButtonsDifference
& MOUSE_BUTTON_MIDDLE
247 && DeviceExtension
->AttributesInformation
.NumberOfButtons
>= 3)
249 if (Input
->RawButtons
& MOUSE_BUTTON_MIDDLE
)
250 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_DOWN
;
252 Input
->ButtonFlags
|= MOUSE_MIDDLE_BUTTON_UP
;
256 /* Send the Input data to the Mouse Class driver */
257 DeviceExtension
->InputDataCount
[Queue
]++;
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;
269 /* Copy RawButtons to Previous Buttons for Input */
270 DeviceExtension
->PreviousButtons
= Input
->RawButtons
;
275 PsTerminateSystemThread(STATUS_SUCCESS
);