OpenCBM
libcommon/init.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 "iec.h"
22 
26 static UNICODE_STRING ServiceKeyRegistryPath;
27 
54 VOID
55 cbm_init_registry(IN PUNICODE_STRING RegistryPath, IN PDEVICE_EXTENSION Pdx)
56 {
57  NTSTATUS ntStatus;
58 
59  FUNC_ENTER();
60 
61  ntStatus = STATUS_SUCCESS;
62 
63  if (RegistryPath)
64  {
65  // Copy the registry path to the location
66 
67  DBG_ASSERT(ServiceKeyRegistryPath.Buffer == 0);
68 
69  // Allocate memory for the registry path
70 
71  ServiceKeyRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
72  RegistryPath->Length, MTAG_SERVKEY);
73 
74  // Copy the registry path into the variable
75 
76  if (ServiceKeyRegistryPath.Buffer)
77  {
78  ServiceKeyRegistryPath.MaximumLength =
79  ServiceKeyRegistryPath.Length = RegistryPath->Length;
80 
81  RtlCopyUnicodeString(&ServiceKeyRegistryPath, RegistryPath);
82  }
83  else
84  {
85  // No memory could be allocateed, mark the
86  // length of the string appropriately
87 
88  ServiceKeyRegistryPath.MaximumLength =
89  ServiceKeyRegistryPath.Length = 0;
90  }
91  }
92 
93  // If there is some registry path given, read from that
94 
95  if (ServiceKeyRegistryPath.Length != 0 && ServiceKeyRegistryPath.Buffer != NULL)
96  {
97  HANDLE hKey;
98 
99  // Open the registry for reading
100 
101  ntStatus = cbm_registry_open_for_read(&hKey, &ServiceKeyRegistryPath);
102 
103  if (NT_SUCCESS(ntStatus))
104  {
105  // the cable type
106 
107  ULONG iecCable = IEC_CABLETYPE_AUTO;
108 
109 #if DBG
110  // In debugging versions, make sure the DebugFlags
111  // are read from the registry
112 
113  cbm_registry_read_ulong(hKey, L"DebugFlags", &DbgFlags);
114 
115 #endif // #if DBG
116 
117  if (Pdx)
118  {
119  //
120  // update the cable type
121  //
122 
123  cbm_registry_read_ulong(hKey, L"CableType", &iecCable);
124 
125  cbmiec_set_cabletype(Pdx, iecCable);
126 
127  //
128  // update if we are requested to permanently lock the parallel port
129  //
130 
131  iecCable = 1; // default is: Yes, lock
132  cbm_registry_read_ulong(hKey, L"PermanentlyLock", &iecCable);
133  Pdx->ParallelPortLock = iecCable ? TRUE : FALSE;
134 
135  }
136 
137  // initialize the libiec library
138 
139  cbmiec_global_init(&hKey);
140 
141  // we're done with the registry
142 
143  cbm_registry_close(hKey);
144  }
145  else
146  {
147  // An error occured.
148  // In this case, initialize the libiec with defaults
149 
150  cbmiec_global_init(NULL);
151  }
152  }
153  else
154  {
155  // No registry path is given.
156  // In this case, initialize the libiec with defaults
157 
158  cbmiec_global_init(NULL);
159  }
160 
161  FUNC_LEAVE();
162 }
163 
173 VOID
174 cbm_initialize_cable_deferred(IN PDEVICE_EXTENSION Pdx)
175 {
176  FUNC_ENTER();
177 
178  Pdx->CableInitTimer = 5; // wait 5 seconds before initializing the cable
179 
180  DBG_IRQL( <= DISPATCH_LEVEL);
181  IoStartTimer(Pdx->Fdo);
182 
183  FUNC_LEAVE();
184 }
185 
186 
204 static NTSTATUS
205 CompleteIOCTL(PDEVICE_OBJECT Fdo, PIRP Irp, PVOID Context)
206 {
207  NTSTATUS ntStatus;
208 
209  FUNC_ENTER();
210 
211  UNREFERENCED_PARAMETER(Context);
212 
213 // DBG_IRQL( <= DISPATCH_LEVEL);
214 // IoStopTimer(Fdo);
215 
216  DBG_IRQL( <= DISPATCH_LEVEL);
217  IoFreeIrp(Irp);
218 
219  FUNC_LEAVE_NTSTATUS_CONST(STATUS_MORE_PROCESSING_REQUIRED);
220 }
221 
241 static VOID
242 InitializeCableTimerRoutine(PDEVICE_OBJECT Fdo, PVOID Context)
243 {
244  PDEVICE_EXTENSION pdx = Context;
245 
246  FUNC_ENTER();
247 
248  // InitializeCableTimerRoutine is called at DISPATCH_LEVEL
249  DBG_IRQL( == DISPATCH_LEVEL);
250 
251  if (pdx->CableInitTimer > 0 && --pdx->CableInitTimer == 0)
252  {
253  NTSTATUS ntStatus;
254 
255  do {
256  PIO_STACK_LOCATION irpSp;
257  PIRP irp;
258 
259  // send a CBMCTRL_UPDATE as ioctl to myself
260 
261  DBG_IRQL( <= DISPATCH_LEVEL );
262  irp = IoAllocateIrp(Fdo->StackSize, FALSE);
263  if (irp == NULL)
264  {
265  ntStatus = STATUS_INSUFFICIENT_RESOURCES;
266  break;
267  }
268 
269  DBG_IRQL( <= DISPATCH_LEVEL );
270  irpSp = IoGetNextIrpStackLocation(irp);
271 
272  irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
273  irpSp->Parameters.DeviceIoControl.IoControlCode = CBMCTRL_UPDATE;
274  irpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
275  irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
276  irpSp->FileObject = NULL;
277 
278  DBG_IRQL( <= DISPATCH_LEVEL );
279  IoSetCompletionRoutine(irp, CompleteIOCTL, pdx, TRUE, TRUE, TRUE);
280 
281  DBG_IRQL( <= DISPATCH_LEVEL );
282  ntStatus = IoCallDriver(Fdo, irp);
283 
284  // If we did not succeed in calling the driver, free the IRP again
285 
286  if (!NT_SUCCESS(ntStatus))
287  {
288  IoFreeIrp(irp);
289  break;
290  }
291 
292  } while (0);
293  }
294 
295  FUNC_LEAVE();
296 }
297 
314 NTSTATUS
315 DriverCommonInit(IN PDRIVER_OBJECT Driverobject, IN PUNICODE_STRING RegistryPath)
316 {
317  FUNC_ENTER();
318 
319  // If performance evaluation is active, initialize that
320 
321  PERF_INIT();
322 
323  // Initialize the settings from the registry
324 
325  cbm_init_registry(RegistryPath, NULL);
326 
327  // set the function pointers to our driver
328 
329  Driverobject->DriverUnload = DriverUnload;
330  Driverobject->MajorFunction[IRP_MJ_CREATE] = cbm_createopenclose;
331  Driverobject->MajorFunction[IRP_MJ_CLOSE] = cbm_createopenclose;
332  Driverobject->MajorFunction[IRP_MJ_CLEANUP] = cbm_cleanup;
333  Driverobject->MajorFunction[IRP_MJ_READ] = cbm_readwrite;
334  Driverobject->MajorFunction[IRP_MJ_WRITE] = cbm_readwrite;
335  Driverobject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = cbm_devicecontrol;
336  Driverobject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = cbm_devicecontrol;
337 
338  FUNC_LEAVE_NTSTATUS_CONST(STATUS_SUCCESS);
339 }
340 
348 VOID
350 {
351  FUNC_ENTER();
352 
353  // If performance evaluation is active, stop it
354 
355  PERF_SAVE();
356 
357  // If we allocated memory for the service key registry
358  // path, free that memory.
359 
360  if (ServiceKeyRegistryPath.Buffer)
361  {
362  ExFreePool(ServiceKeyRegistryPath.Buffer);
363  DBGDO(ServiceKeyRegistryPath.Buffer = NULL;
364  ServiceKeyRegistryPath.MaximumLength = ServiceKeyRegistryPath.Length = 0);
365  }
366 
367  FUNC_LEAVE();
368 }
369 
401 NTSTATUS
402 AddDeviceCommonInit(IN PDEVICE_OBJECT Fdo, IN PUNICODE_STRING DeviceName,
403  IN PCWSTR ParallelPortName)
404 {
405  PDEVICE_EXTENSION pdx;
406  UNICODE_STRING parallelPortName;
407  NTSTATUS ntStatus;
408 
409  FUNC_ENTER();
410 
411  // Initialize the Device Extension
412 
413  pdx = Fdo->DeviceExtension;
414 
415  // make sure the device extension is initialized to zero
416 
417  RtlZeroMemory(pdx, sizeof(*pdx));
418 
419  // Store the name in the device extension
420 
421  pdx->DeviceName.Buffer = DeviceName->Buffer;
422  pdx->DeviceName.Length = DeviceName->Length;
423  pdx->DeviceName.MaximumLength = DeviceName->MaximumLength;
424 
425  // a back-pointer to the fdo contained in the extension
426 
427  pdx->Fdo = Fdo;
428 
429  // Initialize the QUEUE object
430 
431  QueueInit(&pdx->IrpQueue, cbm_startio);
432 
433  // we want to do buffered I/O
434  // since we are not passing very big portions of data,
435  // the speed disadvantage is not that big
436 
437  Fdo->Flags |= DO_BUFFERED_IO;
438 
439  // Generate a UNICODE_STRING containing the name of the
440  // parallel port driver
441 
442  parallelPortName.Buffer = (PWSTR) ParallelPortName;
443  parallelPortName.Length = (USHORT) wcslen(ParallelPortName) * sizeof(WCHAR);
444  parallelPortName.MaximumLength = parallelPortName.Length;
445 
446  // Mark if we are running on an machine with more than one processor
447 
448 /*
449 #ifdef COMPILE_W98_API
450  pdx->IsSMP = 0;
451 #elif COMPILE_W2K_API
452  pdx->IsSMP = (*KeNumberProcessors > 1) ? TRUE : FALSE;
453 #else
454  pdx->IsSMP = (KeNumberProcessors > 1) ? TRUE : FALSE;
455 #endif
456 */
457  pdx->IsSMP = (CbmGetNumberProcessors() > 1) ? TRUE : FALSE;
458 
459  // Initialize timer so that it can be used later on for device initialization
460 
461  DBG_IRQL( == PASSIVE_LEVEL);
462  IoInitializeTimer(pdx->Fdo, InitializeCableTimerRoutine, pdx);
463 
464  // Initialize the parallel port information
465 
466  ntStatus = ParPortInit(&parallelPortName, pdx);
467 
468  if (!NT_SUCCESS(ntStatus))
469  {
470  DBG_ERROR((DBG_PREFIX "ParPortInit() FAILED, deleting device"));
471  LogErrorString(Fdo, CBM_START_FAILED, L"initialization of the parallel port.", NULL);
472  }
473 
474  // Now, start the worker thread
475 
476  if (NT_SUCCESS(ntStatus))
477  {
478  ntStatus = cbm_start_thread(pdx);
479 
481  }
482 
483  // Now, log success to the event logger if we succeeded.
484  // If we failed, the FDO will be deleted soon.
485 
486  if (NT_SUCCESS(ntStatus))
487  {
488  LogErrorOnly(Fdo, CBM_STARTED);
489  }
490 
491  FUNC_LEAVE_NTSTATUS(ntStatus);
492 }
#define DBGDO(_xxx)
Definition: debug.h:409
#define LogErrorString(_Fdo_, _UniqueErrorValue_, _String1_, _String2_)
Definition: util.h:39
#define PERF_SAVE()
Definition: perfeval.h:91
VOID QueueInit(PQUEUE Queue, PCBMDRIVER_STARTIO DriverStartIo)
Initialize a QUEUE object.
Definition: queue.c:388
NTSTATUS cbm_start_thread(IN PDEVICE_EXTENSION Pdx)
Start the worker thread.
Definition: thread.c:34
unsigned long DbgFlags
VOID DriverCommonUninit(VOID)
Undo what DriverCommonInit() has done.
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
Unload routine of the driver.
NTSTATUS cbmiec_global_init(IN PHANDLE HKey)
Initialization for libiec which are global in nature.
Definition: libiec/init.c:251
NTSTATUS cbm_readwrite(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
Services reads from or writes to the driver.
Definition: readwrite.c:84
VOID cbmiec_set_cabletype(IN PDEVICE_EXTENSION Pdx, IN IEC_CABLETYPE CableType)
Set the type of the IEC cable.
Definition: libiec/init.c:139
NTSTATUS cbm_registry_close(IN HANDLE HandleKey)
Close a registry key.
Definition: util-reg.c:230
Definitions for the libiec library.
#define FUNC_LEAVE()
Definition: debug.h:349
NTSTATUS AddDeviceCommonInit(IN PDEVICE_OBJECT Fdo, IN PUNICODE_STRING DeviceName, IN PCWSTR ParallelPortName)
Initialize device object, common to WDM and NT4 driver.
NTSTATUS cbm_createopenclose(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
Services IRPs containing the IRP_MJ_CREATE or IRP_MJ_CLOSE I/O function code.
NTSTATUS cbm_registry_read_ulong(IN HANDLE HandleKey, IN PCWSTR KeyName, OUT PULONG Value)
Read a ULONG value out of a registry key.
Definition: util-reg.c:299
#define DBG_ASSERT(_xxx)
Definition: debug.h:401
NTSTATUS cbm_cleanup(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
Services IRPs containing the IRP_MJ_CLEANUP I/O function code.
Definition: cleanup.c:44
#define DBG_ERROR(_xxx)
Definition: debug.h:397
NTSTATUS cbm_devicecontrol(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
Services IOCTLs.
Definition: ioctl.c:115
VOID cbm_init_registry(IN PUNICODE_STRING RegistryPath, IN PDEVICE_EXTENSION Pdx)
Initialize from registry.
#define PERF_INIT()
Definition: perfeval.h:85
#define CBMCTRL_UPDATE
IOCTL for updating settings of the driver.
Definition: cbmioctl.h:331
#define FUNC_ENTER()
Definition: debug.h:347
NTSTATUS cbm_startio(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
Execute an IRP.
Definition: startio.c:39
ULONG CbmGetNumberProcessors(VOID)
Get the number of processors in the system.
Definition: processor.c:57
Definitions for the opencbm driver.
NTSTATUS ParPortInit(PUNICODE_STRING ParallelPortName, PDEVICE_EXTENSION Pdx)
Initialize the knowledge on a parallel port.
Definition: PortAccess.c:253
VOID cbm_initialize_cable_deferred(IN PDEVICE_EXTENSION Pdx)
Initialize the cable.
#define DBG_PREFIX
Definition: debug.h:320
#define LogErrorOnly(_Fdo_, _UniqueErrorValue_)
Definition: util.h:35
#define MTAG_SERVKEY
Definition: memtags.h:35
NTSTATUS cbm_registry_open_for_read(OUT PHANDLE HandleKey, IN PUNICODE_STRING Path)
Open a registry path for reading.
Definition: util-reg.c:43
NTSTATUS DriverCommonInit(IN PDRIVER_OBJECT Driverobject, IN PUNICODE_STRING RegistryPath)
Perform driver initialization, common to WDM and NT4 driver.