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 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 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 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 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 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 // 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 // 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