/*-------------------------------------------------------------------------*/
/*!
 * \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 99 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() */


