1 /* 2 * PROJECT: ReactOS Serial mouse driver 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/input/sermouse/detect.c 5 * PURPOSE: Detect serial mouse type 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 <ntifs.h> 14 #include <debug.h> 15 16 /* Most of this file is ripped from reactos/drivers/bus/serenum/detect.c */ 17 18 static NTSTATUS 19 DeviceIoControl( 20 IN PDEVICE_OBJECT DeviceObject, 21 IN ULONG CtlCode, 22 IN PVOID InputBuffer OPTIONAL, 23 IN SIZE_T InputBufferSize, 24 IN OUT PVOID OutputBuffer OPTIONAL, 25 IN OUT PSIZE_T OutputBufferSize) 26 { 27 KEVENT Event; 28 PIRP Irp; 29 IO_STATUS_BLOCK IoStatus; 30 NTSTATUS Status; 31 32 KeInitializeEvent (&Event, NotificationEvent, FALSE); 33 34 Irp = IoBuildDeviceIoControlRequest(CtlCode, 35 DeviceObject, 36 InputBuffer, 37 (ULONG)InputBufferSize, 38 OutputBuffer, 39 (OutputBufferSize) ? (ULONG)*OutputBufferSize : 0, 40 FALSE, 41 &Event, 42 &IoStatus); 43 if (Irp == NULL) 44 { 45 WARN_(SERMOUSE, "IoBuildDeviceIoControlRequest() failed\n"); 46 return STATUS_INSUFFICIENT_RESOURCES; 47 } 48 49 Status = IoCallDriver(DeviceObject, Irp); 50 51 if (Status == STATUS_PENDING) 52 { 53 INFO_(SERMOUSE, "Operation pending\n"); 54 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 55 Status = IoStatus.Status; 56 } 57 58 if (OutputBufferSize) 59 { 60 *OutputBufferSize = (SIZE_T)IoStatus.Information; 61 } 62 63 return Status; 64 } 65 66 static NTSTATUS 67 ReadBytes( 68 IN PDEVICE_OBJECT LowerDevice, 69 OUT PUCHAR Buffer, 70 IN ULONG BufferSize, 71 OUT PULONG_PTR FilledBytes) 72 { 73 PIRP Irp; 74 IO_STATUS_BLOCK ioStatus; 75 KEVENT event; 76 LARGE_INTEGER zero; 77 NTSTATUS Status; 78 79 KeInitializeEvent(&event, NotificationEvent, FALSE); 80 zero.QuadPart = 0; 81 Irp = IoBuildSynchronousFsdRequest( 82 IRP_MJ_READ, 83 LowerDevice, 84 Buffer, BufferSize, 85 &zero, 86 &event, 87 &ioStatus); 88 if (!Irp) 89 return FALSE; 90 91 Status = IoCallDriver(LowerDevice, Irp); 92 if (Status == STATUS_PENDING) 93 { 94 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 95 Status = ioStatus.Status; 96 } 97 INFO_(SERMOUSE, "Bytes received: %lu/%lu\n", 98 ioStatus.Information, BufferSize); 99 *FilledBytes = ioStatus.Information; 100 return Status; 101 } 102 103 static NTSTATUS 104 Wait( 105 IN ULONG milliseconds) 106 { 107 KTIMER Timer; 108 LARGE_INTEGER DueTime; 109 110 DueTime.QuadPart = milliseconds * -10; 111 KeInitializeTimer(&Timer); 112 KeSetTimer(&Timer, DueTime, NULL); 113 return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL); 114 } 115 116 SERMOUSE_MOUSE_TYPE 117 SermouseDetectLegacyDevice( 118 IN PDEVICE_OBJECT LowerDevice) 119 { 120 HANDLE Handle; 121 ULONG Fcr, Mcr; 122 ULONG BaudRate; 123 ULONG Command; 124 SERIAL_TIMEOUTS Timeouts; 125 SERIAL_LINE_CONTROL LCR; 126 ULONG_PTR i, Count = 0; 127 UCHAR Buffer[16]; 128 SERMOUSE_MOUSE_TYPE MouseType = mtNone; 129 NTSTATUS Status; 130 131 TRACE_(SERMOUSE, "SermouseDetectLegacyDevice(LowerDevice %p)\n", LowerDevice); 132 133 RtlZeroMemory(Buffer, sizeof(Buffer)); 134 135 /* Open port */ 136 Status = ObOpenObjectByPointer( 137 LowerDevice, 138 OBJ_KERNEL_HANDLE, 139 NULL, 140 0, 141 NULL, 142 KernelMode, 143 &Handle); 144 if (!NT_SUCCESS(Status)) return mtNone; 145 146 /* Reset UART */ 147 TRACE_(SERMOUSE, "Reset UART\n"); 148 Mcr = 0; /* MCR: DTR/RTS/OUT2 off */ 149 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL, 150 &Mcr, sizeof(Mcr), NULL, NULL); 151 if (!NT_SUCCESS(Status)) goto ByeBye; 152 153 /* Set communications parameters */ 154 TRACE_(SERMOUSE, "Set communications parameters\n"); 155 /* DLAB off */ 156 Fcr = 0; 157 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL, 158 &Fcr, sizeof(Fcr), NULL, NULL); 159 if (!NT_SUCCESS(Status)) goto ByeBye; 160 /* Set serial port speed */ 161 BaudRate = 1200; 162 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE, 163 &BaudRate, sizeof(BaudRate), NULL, NULL); 164 if (!NT_SUCCESS(Status)) goto ByeBye; 165 /* Set LCR */ 166 LCR.WordLength = 7; 167 LCR.Parity = NO_PARITY; 168 LCR.StopBits = STOP_BITS_2; 169 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL, 170 &LCR, sizeof(LCR), NULL, NULL); 171 if (!NT_SUCCESS(Status)) goto ByeBye; 172 173 /* Flush receive buffer */ 174 TRACE_(SERMOUSE, "Flush receive buffer\n"); 175 Command = SERIAL_PURGE_RXCLEAR; 176 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL, 177 &Command, sizeof(Command), NULL, NULL); 178 if (!NT_SUCCESS(Status)) goto ByeBye; 179 /* Wait 100 ms */ 180 Wait(100); 181 182 /* Enable DTR/RTS */ 183 TRACE_(SERMOUSE, "Enable DTR/RTS\n"); 184 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR, 185 NULL, 0, NULL, NULL); 186 if (!NT_SUCCESS(Status)) goto ByeBye; 187 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS, 188 NULL, 0, NULL, NULL); 189 if (!NT_SUCCESS(Status)) goto ByeBye; 190 191 /* Set timeout to 500 microseconds */ 192 TRACE_(SERMOUSE, "Set timeout to 500 microseconds\n"); 193 Timeouts.ReadIntervalTimeout = 100; 194 Timeouts.ReadTotalTimeoutMultiplier = 0; 195 Timeouts.ReadTotalTimeoutConstant = 500; 196 Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0; 197 Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS, 198 &Timeouts, sizeof(Timeouts), NULL, NULL); 199 if (!NT_SUCCESS(Status)) goto ByeBye; 200 201 /* Fill the read buffer */ 202 TRACE_(SERMOUSE, "Fill the read buffer\n"); 203 Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count); 204 if (!NT_SUCCESS(Status)) goto ByeBye; 205 206 for (i = 0; i < Count; i++) 207 { 208 if (Buffer[i] == 'B') 209 { 210 /* Sign for Microsoft Ballpoint */ 211 ERR_(SERMOUSE, "Microsoft Ballpoint device detected. THIS DEVICE IS NOT YET SUPPORTED"); 212 MouseType = mtNone; 213 goto ByeBye; 214 } 215 else if (Buffer[i] == 'M') 216 { 217 /* Sign for Microsoft Mouse protocol followed by button specifier */ 218 if (i == sizeof(Buffer) - 1) 219 { 220 /* Overflow Error */ 221 goto ByeBye; 222 } 223 switch (Buffer[i + 1]) 224 { 225 case '3': 226 INFO_(SERMOUSE, "Microsoft Mouse with 3-buttons detected\n"); 227 MouseType = mtLogitech; 228 break; 229 case 'Z': 230 INFO_(SERMOUSE, "Microsoft Wheel Mouse detected\n"); 231 MouseType = mtWheelZ; 232 break; 233 default: 234 INFO_(SERMOUSE, "Microsoft Mouse with 2-buttons detected\n"); 235 MouseType = mtMicrosoft; 236 break; 237 } 238 goto ByeBye; 239 } 240 } 241 242 ByeBye: 243 /* Close port */ 244 if (Handle) 245 ZwClose(Handle); 246 return MouseType; 247 } 248