Sync with trunk r63383 .
[reactos.git] / drivers / serial / serenum / fdo.c
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 ULONG MinorFunction;
157 PIO_STACK_LOCATION Stack;
158 ULONG_PTR Information = 0;
159 NTSTATUS Status;
160
161 Stack = IoGetCurrentIrpStackLocation(Irp);
162 MinorFunction = Stack->MinorFunction;
163
164 switch (MinorFunction)
165 {
166 /* FIXME: do all these minor functions
167 IRP_MN_QUERY_REMOVE_DEVICE 0x1
168 IRP_MN_REMOVE_DEVICE 0x2
169 IRP_MN_CANCEL_REMOVE_DEVICE 0x3
170 IRP_MN_STOP_DEVICE 0x4
171 IRP_MN_QUERY_STOP_DEVICE 0x5
172 IRP_MN_CANCEL_STOP_DEVICE 0x6
173 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
174 IRP_MN_QUERY_INTERFACE (optional) 0x8
175 IRP_MN_QUERY_CAPABILITIES (optional) 0x9
176 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
177 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
178 IRP_MN_SURPRISE_REMOVAL 0x17
179 */
180 case IRP_MN_START_DEVICE: /* 0x0 */
181 {
182 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
183 /* Call lower driver */
184 Status = ForwardIrpAndWait(DeviceObject, Irp);
185 if (NT_SUCCESS(Status))
186 Status = SerenumFdoStartDevice(DeviceObject, Irp);
187 break;
188 }
189 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
190 {
191 switch (Stack->Parameters.QueryDeviceRelations.Type)
192 {
193 case BusRelations:
194 {
195 PDEVICE_RELATIONS DeviceRelations = NULL;
196 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
197 Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations);
198 Information = (ULONG_PTR)DeviceRelations;
199 break;
200 }
201 default:
202 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
203 Stack->Parameters.QueryDeviceRelations.Type);
204 return ForwardIrpAndForget(DeviceObject, Irp);
205 }
206 break;
207 }
208 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */
209 {
210 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
211 return ForwardIrpAndForget(DeviceObject, Irp);
212 }
213 default:
214 {
215 TRACE_(SERENUM, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
216 return ForwardIrpAndForget(DeviceObject, Irp);
217 }
218 }
219
220 Irp->IoStatus.Information = Information;
221 Irp->IoStatus.Status = Status;
222 IoCompleteRequest(Irp, IO_NO_INCREMENT);
223 return Status;
224 }