/*-------------------------------------------------------------------------*/
/*!
 * \file	registry.c
 * \brief	Implements several helper routines for reading from the registry.
 *
 * File:	registry.c
 *
 * Purpose:
 *
 *	Device drivers read lots of configuration information out of the registry.
 *	This file contains the implementation of several functions which read
 *	specific information from the registry.
 *
 * Copyright (c) 2002-2005 Logic Product Development
 *
 * NOTICE:
 *	This file contains source code, ideas, techniques, and information
 *	(the Information) which are Proprietary and Confidential Information
 *	of Logic Product Development, Inc.  This Information may not be used
 *	by or disclosed to any third party except under written license, and
 *	shall be subject to the limitations prescribed under license.
 */
/*-------------------------------------------------------------------------*/
#include <windows.h>
#include "registry.h"
#include "debug_zones.h"


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Returns a handle to the driver's configuration registry key.
 *
 * \b Purpose:
 *
 *	This function is responsible for getting a handle to this driver's
 *	configuration registry key.
 *
 *	\post	NOTE, the caller is responsible for closing the handle returned
 *			by this function.
 *
 * \return	Handle to an open registry key upon success. INVALID_HANDLE_VALUE
 *			upon failure.
 */
/*-------------------------------------------------------------------------*/
HKEY
get_active_reg_key(ULONG reg_key)
{
   ULONG ret_val, val_size;
   HKEY  active_key = INVALID_HANDLE_VALUE;
   WCHAR *config_registry_path;
   
   /* Get a handle to the configuration registry key. */
   ret_val =
      RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCWSTR)reg_key, 0, 0, &active_key);
   
   if ( ERROR_SUCCESS != ret_val ) {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open registry key %s.\r\n"),
         DRVR_NAME, (LPCTSTR)reg_key));
      return (HKEY)(INVALID_HANDLE_VALUE);
   }
   
   /* Get configuration information path from the acquired active_key. */
   val_size = 0;
   ret_val =
      RegQueryValueEx(active_key, TEXT("Key"), 0, NULL,
         (PUCHAR)NULL, &val_size);
   
   if ( ERROR_SUCCESS != ret_val )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\Key.\r\n"),
         DRVR_NAME, (LPCTSTR)active_key));
      RegCloseKey(active_key);
      return (HKEY)(INVALID_HANDLE_VALUE);
   }
   
   /* Allocate enough space to store the string designating the
    * configuration registry key. */
   config_registry_path = LocalAlloc(LPTR, val_size + 4);
   if ( !config_registry_path )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
               (TEXT("%s Error, can't malloc() _2.\r\n"),
               DRVR_NAME, (LPCTSTR)active_key));
      RegCloseKey(active_key);
      return (HKEY)(INVALID_HANDLE_VALUE);
   }
   
   /* Now copy the string from the registry. */
   RegQueryValueEx(active_key, TEXT("Key"), 0, NULL,
      (PUCHAR)config_registry_path, &val_size);
   
   /* Done with that key. */
   RegCloseKey(active_key);
   
   FOOMSG(ZONE_INIT,
      (TEXT("%s configuration registry key is %s.\r\n"),
      DRVR_NAME, (LPCTSTR)config_registry_path));
   
   /* Open up the configuration key. */
   ret_val =
   RegOpenKeyEx(HKEY_LOCAL_MACHINE, config_registry_path, 0, 0, &active_key);
   
   if ( ERROR_SUCCESS != ret_val )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open registry key %s.\r\n"),
         DRVR_NAME, (LPCTSTR)config_registry_path));
      
      active_key = (HKEY)(INVALID_HANDLE_VALUE);
   }
   
   /* Clean up we are about to exit. */
   LocalFree(config_registry_path);
   
   return (active_key);
   
} /* end get_active_reg_key() */


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Queries the registry to determine the appropriate IRQ.
 *
 * \b Purpose:
 *
 *	This function looks for a DWORD value under the "Irq" key in the
 *	registry string passed to it.
 *
 * \return	IRQ number specified in the registry or 0 for failure.
 *
 */
