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