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
SerenumAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT Pdo)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
SerenumFdoStartDevice(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
SerenumFdoQueryBusRelations(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_RELATIONS * pDeviceRelations)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
SerenumFdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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