/*-------------------------------------------------------------------------*/
DWORD
read_irq_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   DWORD irq;
   
   FOOMSG(ZONE_INIT, (TEXT("%s read_irq_from_reg:active_key:%x.\r\n"),
      DRVR_NAME, active_key));
   
   /* Read the IRQ number that our caller would like to use. */
   val_size = sizeof(irq);
   ret_val =
   RegQueryValueEx(active_key,TEXT("Irq"), 0,
      NULL, (PUCHAR)(&irq), &val_size);
   
   if ( ERROR_SUCCESS != ret_val )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\Irq. No IRQ specified.\r\n"),
         DRVR_NAME, (char *)active_key));
      return (0);
   }
   
   return (irq);
   
} /* end read_irq_from_reg() */

/*-------------------------------------------------------------------------*/
/*!
 * \brief	Returns a DWORD containing the address of a scratch register.
 *
 * \b Purpose:
 *
 * \return	Address upon success. Zero upon failure.
 */
/*-------------------------------------------------------------------------*/
DWORD
read_address_base_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   DWORD address_base;
   
   FOOMSG(ZONE_INIT, (TEXT("%s read_address_base_from_reg:active_key:%x.\r\n"),
      DRVR_NAME, active_key));
   
   val_size = sizeof(address_base);
   ret_val =
   RegQueryValueEx(active_key, (LPCWSTR)TEXT("address_base"), 0,
      NULL, (PUCHAR)(&address_base), &val_size);
   
   if ( ERROR_SUCCESS != ret_val )
   {
      FOOMSG(ZONE_ERROR|ZONE_INIT,
         (TEXT("%s Error, can't open %s\\address_base, Error 0x%X\r\n"),
         DRVR_NAME, (LPCTSTR)active_key, ret_val));
      return (0);
   }
   
   return (address_base);
   
} /* end read_scratch_base_from_reg() */


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Returns string containing the name of the ISR's DLL.
 *
 * \b Purpose:
 *
 *	If the user has specified an installable interrupt service routine (ISR)
 *	to handle this driver's interrupts, this function will return a pointer
 *	to a string which contains the name of the dynamic link library (DLL)
 *	where the ISR is implemented.
 *
 *	\post	NOTE, the caller is responsible for freeing the string allocated
 *			by this function.
 *
 * \param	active_key
 *			Open registry key containing the device's configuration
 *			information.
 *
 * \return	Pointer to a valid string upon success. (WCHAR *)(NULL) upon
 *			failure.
 */
/*-------------------------------------------------------------------------*/
WCHAR *
read_isr_dll_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   WCHAR *isr_dll;
   
   /* Make sure that someone didn't pass us a bogus key. */
   if ( INVALID_HANDLE_VALUE == active_key )
      return (WCHAR *)(NULL);
   
   /* Now look to see if the user specified an IsrDLL to use. */
   val_size = 0;
   ret_val =
   RegQueryValueEx(active_key, (LPCWSTR)TEXT("IsrDll"), 0,
      NULL, (PUCHAR)(NULL), &val_size);
   
   if (ERROR_SUCCESS != ret_val) {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\IsrDll. No IsrDll specified.\r\n"),
         DRVR_NAME, (LPCTSTR)active_key));
      return (WCHAR *)(NULL);
   }
   
   /* Allocate enough space to store the string. */
   isr_dll = LocalAlloc(LPTR, val_size + 4);
   if (!isr_dll) {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
               (TEXT("%s Error, can't malloc() _1.\r\n"),
               DRVR_NAME, (LPCTSTR)active_key));
      return (WCHAR *)(NULL);
   }
   /* Now copy the string from the registry. */
   RegQueryValueEx(active_key, (LPCWSTR)TEXT("IsrDll"), 0,
      NULL, (PUCHAR)(isr_dll), &val_size);
   
   return (isr_dll);
   
} /* end read_isr_dll_from_reg() */


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Returns string containing the name of the ISR's handler function.
 *
 * \b Purpose:
 *
 *	If the user has specified an installable interrupt service routine (ISR)
 *	to handle this driver's interrupts, this function will return a pointer
 *	to a string which contains the name of the interrupt handler function.
 *
 *	\post	NOTE, the caller is responsible for freeing the string allocated
 *			by this function.
 *
 * \param	active_key
 *			Open registry key containing the device's configuration
 *			information.
 *
 * \return	Pointer to a valid string upon success. (WCHAR *)(NULL) upon
 *			failure.
 */
