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
DeviceIoControl(IN PDEVICE_OBJECT DeviceObject,IN ULONG CtlCode,IN PVOID InputBuffer OPTIONAL,IN SIZE_T InputBufferSize,IN OUT PVOID OutputBuffer OPTIONAL,IN OUT PSIZE_T OutputBufferSize)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
ReadBytes(IN PDEVICE_OBJECT LowerDevice,OUT PUCHAR Buffer,IN ULONG BufferSize,OUT PULONG_PTR FilledBytes)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
Wait(IN ULONG milliseconds)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
SermouseDetectLegacyDevice(IN PDEVICE_OBJECT LowerDevice)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