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