1 /* 2 vfddev.c 3 4 Virtual Floppy Drive for Windows NT platform 5 Kernel mode driver: device create/delete 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 #ifdef ALLOC_PRAGMA 15 #pragma alloc_text(PAGE, VfdCreateDevice) 16 #pragma alloc_text(PAGE, VfdDeleteDevice) 17 #endif // ALLOC_PRAGMA 18 19 // 20 // Create a VFD device object 21 // 22 NTSTATUS 23 VfdCreateDevice( 24 IN PDRIVER_OBJECT DriverObject, 25 OUT PVOID Parameter) 26 { 27 NTSTATUS status; 28 ULONG physical_num; 29 30 UNICODE_STRING unicode_name; 31 WCHAR name_buffer[40]; 32 33 PVFD_DRIVER_EXTENSION driver_extension = NULL; 34 PDEVICE_OBJECT device_object = NULL; 35 PDEVICE_EXTENSION device_extension = NULL; 36 HANDLE thread_handle = NULL; 37 38 VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - IN\n")); 39 40 #ifdef VFD_PNP 41 42 // Get the driver device_extension for the driver object 43 driver_extension = IoGetDriverObjectExtension( 44 DriverObject, VFD_DRIVER_EXTENSION_ID); 45 46 #else // VFD_PNP 47 48 // The driver device_extension is passed as the Parameter 49 driver_extension = (PVFD_DRIVER_EXTENSION)Parameter; 50 51 #endif // VFD_PNP 52 53 if (driver_extension == NULL) { 54 VFDTRACE(VFDERR, ("[VFD] Failed to get the driver extension\n")); 55 return STATUS_DRIVER_INTERNAL_ERROR; 56 } 57 58 // 59 // Create a device object 60 // \Device\Floppy<n> 61 // 62 physical_num = 0; 63 64 do { 65 name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL; 66 67 _snwprintf(name_buffer, sizeof(name_buffer) - 1, 68 L"\\Device\\Floppy%lu", physical_num); 69 70 RtlInitUnicodeString(&unicode_name, name_buffer); 71 72 status = IoCreateDevice( 73 DriverObject, 74 sizeof(DEVICE_EXTENSION), 75 &unicode_name, 76 FILE_DEVICE_DISK, 77 FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE | FILE_DEVICE_SECURE_OPEN, 78 FALSE, 79 &device_object); 80 81 if (status != STATUS_OBJECT_NAME_EXISTS && 82 status != STATUS_OBJECT_NAME_COLLISION) { 83 break; 84 } 85 } 86 while (++physical_num < 100); 87 88 if (!NT_SUCCESS(status)) { 89 VFDTRACE(VFDERR, 90 ("[VFD] IoCreateDevice() %s\n", 91 GetStatusName(status))); 92 return status; 93 } 94 95 IoGetConfigurationInformation()->FloppyCount++; 96 97 VFDTRACE(VFDINFO | VFDDEV, 98 ("[VFD] Created a device object %ws\n", name_buffer)); 99 100 // 101 // Initialize the device object / device extension 102 // 103 104 device_object->Flags |= DO_DIRECT_IO; 105 106 device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension; 107 108 RtlZeroMemory(device_extension, sizeof(DEVICE_EXTENSION)); 109 110 // Store the back pointer to the device object 111 112 device_extension->DeviceObject = device_object; 113 114 // Store the logical device number 115 116 device_extension->DeviceNumber = driver_extension->NumberOfDevices; 117 118 // Store the device name 119 120 if (!VfdCopyUnicode(&(device_extension->DeviceName), &unicode_name)) { 121 VFDTRACE(VFDERR, 122 ("[VFD] Failed to allocate device name buffer\n")); 123 status = STATUS_INSUFFICIENT_RESOURCES; 124 goto cleanup; 125 } 126 127 // set the default disk geometry (3.5" 1.44M) 128 129 device_extension->Geometry = &geom_tbl[0]; 130 131 // Create the interface link (\??\VirtualFD<n>) 132 133 name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL; 134 135 _snwprintf(name_buffer, sizeof(name_buffer) - 1, 136 L"\\??\\" VFD_DEVICE_BASENAME L"%lu", 137 device_extension->DeviceNumber); 138 139 RtlInitUnicodeString(&unicode_name, name_buffer); 140 141 status = IoCreateSymbolicLink( 142 &unicode_name, &device_extension->DeviceName); 143 144 if (!NT_SUCCESS(status)) { 145 VFDTRACE(VFDERR, 146 ("[VFD] IoCreateSymbolicLink(%ws) %s\n", 147 name_buffer, GetStatusName(status))); 148 goto cleanup; 149 } 150 151 VFDTRACE(VFDINFO|VFDDEV, 152 ("[VFD] Created a symbolic link %ws\n", name_buffer)); 153 154 // Prepare the IRP queue list for the device thread 155 156 InitializeListHead(&device_extension->ListHead); 157 158 KeInitializeSpinLock(&device_extension->ListLock); 159 160 KeInitializeEvent( 161 &device_extension->RequestEvent, 162 SynchronizationEvent, 163 FALSE); 164 165 // Create the device thread 166 167 device_extension->TerminateThread = FALSE; 168 169 status = PsCreateSystemThread( 170 &thread_handle, 171 (ACCESS_MASK) 0L, 172 NULL, 173 NULL, 174 NULL, 175 VfdDeviceThread, 176 device_object); 177 178 if (!NT_SUCCESS(status)) { 179 VFDTRACE(VFDERR, 180 ("[VFD] PsCreateSystemThread() %s\n", 181 GetStatusName(status))); 182 goto cleanup; 183 } 184 185 // get a reference pointer to the thread 186 187 status = ObReferenceObjectByHandle( 188 thread_handle, 189 THREAD_ALL_ACCESS, 190 NULL, 191 KernelMode, 192 &device_extension->ThreadPointer, 193 NULL); 194 195 ZwClose(thread_handle); 196 197 if (!NT_SUCCESS(status)) { 198 VFDTRACE(VFDERR, 199 ("[VFD] ObReferenceObjectByHandle() %s\n", 200 GetStatusName(status))); 201 goto cleanup; 202 } 203 204 // 205 // Load the persistent drive letter from the registry 206 // 207 if (driver_extension->RegistryPath.Buffer) { 208 VfdLoadLink(device_extension, 209 driver_extension->RegistryPath.Buffer); 210 // error is not fatal here 211 } 212 213 // increment the number of devices in the driver extension 214 215 driver_extension->NumberOfDevices++; 216 217 if (DriverObject->DriverUnload) { 218 // not called from the DriverEntry routine 219 device_object->Flags &= ~DO_DEVICE_INITIALIZING; 220 } 221 222 #ifdef VFD_PNP 223 if (Parameter) { 224 // return the device object pointer 225 *(PDEVICE_OBJECT *)Parameter = device_object; 226 } 227 #else // VFD_PNP 228 device_extension->DriverExtension = driver_extension; 229 #endif // VFD_PNP 230 231 VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - OK\n")); 232 233 return STATUS_SUCCESS; 234 235 cleanup: 236 // 237 // Something went wrong at one point 238 // Delete all resources that might be created in this function 239 // 240 if (thread_handle) { 241 242 // terminate the device thread 243 device_extension->TerminateThread = TRUE; 244 245 KeSetEvent( 246 &device_extension->RequestEvent, 247 (KPRIORITY) 0, 248 FALSE); 249 250 if (device_extension->ThreadPointer) { 251 ObDereferenceObject(device_extension->ThreadPointer); 252 } 253 } 254 255 VFDTRACE(VFDINFO|VFDDEV, 256 ("[VFD] Deleting symbolic link %ws\n", name_buffer)); 257 258 IoDeleteSymbolicLink(&unicode_name); 259 260 if (device_extension->DeviceName.Buffer) { 261 VFDTRACE(VFDINFO|VFDDEV, ("[VFD] Deleting device %ws\n", 262 device_extension->DeviceName.Buffer)); 263 264 ExFreePool(device_extension->DeviceName.Buffer); 265 } 266 267 IoDeleteDevice(device_object); 268 IoGetConfigurationInformation()->FloppyCount--; 269 270 VFDTRACE(VFDINFO|VFDDEV, 271 ("[VFD] VfdCreateDevice - %s\n", 272 GetStatusName(status))); 273 274 return status; 275 } 276 277 // 278 // delete a VFD device object 279 // 280 VOID 281 VfdDeleteDevice( 282 IN PDEVICE_OBJECT DeviceObject) 283 { 284 PDEVICE_EXTENSION device_extension; 285 PVFD_DRIVER_EXTENSION driver_extension; 286 UNICODE_STRING unicode_name; 287 WCHAR name_buffer[40]; 288 289 VFDTRACE(VFDINFO|VFDDEV, ("[VFD] VfdDeleteDevice - IN\n")); 290 291 device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; 292 293 // 294 // decrement the number of device in the driver extension 295 // 296 #ifdef VFD_PNP 297 driver_extension = IoGetDriverObjectExtension( 298 DeviceObject->DriverObject, VFD_DRIVER_EXTENSION_ID); 299 #else // VFD_PNP 300 driver_extension = device_extension->DriverExtension; 301 #endif // VFD_PNP 302 303 if (driver_extension) { 304 driver_extension->NumberOfDevices--; 305 } 306 307 // 308 // cleanup the device object 309 // 310 311 // Terminate the device thread 312 313 device_extension->TerminateThread = TRUE; 314 315 KeSetEvent( 316 &device_extension->RequestEvent, 317 (KPRIORITY) 0, 318 FALSE); 319 320 KeWaitForSingleObject( 321 device_extension->ThreadPointer, 322 Executive, 323 KernelMode, 324 FALSE, 325 NULL); 326 327 ObDereferenceObject( 328 device_extension->ThreadPointer); 329 330 // Delete security context object 331 332 if (device_extension->SecurityContext) { 333 SeDeleteClientSecurity(device_extension->SecurityContext); 334 ExFreePool(device_extension->SecurityContext); 335 } 336 337 // Close the image file or free the image buffer 338 339 if (device_extension->FileHandle) { 340 ZwClose(device_extension->FileHandle); 341 } 342 343 if (device_extension->FileBuffer) { 344 ExFreePool(device_extension->FileBuffer); 345 } 346 347 // Release the image path buffer 348 349 if (device_extension->FileName.Buffer) { 350 ExFreePool(device_extension->FileName.Buffer); 351 } 352 353 // Remove the interface symbolic link 354 355 name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL; 356 357 _snwprintf(name_buffer, sizeof(name_buffer) - 1, 358 L"\\??\\" VFD_DEVICE_BASENAME L"%lu", 359 device_extension->DeviceNumber); 360 361 RtlInitUnicodeString(&unicode_name, name_buffer); 362 363 VFDTRACE(VFDINFO|VFDDEV, 364 ("[VFD] Deleting link %ws\n", name_buffer)); 365 366 IoDeleteSymbolicLink(&unicode_name); 367 368 // Remove the persistent drive letter 369 370 if (device_extension->DriveLetter) { 371 #ifdef VFD_MOUNT_MANAGER 372 if (OsMajorVersion >= 5) { 373 // Request the mount manager to remove the drive letter. 374 // This will cause the mount manager to update its database 375 // and it won't arbitrarily assign the drive letter the next 376 // time the driver starts. 377 VfdMountMgrMountPoint(device_extension, 0); 378 } 379 else 380 #endif // VFD_MOUNT_MANAGER 381 { 382 // Windows NT style drive letter handling 383 // Simply remove the symbolic link 384 VfdSetLink(device_extension, 0); 385 } 386 } 387 388 // Release the device name buffer 389 390 if (device_extension->DeviceName.Buffer) { 391 VFDTRACE(VFDINFO|VFDDEV, 392 ("[VFD] Deleting device %ws\n", 393 device_extension->DeviceName.Buffer)); 394 395 ExFreePool(device_extension->DeviceName.Buffer); 396 } 397 398 // Delete the device object 399 400 IoDeleteDevice(DeviceObject); 401 IoGetConfigurationInformation()->FloppyCount--; 402 403 VFDTRACE(VFDINFO|VFDDEV, 404 ("[VFD] VfdDeleteDevice - OUT\n")); 405 406 return; 407 } 408