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)
16 SermouseDeviceIoControl(
17 IN PDEVICE_OBJECT DeviceObject
,
19 IN PVOID InputBuffer OPTIONAL
,
20 IN ULONG InputBufferSize
,
21 IN OUT PVOID OutputBuffer OPTIONAL
,
22 IN OUT PULONG OutputBufferSize
)
26 IO_STATUS_BLOCK IoStatus
;
29 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
31 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
36 (OutputBufferSize
) ? *OutputBufferSize
: 0,
42 WARN_(SERMOUSE
, "IoBuildDeviceIoControlRequest() failed\n");
43 return STATUS_INSUFFICIENT_RESOURCES
;
46 Status
= IoCallDriver(DeviceObject
, Irp
);
48 if (Status
== STATUS_PENDING
)
50 INFO_(SERMOUSE
, "Operation pending\n");
51 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
52 Status
= IoStatus
.Status
;
57 *OutputBufferSize
= (ULONG
)IoStatus
.Information
;
67 PSERMOUSE_DEVICE_EXTENSION DeviceExtension
;
68 PDEVICE_OBJECT LowerDevice
;
69 UCHAR Buffer
[PACKET_BUFFER_SIZE
];
71 IO_STATUS_BLOCK ioStatus
;
76 PMOUSE_INPUT_DATA Input
;
77 ULONG ButtonsDifference
;
82 SERIAL_TIMEOUTS Timeouts
;
83 SERIAL_LINE_CONTROL LCR
;
87 TRACE_(SERMOUSE
, "SermouseDeviceWorker() called\n");
89 DeviceExtension
= (PSERMOUSE_DEVICE_EXTENSION
)((PDEVICE_OBJECT
)Context
)->DeviceExtension
;
90 LowerDevice
= DeviceExtension
->LowerDevice
;
92 PacketBuffer
= DeviceExtension
->PacketBuffer
;
96 /* Initialize device extension */
97 DeviceExtension
->ActiveQueue
= 0;
98 DeviceExtension
->PacketBufferPosition
= 0;
99 DeviceExtension
->PreviousButtons
= 0;
101 /* Initialize serial port */
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
);
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
);
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
);
128 RtlZeroMemory(Buffer
, PACKET_BUFFER_SIZE
);
131 Status
= KeWaitForSingleObject(
132 &DeviceExtension
->StopWorkerThreadEvent
,
137 if (Status
!= STATUS_TIMEOUT
)
139 /* we need to stop the worker thread */
140 KeClearEvent(&DeviceExtension
->StopWorkerThreadEvent
);
144 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
145 Irp
= IoBuildSynchronousFsdRequest(
148 Buffer
, PACKET_BUFFER_SIZE
,
154 /* No memory actually, try later */
155 INFO_(SERMOUSE
, "No memory actually, trying again\n");
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 INFO_(SERMOUSE
, "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
);