1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Serial enumerator driver
4 * FILE: drivers/bus/serenum/pdo.c
5 * PURPOSE: IRP_MJ_PNP operations for PDOs
6 *
7 * PROGRAMMERS: Herv� Poussineau (hpoussin@reactos.org)
8 */
9
10 #include "serenum.h"
11
12 #include <debug.h>
13
14 static NTSTATUS
SerenumPdoStartDevice(IN PDEVICE_OBJECT DeviceObject)15 SerenumPdoStartDevice(
16 IN PDEVICE_OBJECT DeviceObject)
17 {
18 PPDO_DEVICE_EXTENSION DeviceExtension;
19
20 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
21
22 ASSERT(DeviceExtension->Common.PnpState == dsStopped);
23
24 DeviceExtension->Common.PnpState = dsStarted;
25 return STATUS_SUCCESS;
26 }
27
28 static NTSTATUS
SerenumPdoQueryId(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,OUT ULONG_PTR * Information)29 SerenumPdoQueryId(
30 IN PDEVICE_OBJECT DeviceObject,
31 IN PIRP Irp,
32 OUT ULONG_PTR* Information)
33 {
34 PPDO_DEVICE_EXTENSION DeviceExtension;
35 ULONG IdType;
36 PUNICODE_STRING SourceString;
37 UNICODE_STRING String;
38 NTSTATUS Status;
39
40 IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
41 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
42 RtlInitUnicodeString(&String, NULL);
43
44 switch (IdType)
45 {
46 case BusQueryDeviceID:
47 {
48 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
49 SourceString = &DeviceExtension->DeviceId;
50 break;
51 }
52 case BusQueryHardwareIDs:
53 {
54 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
55 SourceString = &DeviceExtension->HardwareIds;
56 break;
57 }
58 case BusQueryCompatibleIDs:
59 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
60 SourceString = &DeviceExtension->CompatibleIds;
61 break;
62 case BusQueryInstanceID:
63 {
64 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
65 SourceString = &DeviceExtension->InstanceId;
66 break;
67 }
68 default:
69 WARN_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
70 ASSERT(FALSE);
71 return STATUS_NOT_SUPPORTED;
72 }
73
74 Status = DuplicateUnicodeString(
75 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
76 SourceString,
77 &String);
78 *Information = (ULONG_PTR)String.Buffer;
79 return Status;
80 }
81
82 static NTSTATUS
SerenumPdoQueryDeviceRelations(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_RELATIONS * pDeviceRelations)83 SerenumPdoQueryDeviceRelations(
84 IN PDEVICE_OBJECT DeviceObject,
85 OUT PDEVICE_RELATIONS* pDeviceRelations)
86 {
87 PFDO_DEVICE_EXTENSION DeviceExtension;
88 PDEVICE_RELATIONS DeviceRelations;
89
90 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
91 ASSERT(DeviceExtension->Common.IsFDO);
92
93 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
94 PagedPool,
95 sizeof(DEVICE_RELATIONS),
96 SERENUM_TAG);
97 if (!DeviceRelations)
98 return STATUS_INSUFFICIENT_RESOURCES;
99
100 ObReferenceObject(DeviceObject);
101 DeviceRelations->Count = 1;
102 DeviceRelations->Objects[0] = DeviceObject;
103
104 *pDeviceRelations = DeviceRelations;
105 return STATUS_SUCCESS;
106 }
107
108 NTSTATUS
SerenumPdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)109 SerenumPdoPnp(
110 IN PDEVICE_OBJECT DeviceObject,
111 IN PIRP Irp)
112 {
113 ULONG MinorFunction;
114 PIO_STACK_LOCATION Stack;
115 ULONG_PTR Information = 0;
116 NTSTATUS Status;
117
118 Stack = IoGetCurrentIrpStackLocation(Irp);
119 MinorFunction = Stack->MinorFunction;
120
121 switch (MinorFunction)
122 {
123 /* FIXME: do all these minor functions
124 IRP_MN_QUERY_REMOVE_DEVICE 0x1
125 IRP_MN_REMOVE_DEVICE 0x2
126 IRP_MN_CANCEL_REMOVE_DEVICE 0x3
127 IRP_MN_STOP_DEVICE 0x4
128 IRP_MN_QUERY_STOP_DEVICE 0x5
129 IRP_MN_CANCEL_STOP_DEVICE 0x6
130 IRP_MN_QUERY_DEVICE_RELATIONS / EjectionRelations (optional) 0x7
131 IRP_MN_QUERY_INTERFACE (required or optional) 0x8
132 IRP_MN_READ_CONFIG (required or optional) 0xf
133 IRP_MN_WRITE_CONFIG (required or optional) 0x10
134 IRP_MN_EJECT (required or optional) 0x11
135 IRP_MN_SET_LOCK (required or optional) 0x12
136 IRP_MN_QUERY_ID / BusQueryDeviceID 0x13
137 IRP_MN_QUERY_ID / BusQueryCompatibleIDs (optional) 0x13
138 IRP_MN_QUERY_ID / BusQueryInstanceID (optional) 0x13
139 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
140 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
141 IRP_MN_SURPRISE_REMOVAL 0x17
142 */
143 case IRP_MN_START_DEVICE: /* 0x0 */
144 {
145 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
146 Status = SerenumPdoStartDevice(DeviceObject);
147 break;
148 }
149 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
150 {
151 switch (Stack->Parameters.QueryDeviceRelations.Type)
152 {
153 case RemovalRelations:
154 {
155 return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
156 }
157 case TargetDeviceRelation:
158 {
159 PDEVICE_RELATIONS DeviceRelations = NULL;
160 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
161 Status = SerenumPdoQueryDeviceRelations(DeviceObject, &DeviceRelations);
162 Information = (ULONG_PTR)DeviceRelations;
163 break;
164 }
165 default:
166 {
167 WARN_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
168 Stack->Parameters.QueryDeviceRelations.Type);
169 ASSERT(FALSE);
170 Status = STATUS_NOT_IMPLEMENTED;
171 break;
172 }
173 }
174 break;
175 }
176 case IRP_MN_QUERY_CAPABILITIES: /* 0x9 */
177 {
178 PDEVICE_CAPABILITIES DeviceCapabilities;
179 ULONG i;
180 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
181
182 DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
183 /* FIXME: capabilities can change with connected device */
184 DeviceCapabilities->LockSupported = FALSE;
185 DeviceCapabilities->EjectSupported = FALSE;
186 DeviceCapabilities->Removable = TRUE;
187 DeviceCapabilities->DockDevice = FALSE;
188 DeviceCapabilities->UniqueID = FALSE;
189 DeviceCapabilities->SilentInstall = FALSE;
190 DeviceCapabilities->RawDeviceOK = TRUE;
191 DeviceCapabilities->SurpriseRemovalOK = TRUE;
192 DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
193 //DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
194 DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
195 for (i = 0; i < PowerSystemMaximum; i++)
196 DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
197 //DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
198 DeviceCapabilities->D1Latency = 0; /* FIXME */
199 DeviceCapabilities->D2Latency = 0; /* FIXME */
200 DeviceCapabilities->D3Latency = 0; /* FIXME */
201 Status = STATUS_SUCCESS;
202 break;
203 }
204 case IRP_MN_QUERY_RESOURCES: /* 0xa */
205 {
206 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
207 /* Serial devices don't need resources, except the ones of
208 * the serial port. This PDO is the serial device PDO, so
209 * report no resource by not changing Information and
210 * Status
211 */
212 Information = Irp->IoStatus.Information;
213 Status = Irp->IoStatus.Status;
214 break;
215 }
216 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0xb */
217 {
218 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
219 /* Serial devices don't need resources, except the ones of
220 * the serial port. This PDO is the serial device PDO, so
221 * report no resource by not changing Information and
222 * Status
223 */
224 Information = Irp->IoStatus.Information;
225 Status = Irp->IoStatus.Status;
226 break;
227 }
228 case IRP_MN_QUERY_DEVICE_TEXT: /* 0xc */
229 {
230 switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
231 {
232 case DeviceTextDescription:
233 {
234 PUNICODE_STRING Source;
235 PWSTR Description;
236 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
237
238 Source = &((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceDescription;
239 Description = ExAllocatePoolWithTag(PagedPool, Source->Length + sizeof(WCHAR), SERENUM_TAG);
240 if (!Description)
241 Status = STATUS_INSUFFICIENT_RESOURCES;
242 else
243 {
244 RtlCopyMemory(Description, Source->Buffer, Source->Length);
245 Description[Source->Length / sizeof(WCHAR)] = L'\0';
246 Information = (ULONG_PTR)Description;
247 Status = STATUS_SUCCESS;
248 }
249 break;
250 }
251 case DeviceTextLocationInformation:
252 {
253 /* We don't have any text location to report,
254 * and this query is optional, so ignore it.
255 */
256 Information = Irp->IoStatus.Information;
257 Status = Irp->IoStatus.Status;
258 break;
259 }
260 default:
261 {
262 WARN_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
263 Stack->Parameters.QueryDeviceText.DeviceTextType);
264 ASSERT(FALSE);
265 Status = STATUS_NOT_SUPPORTED;
266 }
267 }
268 break;
269 }
270 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */
271 {
272 return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
273 }
274 case IRP_MN_QUERY_ID: /* 0x13 */
275 {
276 Status = SerenumPdoQueryId(DeviceObject, Irp, &Information);
277 break;
278 }
279 case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
280 {
281 PPNP_BUS_INFORMATION BusInfo;
282 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
283
284 BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), SERENUM_TAG);
285 if (!BusInfo)
286 Status = STATUS_INSUFFICIENT_RESOURCES;
287 else
288 {
289 memcpy(
290 &BusInfo->BusTypeGuid,
291 &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR,
292 sizeof(BusInfo->BusTypeGuid));
293 BusInfo->LegacyBusType = PNPBus;
294 /* We're the only serial bus enumerator on the computer */
295 BusInfo->BusNumber = 0;
296 Information = (ULONG_PTR)BusInfo;
297 Status = STATUS_SUCCESS;
298 }
299 break;
300 }
301 default:
302 {
303 /* We can't forward request to the lower driver, because
304 * we are a Pdo, so we don't have lower driver... */
305 WARN_(SERENUM, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
306 ASSERT(FALSE);
307 Information = Irp->IoStatus.Information;
308 Status = Irp->IoStatus.Status;
309 }
310 }
311
312 Irp->IoStatus.Information = Information;
313 Irp->IoStatus.Status = Status;
314 IoCompleteRequest(Irp, IO_NO_INCREMENT);
315 return Status;
316 }
317