xref: /reactos/modules/rosapps/drivers/vfd/vfddrv.c (revision 25c7e1a8)
1 /*
2 	vfddrv.c
3 
4 	Virtual Floppy Drive for Windows NT platform
5 	Kernel mode driver: miscellaneous driver functions
6 
7 	Copyright (C) 2003-2005 Ken Kato
8 */
9 
10 #include "imports.h"
11 #include "vfddrv.h"
12 #include "vfddbg.h"
13 
14 //
15 //	driver reinitialize routine
16 //	-- create a drive letter for each device
17 //
18 #ifdef __cplusplus
19 extern "C"
20 #endif	// __cplusplus
21 static VOID
22 NTAPI
23 VfdReinitialize(
24 	IN PDRIVER_OBJECT			DriverObject,
25 	IN PVOID					Context,
26 	IN ULONG					Count);
27 
28 //
29 //	specify code segment
30 //
31 #ifdef ALLOC_PRAGMA
32 #pragma alloc_text(INIT, DriverEntry)
33 #pragma alloc_text(PAGE, VfdReinitialize)
34 #pragma alloc_text(PAGE, VfdUnloadDriver)
35 #pragma alloc_text(PAGE, VfdCreateClose)
36 #pragma alloc_text(PAGE, VfdCopyUnicode)
37 #pragma alloc_text(PAGE, VfdFreeUnicode)
38 #endif	// ALLOC_PRAGMA
39 
40 //
41 //	operating system version
42 //
43 #ifndef __REACTOS__
44 extern ULONG OsMajorVersion = 0;
45 extern ULONG OsMinorVersion = 0;
46 extern ULONG OsBuildNumber	= 0;
47 #else
48 ULONG OsMajorVersion = 0;
49 ULONG OsMinorVersion = 0;
50 ULONG OsBuildNumber	= 0;
51 #endif
52 
53 //
54 //	Trace level flag
55 //
56 #if DBG
57 #ifndef __REACTOS__
58 extern ULONG TraceFlags	= (ULONG)-1;
59 #else
60 ULONG TraceFlags	= (ULONG)-1;
61 #endif
62 #endif	// DBG
63 
64 //
65 //	Driver Entry routine
66 //
67 NTSTATUS
68 NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)69 DriverEntry (
70 	IN PDRIVER_OBJECT			DriverObject,
71 	IN PUNICODE_STRING			RegistryPath)
72 {
73 	NTSTATUS					status;
74 	PVFD_DRIVER_EXTENSION		driver_extension;
75 	ULONG						number_of_devices = VFD_DEFAULT_DEVICES;
76 
77 	ASSERT(DriverObject);
78 
79 	//	Get operating system version
80 
81 	PsGetVersion(&OsMajorVersion, &OsMinorVersion, &OsBuildNumber, NULL);
82 
83 #ifdef VFD_PNP
84 #define VFD_PNP_TAG	"(Plug & Play version)"
85 #else
86 #define VFD_PNP_TAG
87 #endif
88 
89 	VFDTRACE(0, ("[VFD] %s %s" VFD_PNP_TAG "\n",
90 		VFD_PRODUCT_NAME, VFD_DRIVER_VERSION_STR));
91 
92 	VFDTRACE(0,
93 		("[VFD] Running on Windows NT %lu.%lu build %lu\n",
94 		OsMajorVersion, OsMinorVersion, OsBuildNumber));
95 
96 	VFDTRACE(0,
97 		("[VFD] Build Target Environment: %d\n", VER_PRODUCTBUILD));
98 
99 #ifdef VFD_PNP
100 
101 	// Create device_extension for the driver object to store driver specific
102 	// information. Device specific information are stored in device extension
103 	// for each device object.
104 
105 	status = IoAllocateDriverObjectExtension(
106 		DriverObject,
107 		VFD_DRIVER_EXTENSION_ID,
108 		sizeof(VFD_DRIVER_EXTENSION),
109 		&driver_extension);
110 
111 	if(!NT_SUCCESS(status)) {
112 		VFDTRACE(0, ("[VFD] IoAllocateDriverObjectExtension - %s\n",
113 			GetStatusName(status)));
114 		return status;
115 	}
116 
117 #else	// VFD_PNP
118 
119 	//	Windows NT doesn't have the IoAllocateDriverObjectExtension
120 	//	function and I think there's little point in making a non-PnP
121 	//	driver incompatible with Windows NT.
122 
123 	driver_extension = (PVFD_DRIVER_EXTENSION)ExAllocatePoolWithTag(
124 		PagedPool, sizeof(VFD_DRIVER_EXTENSION), VFD_POOL_TAG);
125 
126 	if (!driver_extension) {
127 		VFDTRACE(0, ("[VFD] failed to allocate the driver extension.\n"));
128 		return STATUS_INSUFFICIENT_RESOURCES;
129 	}
130 
131 #endif	// VFD_PNP
132 
133 	RtlZeroMemory(driver_extension, sizeof(VFD_DRIVER_EXTENSION));
134 
135 	//
136 	// Copy the registry path into the driver extension so we can use it later
137 	//
138 	if (VfdCopyUnicode(&(driver_extension->RegistryPath), RegistryPath)) {
139 
140 		//
141 		//	Read config values from the registry
142 		//
143 		RTL_QUERY_REGISTRY_TABLE params[3];
144 		ULONG default_devs	= VFD_DEFAULT_DEVICES;
145 #if DBG
146 		ULONG default_trace = (ULONG)-1;
147 #endif
148 
149 		RtlZeroMemory(params, sizeof(params));
150 
151 		VFDTRACE(0, ("[VFD] Registry Path: %ws\n",
152 			driver_extension->RegistryPath.Buffer));
153 
154 		params[0].Flags			= RTL_QUERY_REGISTRY_DIRECT;
155 		params[0].Name			= VFD_REG_DEVICE_NUMBER;
156 		params[0].EntryContext	= &number_of_devices;
157 		params[0].DefaultType	= REG_DWORD;
158 		params[0].DefaultData	= &default_devs;
159 		params[0].DefaultLength	= sizeof(ULONG);
160 
161 #if DBG
162 		params[1].Flags			= RTL_QUERY_REGISTRY_DIRECT;
163 		params[1].Name			= VFD_REG_TRACE_FLAGS;
164 		params[1].EntryContext	= &TraceFlags;
165 		params[1].DefaultType	= REG_DWORD;
166 		params[1].DefaultData	= &default_trace;
167 		params[1].DefaultLength	= sizeof(ULONG);
168 #endif	// DBG
169 
170 		status = RtlQueryRegistryValues(
171 			RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
172 			driver_extension->RegistryPath.Buffer,
173 			params, NULL, NULL);
174 
175 		if (!NT_SUCCESS(status) ||
176 			number_of_devices == 0 ||
177 			number_of_devices > VFD_MAXIMUM_DEVICES) {
178 			number_of_devices = VFD_DEFAULT_DEVICES;
179 		}
180 
181 		VFDTRACE(0,("[VFD] NumberOfDevices = %lu\n", number_of_devices));
182 		VFDTRACE(0,("[VFD] TraceFlags = 0x%08x\n", TraceFlags));
183 	}
184 	else {
185 		VFDTRACE(0, ("[VFD] failed to allocate the registry path buffer.\n"));
186 		// this error is not fatal
187 	}
188 
189 	//
190 	//	Create VFD device objects
191 	//
192 	do {
193 #ifdef VFD_PNP
194 		status = VfdCreateDevice(DriverObject, NULL);
195 #else	// VFD_PNP
196 		status = VfdCreateDevice(DriverObject, driver_extension);
197 #endif	// VFD_PNP
198 
199 		if (!NT_SUCCESS(status)) {
200 			break;
201 		}
202 	}
203 	while (driver_extension->NumberOfDevices < number_of_devices);
204 
205 	if (!driver_extension->NumberOfDevices) {
206 
207 		//	Failed to create even one device
208 
209 		VfdFreeUnicode(&(driver_extension->RegistryPath));
210 
211 		return status;
212 	}
213 
214 	//	Setup dispatch table
215 
216 	DriverObject->MajorFunction[IRP_MJ_CREATE]			= VfdCreateClose;
217 	DriverObject->MajorFunction[IRP_MJ_CLOSE]			= VfdCreateClose;
218 	DriverObject->MajorFunction[IRP_MJ_READ]			= VfdReadWrite;
219 	DriverObject->MajorFunction[IRP_MJ_WRITE]			= VfdReadWrite;
220 	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]	= VfdDeviceControl;
221 
222 #ifdef VFD_PNP
223 	DriverObject->MajorFunction[IRP_MJ_PNP]				= VfdPlugAndPlay;
224 	DriverObject->MajorFunction[IRP_MJ_POWER]			= VfdPowerControl;
225 	DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]	= VfdSystemControl;
226 	DriverObject->DriverExtension->AddDevice			= VfdAddDevice;
227 #endif	// VFDPNP
228 
229 	DriverObject->DriverUnload = VfdUnloadDriver;
230 
231 	//	Register the driver reinitialize routine to be called
232 	//	*after* the DriverEntry routine returns
233 
234 	IoRegisterDriverReinitialization(
235 		DriverObject, VfdReinitialize, NULL);
236 
237 	VFDTRACE(VFDINFO,
238 		("[VFD] driver initialized with %lu devices.\n",
239 		driver_extension->NumberOfDevices));
240 
241 	return STATUS_SUCCESS;
242 }
243 
244 //
245 //	Driver unload routine
246 //	Cleans up the device objects and other resources
247 //
248 VOID
249 NTAPI
VfdUnloadDriver(IN PDRIVER_OBJECT DriverObject)250 VfdUnloadDriver (
251 	IN PDRIVER_OBJECT			DriverObject)
252 {
253 	PDEVICE_OBJECT				device_object;
254 	PVFD_DRIVER_EXTENSION		driver_extension;
255 
256 	VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - IN\n"));
257 
258 	device_object = DriverObject->DeviceObject;
259 
260 #ifdef VFD_PNP
261 	driver_extension = IoGetDriverObjectExtension(
262 		DriverObject, VFD_DRIVER_EXTENSION_ID);
263 #else
264 	if (device_object && device_object->DeviceExtension) {
265 		driver_extension =
266 			((PDEVICE_EXTENSION)(device_object->DeviceExtension))->DriverExtension;
267 	}
268 	else {
269 		driver_extension = NULL;
270 	}
271 #endif	// VFD_PNP
272 
273 	//
274 	//	Delete all remaining device objects
275 	//
276 	while (device_object) {
277 
278 		PDEVICE_OBJECT next_device = device_object->NextDevice;
279 
280 		VfdDeleteDevice(device_object);
281 
282 		device_object = next_device;
283 	}
284 
285 	//
286 	//	Release the driver extension and the registry path buffer
287 	//
288 	if (driver_extension) {
289 
290 		if (driver_extension->RegistryPath.Buffer) {
291 			VFDTRACE(0, ("[VFD] Releasing the registry path buffer\n"));
292 			ExFreePool(driver_extension->RegistryPath.Buffer);
293 		}
294 
295 #ifndef VFD_PNP
296 		//	The system takes care of freeing the driver extension
297 		//	allocated with IoAllocateDriverObjectExtension in a PnP driver.
298 		VFDTRACE(0, ("[VFD] Releasing the driver extension\n"));
299 		ExFreePool(driver_extension);
300 #endif	// VFD_PNP
301 	}
302 
303 	VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - OUT\n"));
304 }
305 
306 //
307 //	IRP_MJ_CREATE and IRP_MJ_CLOSE handler
308 //	Really nothing to do here...
309 //
310 NTSTATUS
311 NTAPI
VfdCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)312 VfdCreateClose (
313 	IN PDEVICE_OBJECT			DeviceObject,
314 	IN PIRP						Irp)
315 {
316 #if DBG
317 	if (DeviceObject && DeviceObject->DeviceExtension &&
318 		((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) {
319 
320 		VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
321 			GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
322 			((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer));
323 	}
324 	else {
325 		VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n",
326 			GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
327 			DeviceObject));
328 	}
329 #endif	// DBG
330 
331 	Irp->IoStatus.Status = STATUS_SUCCESS;
332 	Irp->IoStatus.Information = FILE_OPENED;
333 
334 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
335 
336 	return STATUS_SUCCESS;
337 }
338 
339 //
340 //	Called after the DriverEntry routine has returned
341 //	(Re)Create a persistent drive letter for each device
342 //
343 VOID
344 NTAPI
VfdReinitialize(IN PDRIVER_OBJECT DriverObject,IN PVOID Context,IN ULONG Count)345 VfdReinitialize(
346 	IN PDRIVER_OBJECT			DriverObject,
347 	IN PVOID					Context,
348 	IN ULONG					Count)
349 {
350 	PDEVICE_OBJECT				device_object;
351 	PDEVICE_EXTENSION			device_extension;
352 
353 	UNREFERENCED_PARAMETER(Context);
354 	UNREFERENCED_PARAMETER(Count);
355 
356 	VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - IN\n"));
357 
358 	device_object = DriverObject->DeviceObject;
359 
360 	while (device_object) {
361 		device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
362 
363 #ifdef VFD_MOUNT_MANAGER
364 		if (OsMajorVersion >= 5) {
365 			//	Windows 2000 / XP
366 			//	Notify the mount manager of a VFD volume arrival
367 			VfdMountMgrNotifyVolume(device_extension);
368 
369 			if (device_extension->DriveLetter) {
370 				//	Create a drive letter via the mount manager.
371 				//	The mount manager may have created a drive letter
372 				//	in response to the volume arrival notification above.
373 				//	In that case, the following call just fails.
374 				VfdMountMgrMountPoint(
375 					device_extension, device_extension->DriveLetter);
376 				//	ignoring the error for it is not fatal here
377 			}
378 		}
379 		else
380 #endif	// VFD_MOUNT_MANAGER
381 		{
382 			//	Windows NT style drive letter assignment
383 			//	Simply create a symbolic link here
384 			if (device_extension->DriveLetter) {
385 				VfdSetLink(
386 					device_extension, device_extension->DriveLetter);
387 				//	ignoring the error for it is not fatal here
388 			}
389 		}
390 
391 		device_object = device_object->NextDevice;
392 	}
393 
394 	VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - OUT\n"));
395 }
396 
397 //
398 //	Device dedicated thread routine
399 //	Dispatch read, write and device I/O request
400 //	redirected from the driver dispatch routines
401 //
402 VOID
403 NTAPI
VfdDeviceThread(IN PVOID ThreadContext)404 VfdDeviceThread (
405 	IN PVOID					ThreadContext)
406 {
407 	PDEVICE_OBJECT				device_object;
408 	PDEVICE_EXTENSION			device_extension;
409 	PLIST_ENTRY					request;
410 	PIRP						irp;
411 	PIO_STACK_LOCATION			io_stack;
412 
413 	ASSERT(ThreadContext != NULL);
414 
415 	device_object = (PDEVICE_OBJECT)ThreadContext;
416 
417 	device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
418 
419 	KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
420 
421 	for (;;) {
422 		//	wait for the request event to be signalled
423 		KeWaitForSingleObject(
424 			&device_extension->RequestEvent,
425 			Executive,
426 			KernelMode,
427 			FALSE,
428 			NULL);
429 
430 		//	terminate request ?
431 		if (device_extension->TerminateThread) {
432 			VFDTRACE(0, ("[VFD] Exitting the I/O thread\n"));
433 			PsTerminateSystemThread(STATUS_SUCCESS);
434 		}
435 
436 		//	perform requested tasks
437 
438 		while ((request = ExInterlockedRemoveHeadList(
439 			&device_extension->ListHead,
440 			&device_extension->ListLock)) != NULL)
441 		{
442 			irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
443 
444 			io_stack = IoGetCurrentIrpStackLocation(irp);
445 
446 			irp->IoStatus.Information = 0;
447 
448 			switch (io_stack->MajorFunction) {
449 			case IRP_MJ_READ:
450 				VfdReadData(device_extension, irp,
451 					io_stack->Parameters.Read.Length,
452 					&io_stack->Parameters.Read.ByteOffset);
453 				break;
454 
455 			case IRP_MJ_WRITE:
456 				VfdWriteData(device_extension, irp,
457 					io_stack->Parameters.Write.Length,
458 					&io_stack->Parameters.Write.ByteOffset);
459 				break;
460 
461 			case IRP_MJ_DEVICE_CONTROL:
462 				VfdIoCtlThread(device_extension, irp,
463 					io_stack->Parameters.DeviceIoControl.IoControlCode);
464 				break;
465 
466 			default:
467 				//	This shouldn't happen...
468 				VFDTRACE(0,
469 					("[VFD] %s passed to the I/O thread\n",
470 					GetMajorFuncName(io_stack->MajorFunction)));
471 
472 				irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
473 			}
474 
475 			IoCompleteRequest(irp,
476 				(CCHAR)(NT_SUCCESS(irp->IoStatus.Status) ?
477 					IO_DISK_INCREMENT : IO_NO_INCREMENT));
478 
479 #ifdef VFD_PNP
480 			IoReleaseRemoveLock(&device_extension->RemoveLock, irp);
481 #endif	// VFD_PNP
482 		} // while
483 	} // for (;;)
484 }
485 
486 //
487 //	Copy a UNICODE_STRING adding a trailing NULL characer
488 //
VfdCopyUnicode(PUNICODE_STRING dst,PUNICODE_STRING src)489 PWSTR VfdCopyUnicode(
490 	PUNICODE_STRING				dst,
491 	PUNICODE_STRING				src)
492 {
493 	RtlZeroMemory(dst, sizeof(UNICODE_STRING));
494 
495 	dst->MaximumLength =
496 		(USHORT)(src->MaximumLength + sizeof(UNICODE_NULL));
497 
498 	dst->Buffer = (PWSTR)ExAllocatePoolWithTag(
499 		PagedPool, dst->MaximumLength, VFD_POOL_TAG);
500 
501 	if(dst->Buffer) {
502 		dst->Length = src->Length;
503 		RtlZeroMemory(dst->Buffer, dst->MaximumLength);
504 
505 		if (src->Length) {
506 			RtlCopyMemory(dst->Buffer, src->Buffer, src->Length);
507 		}
508 	}
509 
510 	return dst->Buffer;
511 }
512 
513 //
514 //	Free a UNICODE_STRING buffer
515 //
VfdFreeUnicode(PUNICODE_STRING str)516 VOID VfdFreeUnicode(
517 	PUNICODE_STRING				str)
518 {
519 	if (str->Buffer) {
520 		ExFreePool(str->Buffer);
521 	}
522 	RtlZeroMemory(str, sizeof(UNICODE_STRING));
523 }
524