Manage Device Context (Compact 2013)
3/26/2014
Device drivers typically use device context to manage physical resources and memory areas that are associated with a hardware device. The device context is usually a pointer to a data structure that contains information about a single hardware device and the resources the system uses to control that device. A device driver might use multiple device contexts to support multiple hardware devices. For example, when a network device driver manages multiple network adapters, it creates and maintains a separate device context for each network adapter.
When the Device Manager calls your XXX_Init (Device Manager) function, your return value is the device context (a DWORD) that you create for the initialized device. The Device Manager passes a registry path of your driver that describes the device to be initialized, and your driver uses this information to populate any data structures that are associated with the device context that you create for that device.
As an example, the following is a modified version of the stream driver SDT_Init function, with additional code to create and return a device context.
// SDT_Init
// This function initializes the device driver. Its responsibility
// is to set the default state of the device and to allocate and
// initialize any global variables or resources.
// Upon success, this function returns a handle to the driver’s state
// (device context). This is passed to Open and Deinit when they are
// called.
DWORD SDT_Init(LPCTSTR pContext, DWORD dwBusContext)
{
BOOL fOk = FALSE;
DEBUGMSG(ZONE_INIT,
(TEXT("SDT_Init(): context %s.\r\n"), pContext));
// Allocate enough storage for this device context:
SDT_DEV_CONTEXT* pDevContext =
(SDT_DEV_CONTEXT *)LocalAlloc(LPTR, sizeof(SDT_DEV_CONTEXT));
// If allocation failed, set the error, clean up, and exit:
if (pDevContext == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
DEBUGMSG(ZONE_ERROR,
(TEXT("SDT_Init(): cannot allocate memory!\r\n)));
goto cleanup;
}
// Try to read the registry entry for this device into
// the device context data structure (implement the function
// ReadRegistry to open the registry key passed in pContext
// and populate pDevContext with information from this
// registry key).
if (!ReadRegistry(pContext, pDevContext))
{
DEBUGMSG(ZONE_WARNING,
(TEXT("SDT_Init(): unable to read registry!)));
goto cleanup;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Initialize device hardware here
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
fOk = TRUE;
cleanup:
// If initialization fails, free the device context
// structure and prepare to return 0 (NULL).
// Otherwise, if initialization succeeds, return
// the device context.
if ( !fOk && pDevContext )
{
LocalFree(pDevContext);
pDevContext = NULL;
}
DEBUGMSG(ZONE_INIT,
(TEXT("SDT_Init(): context %x.\r\n"), pDevContext));
g_pDevContext = pDevContext;
return (DWORD) pDevContext;
}
In this example, when SDT_Init is called, it allocates a structure to hold the device context, reads the registry key for the device (passed in the first parameter), and initializes driver data structures with information from that registry key. After it initializes the device hardware (using information stored in pDevContext), it returns pDevContext to the caller. If the driver is unable to allocate a device context structure for the device or if it detects an error while initializing hardware, it sets the appropriate error code by calling SetLastError and returns 0 (zero) as the value of the device context to indicate that SDT_Init did not succeed.
In this example, the device driver supports only one device context. If your device driver supports multiple devices, and therefore, multiple device contexts, you can modify this code to save multiple copies of pDevContext in a global device driver data structure such as a linked list. For an example of how to save multiple open contexts in a global device driver data structure, see Manage Open Context. You can use this approach to manage multiple device contexts.