6aee0bcd8a29518465ea9b1f4e8c9ab62667bbc4
[reactos.git] / modules / rosapps / drivers / vfd / vfddev.c
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 }