OpenCBM
wdm/LoadUnload.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 2004-2007 Spiro Trikaliotis
8  *
9  */
10 
19 #include <wdm.h>
20 #include "cbm_driver.h"
21 #include "cbmioctl.h"
22 
52 NTSTATUS
53 AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PdoUNUSED, IN PCWSTR ParallelPortName)
54 {
55  PDEVICE_OBJECT fdo;
56  UNICODE_STRING deviceNameNumber;
57  UNICODE_STRING deviceNamePrefix;
58  UNICODE_STRING deviceName;
59  NTSTATUS ntStatus;
60  WCHAR deviceNameNumberBuffer[50];
61 
63  static SHORT no = 0;
64 
65  FUNC_ENTER();
66 
67  UNREFERENCED_PARAMETER(PdoUNUSED);
68 
69  // Until now, no error has occurred
70 
71  ntStatus = STATUS_SUCCESS;
72 
73  // Create the name for the fdo
74  // thus, this is a named driver
75 
76  DBG_IRQL( <= DISPATCH_LEVEL);
77  RtlInitUnicodeString(&deviceNamePrefix, CBMDEVICENAME);
78 
79  // Convert variable no into a UNICODE_STRING
80 
81  deviceNameNumber.Length = 0;
82  deviceNameNumber.MaximumLength = sizeof(deviceNameNumberBuffer);
83  deviceNameNumber.Buffer = deviceNameNumberBuffer;
84  DBG_IRQL( == PASSIVE_LEVEL);
85  RtlIntegerToUnicodeString(no, 10, &deviceNameNumber);
86 
87  // Increment the number for the next device
88 
89  ++no;
90 
91  // Allocate enough space for the concatenation of deviceNamePrefix
92  // and deviceNameNumber
93 
94  deviceName.MaximumLength = deviceNamePrefix.Length + deviceNameNumber.Length;
95  deviceName.Buffer = (PWCHAR) ExAllocatePoolWithTag(NonPagedPool,
96  deviceName.MaximumLength, MTAG_DEVNAME);
97 
98  if (!deviceName.Buffer)
99  {
100  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
101  DBG_ERROR((DBG_PREFIX "Could not allocate memory for deviceName"))
102  LogErrorString(NULL, CBM_START_FAILED, L"allocating memory for device name", NULL);
103  }
104 
105  if (NT_SUCCESS(ntStatus))
106  {
107  // Concatenate both strings
108 
109  DBG_IRQL( < DISPATCH_LEVEL);
110  RtlCopyUnicodeString(&deviceName, &deviceNamePrefix);
111  DBG_IRQL( < DISPATCH_LEVEL);
112  RtlAppendUnicodeStringToString(&deviceName, &deviceNameNumber);
113 
114  // create the FDO with the name just build
115 
116  DBG_IRQL( == PASSIVE_LEVEL);
117  ntStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &deviceName,
118  FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &fdo);
119 
120  if (!NT_SUCCESS(ntStatus))
121  {
122  DBG_ERROR((DBG_PREFIX "IoCreateDevice failed with 0x%08X - %s",
123  ntStatus, DebugNtStatus(ntStatus)));
124  LogErrorString(NULL, CBM_START_FAILED, L"creation of the device object", NULL);
125  }
126  }
127 
128  if (NT_SUCCESS(ntStatus))
129  {
130  // Initialization common to WDM and NT4 driver
131 
132  ntStatus = AddDeviceCommonInit(fdo, &deviceName, ParallelPortName);
133 
134 
135  if (!NT_SUCCESS(ntStatus))
136  {
137  PDEVICE_EXTENSION pdx;
138 
139  // An error has occurred, thus, delete the device
140 
141  // get the pdx of the driver
142 
143  pdx = fdo->DeviceExtension;
144 
145  // If necessary, delete the buffer for the device name
146 
147  if (pdx->DeviceName.Buffer)
148  {
149  DBG_IRQL( < DISPATCH_LEVEL);
150  ExFreePool(pdx->DeviceName.Buffer);
151  }
152 
153  DBG_IRQL( == PASSIVE_LEVEL);
154  IoDeleteDevice(fdo);
155  }
156 
158 /*
159  // Now, attach our FDO to the PDO
160  pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, Pdo);
161  if (!pdx->LowerDeviceObject)
162  {
163  DBG_ERROR((DBG_PREFIX "IoAttachDeviceToDeviceStack failed"));
164  ntStatus = STATUS_DEVICE_REMOVED;
165  }
166  else
167  {
168  // clear initializing flag: we are now ready to work
169  fdo->Flags &= ~DO_DEVICE_INITIALIZING;
170  }
171 */
172 
173  //
174  // Initialize PDX related parts from registry
175  //
176 
177  {
178  PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
179 
180  cbm_init_registry(NULL, pdx);
181  }
182  }
183 
184  FUNC_LEAVE_NTSTATUS(ntStatus);
185 }
186 
187 static KMUTEX MutexDriverLoadUnload;
188 
201 VOID
202 DriverUnload(IN PDRIVER_OBJECT DriverObject)
203 {
204  PDEVICE_OBJECT currentDevice;
205 
206  FUNC_ENTER();
207 
208  // Obtain the mutex that prevents premature unloading
209 
210  DBG_IRQL( < DISPATCH_LEVEL);
211  KeWaitForMutexObject(&MutexDriverLoadUnload, Executive, KernelMode,
212  FALSE, NULL);
213 
214  // Make sure every device object is deleted
215 
216  while (currentDevice = DriverObject->DeviceObject)
217  {
218  PDEVICE_EXTENSION pdx = currentDevice->DeviceExtension;
219 
220  DBG_ASSERT(pdx);
221 
222  // Unlock the parallel port, if necessary
223 
224  if (pdx->ParallelPortIsLocked)
225  {
226  cbm_unlock_parport(pdx);
227  }
228 
229  // Stop the thread of that device, if necessary
230 
231  cbm_stop_thread(pdx);
232 
233  // Uninitialize the parallel port, if necessary
234 
235  ParPortDeinit(pdx);
236 
237  // If a buffer for the device name has been allocated,
238  // release that
239 
240  if (pdx->DeviceName.Buffer)
241  {
242  DBG_IRQL( < DISPATCH_LEVEL);
243  ExFreePool(pdx->DeviceName.Buffer);
244  }
245 
246  // Delete the device
247  // This has to be done *after* the above, as the pdx
248  // is not allowed to be accessed anymore here.
249 
250  DBG_IRQL( == PASSIVE_LEVEL);
251  IoDeleteDevice(currentDevice);
252  }
253 
254  // some more uninitialization, common to WDM and NT4 driver
255 
257 
258 #if DBG
259 
261 
262 #endif
263 
264  // From now on, it is legal to be unloaded
265 
266  DBG_IRQL( <= DISPATCH_LEVEL);
267  KeReleaseMutex(&MutexDriverLoadUnload, FALSE);
268 
269  FUNC_LEAVE();
270 }
271 
294 NTSTATUS
295 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
296 {
297  PENUMERATE enumerate;
298  NTSTATUS ntStatus;
299 
300  FUNC_ENTER();
301 
302  // Initialize the debugging system
303 
304  DBG_INIT();
305 
306  // Initialize the mutex which should prevent premature unloading
307 
308  KeInitializeMutex(&MutexDriverLoadUnload, 0);
309 
310  // Now, obtain that mutex as first operation
311 
312  DBG_IRQL( < DISPATCH_LEVEL);
313  KeWaitForMutexObject(&MutexDriverLoadUnload, Executive, KernelMode,
314  FALSE, NULL);
315 
316 #if DBG
317 
319 
320 #endif
321 
322  // Output a status message
323 
324  DBG_PRINT((DBG_PREFIX "CBM4WDM.SYS " __DATE__ " " __TIME__));
325 
326  // Perform initialization common to NT4 and WDM driver
327 
328  ntStatus = DriverCommonInit(DriverObject, RegistryPath);
329 
331 
333 
334  // enumerate all parallel port drivers:
335 
336  ntStatus = ParPortEnumerateOpen(&enumerate);
337 
338  if (NT_SUCCESS(ntStatus))
339  {
340  PCWSTR DriverName;
341 
342  do
343  {
344  ntStatus = ParPortEnumerate(enumerate,&DriverName);
345 
346  if (NT_SUCCESS(ntStatus) && *DriverName)
347  {
348  DBG_SUCCESS((DBG_PREFIX "Drivername = \"%ws\"", DriverName));
349  AddDevice(DriverObject, NULL, DriverName);
350  }
351  } while (NT_SUCCESS(ntStatus) && *DriverName);
352 
353  ParPortEnumerateClose(enumerate);
354  }
355 
356  // From now on, it is legal to be unloaded
357 
358  DBG_IRQL( <= DISPATCH_LEVEL);
359  KeReleaseMutex(&MutexDriverLoadUnload, FALSE);
360 
361  FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
362 }
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
Unload routine of the driver.
#define LogErrorString(_Fdo_, _UniqueErrorValue_, _String1_, _String2_)
Definition: util.h:39
NTSTATUS cbm_unlock_parport(IN PDEVICE_EXTENSION Pdx)
Unlock the parallel port for the driver.
Definition: lockunlock.c:128
NTSTATUS AddDeviceCommonInit(IN PDEVICE_OBJECT Fdo, IN PUNICODE_STRING DeviceName, IN PCWSTR ParallelPortName)
Initialize device object, common to WDM and NT4 driver.
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PdoUNUSED, IN PCWSTR ParallelPortName)
create functional device object (FDO) for enumerated device
NTSTATUS DriverCommonInit(IN PDRIVER_OBJECT Driverobject, IN PUNICODE_STRING RegistryPath)
Perform driver initialization, common to WDM and NT4 driver.
Define the IOCTL codes for the opencbm driver.
NTSTATUS ParPortEnumerate(PENUMERATE EnumStruct, PCWSTR *DriverName)
Get next enumerated parallel port driver.
Definition: nt4/PortEnum.c:196
VOID DbgAllocateMemoryBuffer(VOID)
Get storage area for debugging output.
#define FUNC_LEAVE()
Definition: debug.h:349
VOID cbm_stop_thread(IN PDEVICE_EXTENSION Pdx)
Stop the worker thread.
Definition: thread.c:117
VOID ParPortEnumerateClose(PENUMERATE EnumStruct)
Stop enumeration of the parallel port drivers.
Definition: nt4/PortEnum.c:264
#define DBG_ASSERT(_xxx)
Definition: debug.h:401
#define DBG_ERROR(_xxx)
Definition: debug.h:397
#define DBG_SUCCESS(_xxx)
Definition: debug.h:393
VOID cbm_init_registry(IN PUNICODE_STRING RegistryPath, IN PDEVICE_EXTENSION Pdx)
Initialize from registry.
#define MTAG_DEVNAME
Definition: memtags.h:26
VOID DriverCommonUninit(VOID)
Undo what DriverCommonInit() has done.
NTSTATUS ParPortEnumerateOpen(PENUMERATE *EnumStruct)
Start enumeration of the parallel port drivers.
Definition: nt4/PortEnum.c:74
#define FUNC_ENTER()
Definition: debug.h:347
const UCHAR * DebugNtStatus(NTSTATUS Value)
Return the description of an NTSTATUS code.
Definitions for the opencbm driver.
#define DBG_PREFIX
Definition: debug.h:320
NTSTATUS ParPortDeinit(PDEVICE_EXTENSION Pdx)
Undoes anything ParPortInit has done.
Definition: PortAccess.c:339
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
Start routine of the driver.
VOID DbgFreeMemoryBuffer(VOID)
Free storage area for debugging output.
PVOID PENUMERATE
#define DBG_PRINT(_xxx)
Definition: debug.h:403