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