In the DriverShell Example that I posted (Windows CE: A Stream Interface Driver Shell), I included an XXX_Init() function that didn’t do very much. This post will discuss the things that you can do with XXX_Init(). For reference, this is the function as I originally posted it.
DWORD XXX_Init(LPCTSTR RegistryPath, DWORD dwBusContect) 
{
    HKEY hKey;
 
    RETAILMSG( 1, (TEXT("XXX_Init\n")));
    
    hKey = OpenDeviceKey(RegistryPath);
    if ( !hKey ) {
        RETAILMSG(1, (TEXT("Failed to open devkeypath,\r\n")));
    }
    else
    {
         // Read values from registry if needed
 
         RegCloseKey (hKey);
    }
 
    return TRUE;
}
 
The Init function is called by the device manager soon after loading the driver. XXX_Init() is the driver’s chance to:
·         Initialize the hardware that the driver will manage
·         Read registry setting
·         Initialize global variables that the driver may need
·         Start threads
·         Start interrupts
·         Create synchronization objects
The parameters passed into XXX_Init() are a pointer to a string that contains the active registry key name. This registry key name is important because the driver really should not depend on any fixed registry key name, and because if you need to have multiple instances of the driver each will have a different registry key name. The other parameter is a DWORD which could be a pointer to data based in by the process that called ActivateDeviceEx(). This would only be used if the driver is loaded by an application or by a BUS driver.
Initialize the Hardware
Most, but not all, drivers manage some hardware. XXX_Init() is a good place to make sure that the hardware is powered up and initialized to some known value.   For some hardware, you may want to wait until an application opens the driver to power up the hardware. 
Keep in mind that in some cases the hardware may not be in a known state when the driver is loaded. There are some chips that are not reset on a soft reset or even a hard reset, but are only reset when power is applied to the board.   In one case that I have seen the interrupt enable for the chip is enabled when the chip is reset, but the chip was only reset when power was applied to the board, so if the driver didn’t specifically enable the interrupt there would be no interrupts if the board was reset.
For a driver like a virtual serial port driver, XXX_Init() might be a good place to open the physical serial driver.
Read Registry Settings
If your driver is configurable via the registry, XXX_Init() is where your driver should read the registry settings using the key name that is passed in. OpenDeviceKey() can be used to obtain a HANDLE to the registry key.
Initialize Global Variables
At first glance, you might think there isn’t much to say about this, but this can be very important to the function of the driver. If the driver will have multiple instances running, it will be important to create a set of data that identifies the instance. This data set probably will not be saved in a global variable declared in the driver file, but instead will be data that is allocated when XXX_Init() runs and a pointer to the data should be returned by the function. On calls to XXX_Open() other functions the pointer will be passed in so the functions will have information about the current instance of the driver.
One important piece of data to have is a counter of open calls that will be incremented when the driver is opened and decremented when it is closed. This counter can be used to limit access to the driver, especially if the driver is only capable of having a single open at a time. Other data to have might include a virtual address of the hardware.
Start Threads
If the driver needs to have threads running, like an Interrupt Service Thread (ISR), the driver might need to start that thread from XXX_Init().
Start Interrupts
If the driver is to handle interrupts, use functions like InterruptInitialize() and CreateEvent() to initialize and start the interrupt handling.
Create Synchronization Objects
Synchronization objects like events, critical sections, mutexes and semaphores are important for managing multiple driver instances and/or multiple threads. The objects that the driver uses will depend on what it is doing.
Return Value
The return value must be non-zero on success. DriverShell returns TRUE, but that is because DriverShell doesn’t actually do anything. A better return value would be a unique identifier for the instance of the driver, like a pointer to the instance data.
Tags:
Copyright © 2008 – Bruce Eitman
All Rights Reserved