xref: /reactos/modules/rosapps/drivers/vfd/vfdpnp.c (revision 3ff08b64)
1 /*
2 	vfdpnp.c
3 
4 	Virtual Floppy Drive for Windows NT platform
5 	Kernel mode driver: Plug & Play functions
6 
7 	Copyright (C) 2003-2005 Ken Kato
8 */
9 
10 #ifndef VFD_PNP
11 /*
12 	Not in working order for the time being
13 	so DO NOT define VFD_PNP macro
14 	unless you know exactly what you are doing...
15 */
16 #if !defined(__REACTOS__) || defined(_MSC_VER)
17 //	suppress empty compile unit warning
18 #pragma warning (disable: 4206)
19 #pragma message ("Plug and play support feature is disabled.")
20 #endif
21 
22 #else	// VFD_PNP
23 
24 #include "imports.h"
25 #include "vfddrv.h"
26 #include "vfddbg.h"
27 
28 static NTSTATUS
29 VfdReportDevice(
30 	PDEVICE_EXTENSION	device_extension);
31 
32 #ifdef ALLOC_PRAGMA
33 #pragma alloc_text(PAGE, VfdPlugAndPlay)
34 #pragma alloc_text(PAGE, VfdPowerControl)
35 #pragma alloc_text(PAGE, VfdSystemControl)
36 #pragma alloc_text(PAGE, VfdAddDevice)
37 #pragma alloc_text(PAGE, VfdReportDevice)
38 #endif	// ALLOC_PRAGMA
39 
40 #define REMLOCK_TAG				'LdfV'	//	"VfdL"
41 #define REMLOCK_MAXIMUM			1		//	Max minutes system allows lock to be held
42 #define REMLOCK_HIGHWATER		10		//	Max number of irps holding lock at one time
43 
44 #if DBG
45 static PCSTR StateTable[] ={
46 	{ "STOPPED"		},
47 	{ "WORKING"		},
48 	{ "PENDINGSTOP"	},
49 	{ "PENDINGREMOVE"	},
50 	{ "SURPRISEREMOVED" },
51 	{ "REMOVED"		},
52 	{ "UNKNOWN"		}
53 };
54 #endif	// DBG
55 
56 //
57 //	PnP I/O request dispatch
58 //
59 NTSTATUS
VfdPlugAndPlay(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)60 VfdPlugAndPlay(
61 	IN PDEVICE_OBJECT		DeviceObject,
62 	IN PIRP					Irp)
63 {
64 	PIO_STACK_LOCATION		io_stack;
65 	PDEVICE_EXTENSION		device_extension;
66 	NTSTATUS				status = STATUS_SUCCESS;
67 	BOOLEAN				lockHeld = TRUE;
68 
69 	//
70 	//	setup necessary pointers
71 	//
72 	io_stack			= IoGetCurrentIrpStackLocation( Irp );
73 	device_extension	= (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
74 
75 	ASSERT(device_extension->DeviceState < VFD_MAX_STATE);
76 
77 	VFDTRACE(VFDINFO, ("[VFD] VfdPlugAndPlay - IN. %ws %s Device State=%s\n",
78 		device_extension->device_name.Buffer,
79 		GetPnpIrpName(io_stack->MinorFunction),
80 		StateTable[device_extension->DeviceState]));
81 
82 	//
83 	//	Acquire remove lock
84 	//
85 	status = IoAcquireRemoveLock(&device_extension->RemoveLock, Irp);
86 
87 	if (!NT_SUCCESS(status)) {
88 		VFDTRACE(0, ("Acquire RemoveLock failed - %s\n", NtStatusToStr(status)));
89 
90 		Irp->IoStatus.Status = status;
91 		Irp->IoStatus.Information = 0;
92 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
93 		return status;
94 	}
95 
96 	//
97 	//	Process the PnP I/O request
98 	//
99 	switch (io_stack->MinorFunction) {
100 	case IRP_MN_START_DEVICE:					// 0x00
101 		//
102 		//	Start the device
103 		//
104 		device_extension->DeviceState = VFD_WORKING;
105 		status = STATUS_SUCCESS;
106 
107 		Irp->IoStatus.Status = status;
108 		Irp->IoStatus.Information = 0;
109 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
110 		break;
111 
112 	case IRP_MN_QUERY_REMOVE_DEVICE:					// 0x01
113 		//
114 		//	Prepare device removal
115 		//
116 		device_extension->DeviceState = VFD_PENDINGREMOVE;
117 		status = STATUS_SUCCESS;
118 
119 		Irp->IoStatus.Status = status;
120 		Irp->IoStatus.Information = 0;
121 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
122 		break;
123 
124 	case IRP_MN_REMOVE_DEVICE:							// 0x02
125 		//
126 		//	Remove the device
127 		//
128 		status = STATUS_SUCCESS;
129 
130 		//	complete the current request
131 		Irp->IoStatus.Status = status;
132 		Irp->IoStatus.Information = 0;
133 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
134 
135 		//
136 		// Set the device status to REMOVED and wait for other drivers
137 		// to release the lock, then delete the device object
138 		//
139 		device_extension->DeviceState = VFD_REMOVED;
140 		IoReleaseRemoveLockAndWait(&device_extension->RemoveLock, Irp);
141 		lockHeld = FALSE;
142 
143 		VfdRemoveDevice(DeviceObject);
144 		break;
145 
146 	case IRP_MN_CANCEL_REMOVE_DEVICE:					// 0x03
147 		//
148 		// Before sending the IRP down make sure we have received
149 		// a IRP_MN_QUERY_REMOVE_DEVICE. We may get Cancel Remove
150 		// without receiving a Query Remove earlier, if the
151 		// driver on top fails a Query Remove and passes down the
152 		// Cancel Remove.
153 		//
154 
155 		if (device_extension->DeviceState == VFD_PENDINGREMOVE) {
156 			device_extension->DeviceState = VFD_WORKING;
157 		}
158 
159 		status = STATUS_SUCCESS;
160 		Irp->IoStatus.Status = status;
161 		Irp->IoStatus.Information = 0;
162 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
163 
164 		break;
165 
166 	case IRP_MN_STOP_DEVICE:							// 0x04
167 		device_extension->DeviceState = VFD_STOPPED;
168 
169 		status = STATUS_SUCCESS;
170 		Irp->IoStatus.Status = status;
171 		Irp->IoStatus.Information = 0;
172 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
173 		break;
174 
175 	case IRP_MN_QUERY_STOP_DEVICE:						// 0x05
176 		device_extension->DeviceState = VFD_PENDINGSTOP;
177 
178 		status = STATUS_SUCCESS;
179 		Irp->IoStatus.Status = status;
180 		Irp->IoStatus.Information = 0;
181 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
182 		break;
183 
184 	case IRP_MN_CANCEL_STOP_DEVICE:						// 0x06
185 		//
186 		// Before sending the IRP down make sure we have received
187 		// a IRP_MN_QUERY_STOP_DEVICE. We may get Cancel Stop
188 		// without receiving a Query Stop earlier, if the
189 		// driver on top fails a Query Stop and passes down the
190 		// Cancel Stop.
191 		//
192 
193 		if (device_extension->DeviceState == VFD_PENDINGSTOP ) {
194 			device_extension->DeviceState = VFD_WORKING;
195 		}
196 
197 		status = STATUS_SUCCESS;
198 		Irp->IoStatus.Status = status;
199 		Irp->IoStatus.Information = 0;
200 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
201 		break;
202 
203 	case IRP_MN_QUERY_DEVICE_RELATIONS:				// 0x07
204 		status = STATUS_SUCCESS;
205 		Irp->IoStatus.Information = 0;
206 
207 		switch (io_stack->Parameters.QueryDeviceRelations.Type) {
208 		case BusRelations:
209 			VFDTRACE(VFDINFO, ("------- BusRelations Query\n"));
210 			break;
211 
212 		case EjectionRelations:
213 			VFDTRACE(VFDINFO, ("------- EjectionRelations Query\n"));
214 			break;
215 
216 		case PowerRelations:
217 			VFDTRACE(VFDINFO, ("------- PowerRelations Query\n"));
218 			break;
219 
220 		case RemovalRelations:
221 			VFDTRACE(VFDINFO, ("------- RemovalRelations Query\n"));
222 			break;
223 
224 		case TargetDeviceRelation:
225 			VFDTRACE(VFDINFO, ("------- TargetDeviceRelation Query\n"));
226 
227 			Irp->IoStatus.Information = (LONG)ExAllocatePoolWithTag(
228 				PagedPool, sizeof(DEVICE_RELATIONS), VFD_POOL_TAG);
229 
230 			if (Irp->IoStatus.Information) {
231 				PDEVICE_RELATIONS rel = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
232 
233 				rel->Count = 1;
234 				rel->Objects[0] = device_extension->device_object;
235 
236 				status = STATUS_SUCCESS;
237 			}
238 			else {
239 				status = STATUS_INSUFFICIENT_RESOURCES;
240 			}
241 			break;
242 
243 		default:
244 			VFDTRACE(VFDINFO, ("------- Unknown Query\n"));
245 			break;
246 		}
247 		Irp->IoStatus.Status = status;
248 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
249 
250 		break;
251 
252 //	case IRP_MN_QUERY_INTERFACE:						// 0x08
253 //	case IRP_MN_QUERY_CAPABILITIES:					// 0x09
254 //	case IRP_MN_QUERY_RESOURCES:						// 0x0A
255 //	case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:			// 0x0B
256 //	case IRP_MN_QUERY_DEVICE_TEXT:						// 0x0C
257 //	case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:			// 0x0D
258 //	case IRP_MN_READ_CONFIG:							// 0x0F
259 //	case IRP_MN_WRITE_CONFIG:							// 0x10
260 //	case IRP_MN_EJECT:									// 0x11
261 //	case IRP_MN_SET_LOCK:								// 0x12
262 //	case IRP_MN_QUERY_ID:								// 0x13
263 //	case IRP_MN_QUERY_PNP_DEVICE_STATE:				// 0x14
264 //	case IRP_MN_QUERY_BUS_INFORMATION:					// 0x15
265 //	case IRP_MN_DEVICE_USAGE_NOTIFICATION:				// 0x16
266 
267 	case IRP_MN_SURPRISE_REMOVAL:						// 0x17
268 		device_extension->DeviceState = VFD_SURPRISEREMOVED;
269 
270 		status = STATUS_SUCCESS;
271 		Irp->IoStatus.Status = status;
272 		Irp->IoStatus.Information = 0;
273 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
274 		break;
275 
276 //	case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:			// 0x18
277 
278 	default:
279 		//
280 		//	unknown request -- simply pass it to the lower device
281 		//
282 		status = STATUS_INVALID_DEVICE_REQUEST;
283 		Irp->IoStatus.Status = status;
284 		Irp->IoStatus.Information = 0;
285 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
286 		break;
287 	}
288 
289 	//
290 	// Device Extenion is gone if the current IRP is IRP_MN_REMOVE_DEVICE
291 	//
292 	if (lockHeld == TRUE) {
293 		IoReleaseRemoveLock(&device_extension->RemoveLock, Irp);
294 	}
295 
296 	VFDTRACE(VFDINFO, ("[VFD] VfdPlugAndPlay - %s\n", NtStatusToStr(status)));
297 
298 	return status;
299 }
300 
301 //
302 //	Power management I/O request dispatch
303 //
304 NTSTATUS
VfdPowerControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)305 VfdPowerControl(
306 	IN PDEVICE_OBJECT		DeviceObject,
307 	IN PIRP				Irp)
308 {
309 	PIO_STACK_LOCATION		io_stack;
310 	PDEVICE_EXTENSION		device_extension;
311 	NTSTATUS				status;
312 
313 	io_stack = IoGetCurrentIrpStackLocation( Irp );
314 	device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
315 
316 	VFDTRACE(VFDINFO, ("[VFD] VfdPowerControl - IN. %ws %s Device State=%s\n",
317 		device_extension->device_name.Buffer,
318 		GetPnpIrpName(io_stack->MinorFunction),
319 		StateTable[device_extension->DeviceState]));
320 
321 	PoStartNextPowerIrp(Irp);
322 
323 	//
324 	// If the device has been removed, the driver should not pass
325 	// the IRP down to the next lower driver.
326 	//
327 
328 	if (device_extension->DeviceState == VFD_REMOVED) {
329 		status = STATUS_DELETE_PENDING;
330 	}
331 	else {
332 		status = STATUS_SUCCESS;
333 	}
334 
335 	Irp->IoStatus.Status = status;
336 	Irp->IoStatus.Information = 0;
337 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
338 
339 	VFDTRACE(VFDINFO, ("[VFD] VfdPowerControl - %s\n", NtStatusToStr(status)));
340 
341 	return status;
342 }
343 
344 //
345 //	WMI I/O request dispatch
346 //
347 NTSTATUS
VfdSystemControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)348 VfdSystemControl(
349 	IN PDEVICE_OBJECT		DeviceObject,
350 	IN PIRP				Irp)
351 {
352 	PIO_STACK_LOCATION		io_stack;
353 	PDEVICE_EXTENSION		device_extension;
354 	NTSTATUS				status;
355 
356 	io_stack = IoGetCurrentIrpStackLocation(Irp);
357 	device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
358 
359 	VFDTRACE(VFDINFO, ("[VFD] VfdSystemControl - IN. %ws %s Device State=%s\n",
360 		device_extension->device_name.Buffer,
361 		GetPnpIrpName(io_stack->MinorFunction),
362 		StateTable[device_extension->DeviceState]));
363 
364 	status = STATUS_SUCCESS;
365 	Irp->IoStatus.Status = status;
366 	Irp->IoStatus.Information = 0;
367 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
368 
369 	VFDTRACE(VFDINFO, ("[VFD] VfdSystemControl - %s\n", NtStatusToStr(status)));
370 
371 	return status;
372 }
373 
374 //
375 //	PnP AddDevice function
376 //
377 NTSTATUS
VfdAddDevice(IN PDRIVER_OBJECT DriverObject,IN OUT PDEVICE_OBJECT PhysicalDevice)378 VfdAddDevice(
379 	IN		PDRIVER_OBJECT		DriverObject,
380 	IN OUT	PDEVICE_OBJECT		PhysicalDevice)
381 {
382 	PDEVICE_OBJECT		device_object;
383 	PDEVICE_EXTENSION	device_extension;
384 	NTSTATUS status;
385 
386 	VFDTRACE(VFDINFO, ("[VFD] VfdAddDevice - IN\n"));
387 
388 	status = VfdCreateDevice(DriverObject, &device_object);
389 
390 	if (NT_SUCCESS(status)) {
391 
392 		device_object->Flags |= DO_POWER_PAGABLE;
393 
394 		device_extension =
395 			(PDEVICE_EXTENSION)device_object->DeviceExtension;
396 
397 		// Device starts in Stopped state
398 		device_extension->DeviceState = VFD_STOPPED;
399 
400 		VFDTRACE(VFDINFO, ("[VFD] Initializing the remove lock\n"));
401 
402 		IoInitializeRemoveLock(
403 			&device_extension->RemoveLock,
404 			REMLOCK_TAG,
405 			REMLOCK_MAXIMUM,
406 			REMLOCK_HIGHWATER);
407 
408 		if (PhysicalDevice) {
409 			device_extension->PhysicalDevice = PhysicalDevice;
410 		}
411 		else {
412 			VfdReportDevice(device_extension);
413 		}
414 		VfdRegisterInterface(device_extension);
415 		VfdMountMgrNotifyVolume(device_extension);
416 	}
417 
418 	return status;
419 }
420 
421 //
422 //	Report a VFD device to the PnP manager
423 //
424 NTSTATUS
VfdReportDevice(PDEVICE_EXTENSION device_extension)425 VfdReportDevice(
426 	PDEVICE_EXTENSION	device_extension)
427 {
428 	NTSTATUS status	= STATUS_SUCCESS;
429 	CM_RESOURCE_LIST				list = {0};
430 	PCM_FULL_RESOURCE_DESCRIPTOR	full = &(list.List[0]);
431 	PCM_PARTIAL_RESOURCE_LIST		part = &(full->PartialResourceList);
432 	PCM_PARTIAL_RESOURCE_DESCRIPTOR	desc = &(part->PartialDescriptors[0]);;
433 
434 	list.Count				= 1;
435 
436 	full->InterfaceType		= Internal;
437 	full->BusNumber		= device_extension->device_number;
438 
439 	part->Version			= 1;
440 	part->Revision			= 1;
441 	part->Count			= 1;
442 
443 	desc->Type				= CmResourceTypeDeviceSpecific;
444 	desc->ShareDisposition	= CmResourceShareShared;
445 	desc->Flags			= 0;
446 
447 	VFDTRACE(VFDINFO,("[VFD] Reporting device %lu to the PnP manager\n",
448 		device_extension->device_number));
449 
450 	status = IoReportDetectedDevice(
451 		device_extension->device_object->DriverObject,	// IN PDRIVER_OBJECT DriverObject,
452 		Internal,								// IN INTERFACE_TYPE LegacyBusType,
453 		(ULONG)-1,								// IN ULONG BusNumber,
454 		(ULONG)-1,								// IN ULONG SlotNumber,
455 		&list,									// IN PCM_RESOURCE_LIST ResourceList,
456 		NULL,									// IN PIO_RESOURCE_REQUIREMENTS_LIST OPTIONAL,
457 		TRUE,									// IN BOOLEAN ResourceAssigned,
458 		&(device_extension->PhysicalDevice)		// IN OUT PDEVICE_OBJECT *DeviceObject
459 	);
460 
461 	if (!NT_SUCCESS(status)) {
462 		VFDTRACE(0,
463 			("[VFD] IoReportDetectedDevice - %s\n",
464 			NtStatusToStr(status)));
465 	}
466 
467 	device_extension->TargetDevice = IoAttachDeviceToDeviceStack(
468 		device_extension->device_object,
469 		device_extension->PhysicalDevice);
470 
471 	return status;
472 }
473 
474 #endif	// VFD_PNP
475