OpenCBM
nt4/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 Spiro Trikaliotis
8  *
9  */
10 
19 #include <ntddk.h>
20 #include "cbm_driver.h"
21 #include "cbmioctl.h"
22 
23 #undef ExFreePool
24 
54 NTSTATUS
55 AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PdoUNUSED, IN PCWSTR ParallelPortName)
56 {
57  PDEVICE_OBJECT fdo;
58  UNICODE_STRING deviceNameNumber;
59  UNICODE_STRING deviceNamePrefix;
60  UNICODE_STRING deviceName;
61  NTSTATUS ntStatus;
62  WCHAR deviceNameNumberBuffer[50];
63 
65  static SHORT no = 0;
66 
67  FUNC_ENTER();
68 
69  UNREFERENCED_PARAMETER(PdoUNUSED);
70 
71  // Until now, no error has occurred
72 
73  ntStatus = STATUS_SUCCESS;
74 
75  // Create the name for the fdo
76  // thus, this is a named driver
77 
78  DBG_IRQL( <= DISPATCH_LEVEL);
79  RtlInitUnicodeString(&deviceNamePrefix, CBMDEVICENAME);
80 
81  // Convert variable no into a UNICODE_STRING
82 
83  deviceNameNumber.Length = 0;
84  deviceNameNumber.MaximumLength = sizeof(deviceNameNumberBuffer);
85  deviceNameNumber.Buffer = deviceNameNumberBuffer;
86  DBG_IRQL( == PASSIVE_LEVEL);
87  RtlIntegerToUnicodeString(no, 10, &deviceNameNumber);
88 
89  // Increment the number for the next device
90 
91  ++no;
92 
93  // Allocate enough space for the concatenation of deviceNamePrefix
94  // and deviceNameNumber
95 
96  deviceName.MaximumLength = deviceNamePrefix.Length + deviceNameNumber.Length;
97  deviceName.Buffer = (PWCHAR) ExAllocatePoolWithTag(NonPagedPool,
98  deviceName.MaximumLength, MTAG_DEVNAME);
99 
100  if (!deviceName.Buffer)
101  {
102  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
103  DBG_ERROR((DBG_PREFIX "Could not allocate memory for deviceName"))
104  LogErrorString(NULL, CBM_START_FAILED, L"allocating memory for device name", NULL);
105  }
106 
107  if (NT_SUCCESS(ntStatus))
108  {
109  // Concatenate both strings
110 
111  DBG_IRQL( < DISPATCH_LEVEL);
112  RtlCopyUnicodeString(&deviceName, &deviceNamePrefix);
113  DBG_IRQL( < DISPATCH_LEVEL);
114  RtlAppendUnicodeStringToString(&deviceName, &deviceNameNumber);
115 
116  // create the FDO with the name just build
117 
118  DBG_IRQL( == PASSIVE_LEVEL);
119  ntStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &deviceName,
120  FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, TRUE, &fdo);
121 
122  if (!NT_SUCCESS(ntStatus))
123  {
124  DBG_ERROR((DBG_PREFIX "IoCreateDevice failed with 0x%08X - %s",
125  ntStatus, DebugNtStatus(ntStatus)));
126  LogErrorString(NULL, CBM_START_FAILED, L"creation of the device object", NULL);
127  }
128  }
129 
130  if (NT_SUCCESS(ntStatus))
131  {
132  PDEVICE_EXTENSION pdx;
133 
134  // Initialization common to WDM and NT4 driver
135 
136  ntStatus = AddDeviceCommonInit(fdo, &deviceName, ParallelPortName);
137 
138  // mark that we are running the NT4 version of the driver
139 
140  pdx = fdo->DeviceExtension;
141  pdx->IsNT4 = TRUE;
142 
143  if (!NT_SUCCESS(ntStatus))
144  {
145  // An error has occurred, thus, delete the device
146 
147  // If necessary, delete the buffer for the device name
148 
149  if (pdx->DeviceName.Buffer)
150  {
151  DBG_IRQL( < DISPATCH_LEVEL);
152  ExFreePool(pdx->DeviceName.Buffer);
153  }
154 
155  DBG_IRQL( == PASSIVE_LEVEL);
156  IoDeleteDevice(fdo);
157  }
158  }
159 
160  FUNC_LEAVE_NTSTATUS(ntStatus);
161 }
162 
163 static KMUTEX MutexDriverLoadUnload;
164 
177 VOID
178 DriverUnload(IN PDRIVER_OBJECT DriverObject)
179 {
180  PDEVICE_OBJECT currentDevice;
181 
182  FUNC_ENTER();
183 
184  // Obtain the mutex that prevents premature unloading
185 
186  DBG_IRQL( < DISPATCH_LEVEL);
187  KeWaitForMutexObject(&MutexDriverLoadUnload, Executive, KernelMode,
188  FALSE, NULL);
189 
190  // Make sure every device object is deleted
191 
192  while (currentDevice = DriverObject->DeviceObject)
193  {
194  PDEVICE_EXTENSION pdx = currentDevice->DeviceExtension;
195 
196  DBG_ASSERT(pdx);
197 
198  // Unlock the parallel port, if necessary
199 
200  if (pdx->ParallelPortIsLocked)
201  {
202  cbm_unlock_parport(pdx);
203  }
204 
205  // Stop the thread of that device, if necessary
206 
207  cbm_stop_thread(pdx);
208 
209  // Uninitialize the parallel port, if necessary
210 
211  ParPortDeinit(pdx);
212 
213  // If a buffer for the device name has been allocated,
214  // release that
215 
216  if (pdx->DeviceName.Buffer)
217  {
218  DBG_IRQL( < DISPATCH_LEVEL);
219  ExFreePool(pdx->DeviceName.Buffer);
220  }
221 
222  // Delete the device
223  // This has to be done *after* the above, as the pdx
224  // is not allowed to be accessed anymore here.
225 
226  DBG_IRQL( == PASSIVE_LEVEL);
227  IoDeleteDevice(currentDevice);
228  }
229 
230  // some more uninitialization, common to WDM and NT4 driver
231 
233 
234 #if DBG
235 
237 
238 #endif
239 
240  // From now on, it is legal to be unloaded
241 
242  DBG_IRQL( <= DISPATCH_LEVEL);
243  KeReleaseMutex(&MutexDriverLoadUnload, FALSE);
244 
245  FUNC_LEAVE();
246 }
247 
270 NTSTATUS
271 DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
272 {
273  PENUMERATE enumerate;
274  NTSTATUS ntStatus;
275 
276  FUNC_ENTER();
277 
278  // Initialize the debugging system
279 
280  DBG_INIT();
281 
282  // Initialize the mutex which should prevent premature unloading
283 
284  KeInitializeMutex(&MutexDriverLoadUnload, 0);
285 
286  // Now, obtain that mutex as first operation
287 
288  DBG_IRQL( < DISPATCH_LEVEL);
289  KeWaitForMutexObject(&MutexDriverLoadUnload, Executive, KernelMode,
290  FALSE, NULL);
291 
292 #if DBG
293 
295 
296 #endif
297 
298  // Output a status message
299 
300  DBG_PRINT((DBG_PREFIX "CBM4NT.SYS " __DATE__ " " __TIME__));
301 
302  // Perform initialization common to NT4 and WDM driver
303 
304  ntStatus = DriverCommonInit(DriverObject, RegistryPath);
305 
306  // enumerate all parallel port drivers:
307 
308  ntStatus = ParPortEnumerateOpen(&enumerate);
309 
310  if (NT_SUCCESS(ntStatus))
311  {
312  PCWSTR DriverName;
313 
314  do
315  {
316  ntStatus = ParPortEnumerate(enumerate,&DriverName);
317 
318  if (NT_SUCCESS(ntStatus) && *DriverName)
319  {
320  DBG_SUCCESS((DBG_PREFIX "Drivername = \"%ws\"", DriverName));
321  AddDevice(DriverObject, NULL, DriverName);
322  }
323  } while (NT_SUCCESS(ntStatus) && *DriverName);
324 
325  ParPortEnumerateClose(enumerate);
326  }
327 
328  // From now on, it is legal to be unloaded
329 
330  DBG_IRQL( <= DISPATCH_LEVEL);
331  KeReleaseMutex(&MutexDriverLoadUnload, FALSE);
332 
333  FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
334 }
#define LogErrorString(_Fdo_, _UniqueErrorValue_, _String1_, _String2_)
Definition: util.h:39
NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PdoUNUSED, IN PCWSTR ParallelPortName)
create functional device object (FDO) for enumerated device
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 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
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
Start routine of the driver.
#define DBG_ASSERT(_xxx)
Definition: debug.h:401
#define DBG_ERROR(_xxx)
Definition: debug.h:397
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
Unload routine of the driver.
#define DBG_SUCCESS(_xxx)
Definition: debug.h:393
#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
VOID DbgFreeMemoryBuffer(VOID)
Free storage area for debugging output.
PVOID PENUMERATE
#define DBG_PRINT(_xxx)
Definition: debug.h:403