/*-------------------------------------------------------------------------*/
WCHAR *
read_isr_handler_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   WCHAR *isr_handler;
   
   /* Make sure that someone didn't pass us a bogus key. */
   if ( INVALID_HANDLE_VALUE == active_key )
      return (WCHAR *)(NULL);
   
   /* Now look to see if the user specified an IsrDLL to use. */
   val_size = 0;
   ret_val =
   RegQueryValueEx(active_key, (LPCWSTR)TEXT("IsrHandler"), 0,
      NULL, (PUCHAR)(NULL), &val_size);
   
   if ( ERROR_SUCCESS != ret_val )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\IsrHandler.\r\n"),
         DRVR_NAME, (LPCTSTR)active_key));
      return (WCHAR *)(NULL);
   }
   
   /* Allocate enough space to store the string. */
   isr_handler = LocalAlloc(LPTR, val_size + 4);
   if ( !isr_handler )
   {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
               (TEXT("%s Error, can't malloc() _3.\r\n"),
               DRVR_NAME, (LPCTSTR)active_key));
      return (WCHAR *)(NULL);
   }
   /* Now copy the string from the registry. */
   RegQueryValueEx(active_key, (LPCWSTR)TEXT("IsrHandler"), 0,
      NULL, (PUCHAR)(isr_handler), &val_size);
   
   return (isr_handler);
   
} /* end read_isr_handler_from_reg() */


/*-------------------------------------------------------------------------*/
/*!
 * \brief	Queries the registry to determine the GPIO port pin.
 *
 * \b Purpose:
 *
 *	This function looks for a DWORD value under the "GpioIntPin" key in the
 *	registry string passed to it.
 *
 * \return	GpioIntPin number specified in the registry or (-1) for failure.
 *
 */
/*-------------------------------------------------------------------------*/
DWORD
read_gpio_pin_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   DWORD gpio_pin;
   
   FOOMSG(ZONE_INIT, (TEXT("%s read_gpio_pin_from_reg:active_key:%x.\r\n"),
      DRVR_NAME, active_key));
   
   /* Read the IRQ number that our caller would like to use. */
   val_size = sizeof(gpio_pin);
   ret_val =
   RegQueryValueEx(active_key,TEXT("GpioIntPin"), 0,
      NULL, (PUCHAR)(&gpio_pin), &val_size);
   
   if (ERROR_SUCCESS != ret_val) {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\GpioIntPin. No GpioIntPin specified.\r\n"),
         DRVR_NAME, (LPCTSTR)active_key));
      return (DWORD)(-1);
   }
   
   return (gpio_pin);
   
} /* end read_gpio_pin_from_reg() */

/*-------------------------------------------------------------------------*/
/*!
 * \brief   Queries the registry to determine the IST priority.
 *
 * \b Purpose:
 *
 *	This function looks for a DWORD value under the "Priority256" key in the
 *	registry string passed to it.
 *
 * \return	Priority256 number specified in the registry or (-1) for failure.
 *
 */
/*-------------------------------------------------------------------------*/
DWORD
read_priority_from_reg(HKEY active_key)
{
   ULONG ret_val, val_size;
   DWORD dwPriority;
   
   FOOMSG(ZONE_INIT, (TEXT("%s read_priority_from_reg:active_key:%x.\r\n"),
      DRVR_NAME, active_key));
   
   /* Read the IRQ number that our caller would like to use. */
   val_size = sizeof(dwPriority);
   ret_val =
      RegQueryValueEx(active_key, TEXT("Priority256"), 0,
         NULL, (PUCHAR)(&dwPriority), &val_size);
   
   if (ERROR_SUCCESS != ret_val) {
      FOOMSG(ZONE_ERROR|ZONE_WARN,
         (TEXT("%s Error, can't open %s\\Priority256. No Priority256 specified.\r\n"),
         DRVR_NAME, (LPCTSTR)active_key));
      return (DWORD)(-1);
   }
   
   return (dwPriority);
   
} /* end read_priority_from_reg() */

