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