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 #include <debug.h> 14 15 static NTSTATUS 16 SermouseDeviceIoControl( 17 IN PDEVICE_OBJECT DeviceObject, 18 IN ULONG CtlCode, 19 IN PVOID InputBuffer OPTIONAL, 20 IN ULONG InputBufferSize, 21 IN OUT PVOID OutputBuffer OPTIONAL, 22 IN OUT PULONG OutputBufferSize) 23 { 24 KEVENT Event; 25 PIRP Irp; 26 IO_STATUS_BLOCK IoStatus; 27 NTSTATUS Status; 28 29 KeInitializeEvent(&Event, NotificationEvent, FALSE); 30 31 Irp = IoBuildDeviceIoControlRequest(CtlCode, 32 DeviceObject, 33 InputBuffer, 34 InputBufferSize, 35 OutputBuffer, 36 (OutputBufferSize) ? *OutputBufferSize : 0, 37 FALSE, 38 &Event, 39 &IoStatus); 40 if (Irp == NULL) 41 { 42 WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n"); 43 return STATUS_INSUFFICIENT_RESOURCES; 44 } 45 46 Status = IoCallDriver(DeviceObject, Irp); 47 48 if (Status == STATUS_PENDING) 49 { 50 INFO_(SERMOUSE, "Operation pending\n"); 51 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 52 Status = IoStatus.Status; 53 } 54 55 if (OutputBufferSize) 56 { 57 *OutputBufferSize = (ULONG)IoStatus.Information; 58 } 59 60 return Status; 61 } 62 63 VOID NTAPI 64 SermouseDeviceWorker( 65 PVOID Context) 66 { 67 PSERMOUSE_DEVICE_EXTENSION DeviceExtension; 68 PDEVICE_OBJECT LowerDevice; 69 UCHAR Buffer[PACKET_BUFFER_SIZE]; 70 PIRP Irp; 71 IO_STATUS_BLOCK ioStatus; 72 KEVENT event; 73 PUCHAR PacketBuffer; 74 UCHAR ReceivedByte; 75 ULONG Queue; 76 PMOUSE_INPUT_DATA Input; 77 ULONG ButtonsDifference; 78 KIRQL OldIrql; 79 ULONG i; 80 ULONG Fcr; 81 ULONG BaudRate; 82 SERIAL_TIMEOUTS Timeouts; 83 SERIAL_LINE_CONTROL LCR; 84 LARGE_INTEGER Zero; 85 NTSTATUS Status; 86 87 TRACE_(SERMOUSE, "SermouseDeviceWorker() called\n"); 88 89 DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension; 90 LowerDevice = DeviceExtension->LowerDevice; 91 Zero.QuadPart = 0; 92 PacketBuffer = DeviceExtension->PacketBuffer; 93 94 ASSERT(LowerDevice); 95 96 /* Initialize device extension */ 97 DeviceExtension->ActiveQueue = 0; 98 DeviceExtension->PacketBufferPosition = 0; 99 DeviceExtension->PreviousButtons = 0; 100 101 /* Initialize serial port */ 102 Fcr = 0; 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); 111 /* Set LCR */ 112 LCR.WordLength = 7; 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); 118 119 /* Set timeouts */ 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); 126 127 /* main read loop */ 128 RtlZeroMemory(Buffer, PACKET_BUFFER_SIZE); 129 while (TRUE) 130 { 131 Status = KeWaitForSingleObject( 132 &DeviceExtension->StopWorkerThreadEvent, 133 Executive, 134 KernelMode, 135 TRUE, 136 &Zero); 137 if (Status != STATUS_TIMEOUT) 138 { 139 /* we need to stop the worker thread */ 140 KeClearEvent(&DeviceExtension->StopWorkerThreadEvent); 141 break; 142 } 143 144 KeInitializeEvent(&event, NotificationEvent, FALSE); 145 Irp = IoBuildSynchronousFsdRequest( 146 IRP_MJ_READ, 147 LowerDevice, 148 Buffer, PACKET_BUFFER_SIZE, 149 &Zero, 150 &event, 151 &ioStatus); 152 if (!Irp) 153 { 154 /* No memory actually, try later */ 155 INFO_(SERMOUSE, "No memory actually, trying again\n"); 156 KeStallExecutionProcessor(10); 157 continue; 158 } 159 160 Status = IoCallDriver(LowerDevice, Irp); 161 if (Status == STATUS_PENDING) 162 { 163 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 164 Status = ioStatus.Status; 165 } 166 167 if (!NT_SUCCESS(Status)) 168 continue; 169 170 /* Read all available data and process */ 171 for (i = 0; i < ioStatus.Information; i++) 172 { 173 ReceivedByte = Buffer[i]; 174 INFO_(SERMOUSE, "ReceivedByte 0x%02x\n", ReceivedByte); 175 176 /* Synchronize */ 177 if ((ReceivedByte & 0x40) == 0x40) 178 DeviceExtension->PacketBufferPosition = 0; 179 180 PacketBuffer[DeviceExtension->PacketBufferPosition] = ReceivedByte & 0x7f; 181 DeviceExtension->PacketBufferPosition++; 182 183 /* Process packet if complete */ 184 if (DeviceExtension->PacketBufferPosition >= 3) 185 { 186 Queue = DeviceExtension->ActiveQueue % 2; 187 188 /* Prevent buffer overflow */ 189 if (DeviceExtension->InputDataCount[Queue] == 1) 190 continue; 191 192 Input = &DeviceExtension->MouseInputData[Queue]; 193 194 if (DeviceExtension->PacketBufferPosition == 3) 195 { 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)); 199 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); 204 } 205 else if (DeviceExtension->PacketBufferPosition == 4) 206 { 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)) 211 { 212 Input->RawButtons ^= MOUSE_BUTTON_MIDDLE; 213 Input->LastX = 0; 214 Input->LastY = 0; 215 } 216 else 217 { 218 continue; 219 } 220 } 221 222 /* Determine ButtonFlags */ 223 Input->ButtonFlags = 0; 224 ButtonsDifference = DeviceExtension->PreviousButtons ^ Input->RawButtons; 225 226 if (ButtonsDifference != 0) 227 { 228 if (ButtonsDifference & MOUSE_BUTTON_LEFT 229 && DeviceExtension->AttributesInformation.NumberOfButtons >= 1) 230 { 231 if (Input->RawButtons & MOUSE_BUTTON_LEFT) 232 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN; 233 else 234 Input->ButtonFlags |= MOUSE_LEFT_BUTTON_UP; 235 } 236 237 if (ButtonsDifference & MOUSE_BUTTON_RIGHT 238 && DeviceExtension->AttributesInformation.NumberOfButtons >= 2) 239 { 240 if (Input->RawButtons & MOUSE_BUTTON_RIGHT) 241 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN; 242 else 243 Input->ButtonFlags |= MOUSE_RIGHT_BUTTON_UP; 244 } 245 246 if (ButtonsDifference & MOUSE_BUTTON_MIDDLE 247 && DeviceExtension->AttributesInformation.NumberOfButtons >= 3) 248 { 249 if (Input->RawButtons & MOUSE_BUTTON_MIDDLE) 250 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN; 251 else 252 Input->ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP; 253 } 254 } 255 256 /* Send the Input data to the Mouse Class driver */ 257 DeviceExtension->InputDataCount[Queue]++; 258 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; 268 269 /* Copy RawButtons to Previous Buttons for Input */ 270 DeviceExtension->PreviousButtons = Input->RawButtons; 271 } 272 } 273 } 274 275 PsTerminateSystemThread(STATUS_SUCCESS); 276 } 277