xref: /reactos/drivers/serial/serenum/fdo.c (revision d2aeaba5)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Serial enumerator driver
4  * FILE:            drivers/bus/serenum/fdo.c
5  * PURPOSE:         IRP_MJ_PNP operations for FDOs
6  *
7  * PROGRAMMERS:     Herv� Poussineau (hpoussin@reactos.org)
8  */
9 
10 #include "serenum.h"
11 
12 #include <debug.h>
13 
14 NTSTATUS NTAPI
15 SerenumAddDevice(
16 	IN PDRIVER_OBJECT DriverObject,
17 	IN PDEVICE_OBJECT Pdo)
18 {
19 	PDEVICE_OBJECT Fdo;
20 	PFDO_DEVICE_EXTENSION DeviceExtension;
21 	NTSTATUS Status;
22 
23 	TRACE_(SERENUM, "SerenumAddDevice called. Pdo = %p\n", Pdo);
24 
25 	/* Create new device object */
26 	Status = IoCreateDevice(DriverObject,
27 	                        sizeof(FDO_DEVICE_EXTENSION),
28 	                        NULL,
29 	                        FILE_DEVICE_BUS_EXTENDER,
30 	                        FILE_DEVICE_SECURE_OPEN,
31 	                        FALSE,
32 	                        &Fdo);
33 	if (!NT_SUCCESS(Status))
34 	{
35 		WARN_(SERENUM, "IoCreateDevice() failed with status 0x%08lx\n", Status);
36 		return Status;
37 	}
38 	DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
39 	RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
40 
41 	/* Register device interface */
42 	Status = IoRegisterDeviceInterface(
43 		Pdo,
44 		&GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
45 		NULL,
46 		&DeviceExtension->SerenumInterfaceName);
47 	if (!NT_SUCCESS(Status))
48 	{
49 		WARN_(SERENUM, "IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
50 		IoDeleteDevice(Fdo);
51 		return Status;
52 	}
53 
54 	DeviceExtension->Common.IsFDO = TRUE;
55 	DeviceExtension->Common.PnpState = dsStopped;
56 	DeviceExtension->Pdo = Pdo;
57 	IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERENUM_TAG, 0, 0);
58 	Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
59 	if (!NT_SUCCESS(Status))
60 	{
61 		WARN_(SERENUM, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
62 		IoDeleteDevice(Fdo);
63 		return Status;
64 	}
65 	if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
66 		Fdo->Flags |= DO_POWER_PAGABLE;
67 	if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
68 		Fdo->Flags |= DO_BUFFERED_IO;
69 	if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
70 		Fdo->Flags |= DO_DIRECT_IO;
71 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
72 
73 	return STATUS_SUCCESS;
74 }
75 
76 static NTSTATUS NTAPI
77 SerenumFdoStartDevice(
78 	IN PDEVICE_OBJECT DeviceObject,
79 	IN PIRP Irp)
80 {
81 	PFDO_DEVICE_EXTENSION DeviceExtension;
82 	NTSTATUS Status;
83 
84 	TRACE_(SERENUM, "SerenumFdoStartDevice() called\n");
85 	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
86 
87 	ASSERT(DeviceExtension->Common.PnpState == dsStopped);
88 
89 	Status = IoSetDeviceInterfaceState(&DeviceExtension->SerenumInterfaceName, TRUE);
90 	if (!NT_SUCCESS(Status))
91 	{
92 		WARN_(SERENUM, "IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status);
93 		return Status;
94 	}
95 
96 	DeviceExtension->Common.PnpState = dsStarted;
97 
98 	return STATUS_SUCCESS;
99 }
100 
101 static NTSTATUS
102 SerenumFdoQueryBusRelations(
103 	IN PDEVICE_OBJECT DeviceObject,
104 	OUT PDEVICE_RELATIONS* pDeviceRelations)
105 {
106 	PFDO_DEVICE_EXTENSION DeviceExtension;
107 	PDEVICE_RELATIONS DeviceRelations;
108 	ULONG NumPDO;
109 	ULONG i;
110 	NTSTATUS Status = STATUS_SUCCESS;
111 
112 	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
113 	ASSERT(DeviceExtension->Common.IsFDO);
114 
115 	/* Do enumeration if needed */
116 	if (!(DeviceExtension->Flags & FLAG_ENUMERATION_DONE))
117 	{
118 		ASSERT(DeviceExtension->AttachedPdo == NULL);
119 		/* Detect plug-and-play devices */
120 		Status = SerenumDetectPnpDevice(DeviceObject, DeviceExtension->LowerDevice);
121 		if (Status == STATUS_DEVICE_NOT_CONNECTED)
122 		{
123 			/* Detect legacy devices */
124 			Status = SerenumDetectLegacyDevice(DeviceObject, DeviceExtension->LowerDevice);
125 			if (Status == STATUS_DEVICE_NOT_CONNECTED)
126 				Status = STATUS_SUCCESS;
127 		}
128 		DeviceExtension->Flags |= FLAG_ENUMERATION_DONE;
129 	}
130 	NumPDO = (DeviceExtension->AttachedPdo != NULL ? 1 : 0);
131 
132 	DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
133 		PagedPool,
134 		sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (NumPDO - 1),
135 		SERENUM_TAG);
136 	if (!DeviceRelations)
137 		return STATUS_INSUFFICIENT_RESOURCES;
138 
139 	/* Fill returned structure */
140 	DeviceRelations->Count = NumPDO;
141 	for (i = 0; i < NumPDO; i++)
142 	{
143 		ObReferenceObject(DeviceExtension->AttachedPdo);
144 		DeviceRelations->Objects[i] = DeviceExtension->AttachedPdo;
145 	}
146 
147 	*pDeviceRelations = DeviceRelations;
148 	return Status;
149 }
150 
151 NTSTATUS
152 SerenumFdoPnp(
153 	IN PDEVICE_OBJECT DeviceObject,
154 	IN PIRP Irp)
155 {
156 	PFDO_DEVICE_EXTENSION FdoExtension;
157 	ULONG MinorFunction;
158 	PIO_STACK_LOCATION Stack;
159 	ULONG_PTR Information = 0;
160 	NTSTATUS Status;
161 
162 	Stack = IoGetCurrentIrpStackLocation(Irp);
163 	MinorFunction = Stack->MinorFunction;
164 
165 	switch (MinorFunction)
166 	{
167 		/* FIXME: do all these minor functions
168 		IRP_MN_QUERY_REMOVE_DEVICE 0x1
169 		IRP_MN_REMOVE_DEVICE 0x2
170 		IRP_MN_CANCEL_REMOVE_DEVICE 0x3
171 		IRP_MN_STOP_DEVICE 0x4
172 		IRP_MN_QUERY_STOP_DEVICE 0x5
173 		IRP_MN_CANCEL_STOP_DEVICE 0x6
174 		IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
175 		IRP_MN_QUERY_INTERFACE (optional) 0x8
176 		IRP_MN_QUERY_CAPABILITIES (optional) 0x9
177 		IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
178 		IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
179 		IRP_MN_SURPRISE_REMOVAL 0x17
180 		*/
181 		case IRP_MN_START_DEVICE: /* 0x0 */
182 		{
183 			TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
184 			/* Call lower driver */
185 			FdoExtension = DeviceObject->DeviceExtension;
186 			Status = STATUS_UNSUCCESSFUL;
187 
188 			if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp))
189 			{
190 				Status = Irp->IoStatus.Status;
191 				if (NT_SUCCESS(Status))
192 				{
193 					Status = SerenumFdoStartDevice(DeviceObject, Irp);
194 				}
195 			}
196 
197 			break;
198 		}
199 		case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
200 		{
201 			switch (Stack->Parameters.QueryDeviceRelations.Type)
202 			{
203 				case BusRelations:
204 				{
205 					PDEVICE_RELATIONS DeviceRelations = NULL;
206 					TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
207 					Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations);
208 					Information = (ULONG_PTR)DeviceRelations;
209 					break;
210 				}
211 				default:
212 					TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
213 						Stack->Parameters.QueryDeviceRelations.Type);
214 					return ForwardIrpAndForget(DeviceObject, Irp);
215 			}
216 			break;
217 		}
218 		case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */
219 		{
220 			TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
221 			return ForwardIrpAndForget(DeviceObject, Irp);
222 		}
223 		default:
224 		{
225 			TRACE_(SERENUM, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
226 			return ForwardIrpAndForget(DeviceObject, Irp);
227 		}
228 	}
229 
230 	Irp->IoStatus.Information = Information;
231 	Irp->IoStatus.Status = Status;
232 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
233 	return Status;
234 }
235