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