xref: /reactos/modules/rosapps/drivers/vfd/vfddev.c (revision ba3f0743)
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