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