xref: /reactos/drivers/serial/serenum/pdo.c (revision c2c66aff)
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