xref: /reactos/drivers/input/sermouse/fdo.c (revision c2c66aff)
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:     IRP_MJ_PNP operations for FDOs
6  * PROGRAMMERS: Copyright 2005-2006 Herv� Poussineau (hpoussin@reactos.org)
7  */
8 
9 #include "sermouse.h"
10 
11 #include <debug.h>
12 
13 NTSTATUS NTAPI
14 SermouseAddDevice(
15 	IN PDRIVER_OBJECT DriverObject,
16 	IN PDEVICE_OBJECT Pdo)
17 {
18 	PSERMOUSE_DRIVER_EXTENSION DriverExtension;
19 	PDEVICE_OBJECT Fdo;
20 	PSERMOUSE_DEVICE_EXTENSION DeviceExtension = NULL;
21 	NTSTATUS Status;
22 
23 	TRACE_(SERMOUSE, "SermouseAddDevice called. Pdo = 0x%p\n", Pdo);
24 
25 	if (Pdo == NULL)
26 		return STATUS_SUCCESS;
27 
28 	/* Create new device object */
29 	DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
30 	Status = IoCreateDevice(
31 		DriverObject,
32 		sizeof(SERMOUSE_DEVICE_EXTENSION),
33 		NULL,
34 		FILE_DEVICE_SERIAL_MOUSE_PORT,
35 		FILE_DEVICE_SECURE_OPEN,
36 		TRUE,
37 		&Fdo);
38 	if (!NT_SUCCESS(Status))
39 	{
40 		WARN_(SERMOUSE, "IoCreateDevice() failed with status 0x%08lx\n", Status);
41 		goto cleanup;
42 	}
43 
44 	DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)Fdo->DeviceExtension;
45 	RtlZeroMemory(DeviceExtension, sizeof(SERMOUSE_DEVICE_EXTENSION));
46 	DeviceExtension->MouseType = mtNone;
47 	DeviceExtension->PnpState = dsStopped;
48 	DeviceExtension->DriverExtension = DriverExtension;
49 	KeInitializeEvent(&DeviceExtension->StopWorkerThreadEvent, NotificationEvent, FALSE);
50 	Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
51 	if (!NT_SUCCESS(Status))
52 	{
53 		WARN_(SERMOUSE, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
54 		goto cleanup;
55 	}
56 	if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
57 		Fdo->Flags |= DO_POWER_PAGABLE;
58 	if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
59 		Fdo->Flags |= DO_BUFFERED_IO;
60 	if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
61 		Fdo->Flags |= DO_DIRECT_IO;
62 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
63 
64 	return STATUS_SUCCESS;
65 
66 cleanup:
67 	if (DeviceExtension)
68 	{
69 		if (DeviceExtension->LowerDevice)
70 			IoDetachDevice(DeviceExtension->LowerDevice);
71 	}
72 	if (Fdo)
73 	{
74 		IoDeleteDevice(Fdo);
75 	}
76 	return Status;
77 }
78 
79 NTSTATUS NTAPI
80 SermouseStartDevice(
81 	IN PDEVICE_OBJECT DeviceObject,
82 	IN PIRP Irp)
83 {
84 	PSERMOUSE_DEVICE_EXTENSION DeviceExtension;
85 	SERMOUSE_MOUSE_TYPE MouseType;
86 	NTSTATUS Status;
87 
88 	DeviceExtension = (PSERMOUSE_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
89 
90 	ASSERT(DeviceExtension->PnpState == dsStopped);
91 	ASSERT(DeviceExtension->LowerDevice);
92 	MouseType = SermouseDetectLegacyDevice(DeviceExtension->LowerDevice);
93 	if (MouseType == mtNone)
94 	{
95 		WARN_(SERMOUSE, "No mouse connected to Fdo %p\n",
96 			DeviceExtension->LowerDevice);
97 		return STATUS_DEVICE_NOT_CONNECTED;
98 	}
99 
100 	switch (MouseType)
101 	{
102 		case mtMicrosoft:
103 			DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
104 			DeviceExtension->AttributesInformation.NumberOfButtons = 2;
105 			break;
106 		case mtLogitech:
107 			DeviceExtension->AttributesInformation.MouseIdentifier = MOUSE_SERIAL_HARDWARE;
108 			DeviceExtension->AttributesInformation.NumberOfButtons = 3;
109 			break;
110 		case mtWheelZ:
111 			DeviceExtension->AttributesInformation.MouseIdentifier = WHEELMOUSE_SERIAL_HARDWARE;
112 			DeviceExtension->AttributesInformation.NumberOfButtons = 3;
113 			break;
114 		default:
115 			WARN_(SERMOUSE, "Unknown mouse type 0x%lx\n", MouseType);
116 			ASSERT(FALSE);
117 			return STATUS_UNSUCCESSFUL;
118 	}
119 
120 	if (DeviceExtension->DriverExtension->NumberOfButtons != 0)
121 		/* Override the number of buttons */
122 		DeviceExtension->AttributesInformation.NumberOfButtons = DeviceExtension->DriverExtension->NumberOfButtons;
123 
124 	DeviceExtension->AttributesInformation.SampleRate = 1200 / 8;
125 	DeviceExtension->AttributesInformation.InputDataQueueLength = 1;
126 	DeviceExtension->MouseType = MouseType;
127 	DeviceExtension->PnpState = dsStarted;
128 
129 	/* Start read loop */
130 	Status = PsCreateSystemThread(
131 		&DeviceExtension->WorkerThreadHandle,
132 		(ACCESS_MASK)0L,
133 		NULL,
134 		NULL,
135 		NULL,
136 		SermouseDeviceWorker,
137 		DeviceObject);
138 
139 	return Status;
140 }
141 
142 NTSTATUS NTAPI
143 SermousePnp(
144 	IN PDEVICE_OBJECT DeviceObject,
145 	IN PIRP Irp)
146 {
147 	ULONG MinorFunction;
148 	PIO_STACK_LOCATION Stack;
149 	ULONG_PTR Information = 0;
150 	NTSTATUS Status;
151 
152 	Stack = IoGetCurrentIrpStackLocation(Irp);
153 	MinorFunction = Stack->MinorFunction;
154 	Information = Irp->IoStatus.Information;
155 
156 	switch (MinorFunction)
157 	{
158 		/* FIXME: do all these minor functions
159 		IRP_MN_QUERY_REMOVE_DEVICE 0x1
160 		IRP_MN_REMOVE_DEVICE 0x2
161 		IRP_MN_CANCEL_REMOVE_DEVICE 0x3
162 		IRP_MN_STOP_DEVICE 0x4
163 		IRP_MN_QUERY_STOP_DEVICE 0x5
164 		IRP_MN_CANCEL_STOP_DEVICE 0x6
165 		IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
166 		IRP_MN_QUERY_INTERFACE (optional) 0x8
167 		IRP_MN_QUERY_CAPABILITIES (optional) 0x9
168 		IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional or required) 0xd
169 		IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
170 		IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
171 		IRP_MN_SURPRISE_REMOVAL 0x17
172 		*/
173 		case IRP_MN_START_DEVICE: /* 0x0 */
174 		{
175 			TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
176 			/* Call lower driver */
177 			Status = ForwardIrpAndWait(DeviceObject, Irp);
178 			if (NT_SUCCESS(Status))
179 				Status = SermouseStartDevice(DeviceObject, Irp);
180 			break;
181 		}
182 		case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
183 		{
184 			switch (Stack->Parameters.QueryDeviceRelations.Type)
185 			{
186 				case BusRelations:
187 				{
188 					PDEVICE_RELATIONS DeviceRelations = NULL;
189 					TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
190 
191 					DeviceRelations = ExAllocatePoolWithTag(PagedPool, FIELD_OFFSET(DEVICE_RELATIONS, Objects), SERMOUSE_TAG);
192 					if (!DeviceRelations)
193 					{
194 						WARN_(SERMOUSE, "ExAllocatePoolWithTag() failed\n");
195 						Status = STATUS_NO_MEMORY;
196 					}
197 					else
198 					{
199 						DeviceRelations->Count = 0;
200 						Status = STATUS_SUCCESS;
201 						Information = (ULONG_PTR)DeviceRelations;
202 					}
203 					break;
204 				}
205 				default:
206 				{
207 					TRACE_(SERMOUSE, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
208 						Stack->Parameters.QueryDeviceRelations.Type);
209 					return ForwardIrpAndForget(DeviceObject, Irp);
210 				}
211 			}
212 			break;
213 		}
214 		default:
215 		{
216 			TRACE_(SERMOUSE, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
217 			return ForwardIrpAndForget(DeviceObject, Irp);
218 		}
219 	}
220 
221 	Irp->IoStatus.Information = Information;
222 	Irp->IoStatus.Status = Status;
223 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
224 	return Status;
225 }
226