/******************************************************************************
 Hardware Programming Interface (HPI) Utility functions.

Copyright (C) 1997-2017 AudioScience, Inc. All rights reserved.

This software is provided 'as-is', without any express or implied warranty.
In no event will AudioScience Inc. be held liable for any damages arising
from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This copyright notice and list of conditions may not be altered or removed
   from any source distribution.

AudioScience, Inc. <support@audioscience.com>

( This license is GPL compatible see http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses )

*******************************************************************************/

#include "hpi_internal.h"
#include "hpimsginit.h"

// The actual message size for each object type
static uint16_t aMsgSize[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT;
// The actual response size for each object type
static uint16_t aResSize[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT;
// Flag to enable alternate message type for SSX2 bypass.
#ifdef HPI_OS_LINUX_KERNEL
static uint16_t gwSSX2Bypass;
#else
static uint16_t gwSSX2Bypass = 0;
#endif

#ifndef HPI_OS_LINUX_KERNEL
/** \internal
  * Used by ASIO driver to disable SSX2 for a single process
  * \param phSubSys Vestigial subsys handle (unused), may be set to NULL
  * \param wBypass New bypass setting 0 = off, nonzero = on
  * \return Previous bypass setting.
  */
HPI_API (uint16_t) HPI_SubSysSsx2Bypass(
	const hpi_hsubsys_t *phSubSys,
	uint16_t wBypass
)
{
	uint16_t oldValue = gwSSX2Bypass;
	(void)phSubSys;

	gwSSX2Bypass = wBypass;

	return oldValue;
}
#endif

/** \internal
  * initialize the HPI message structure
  */
static void HPI_InitMessage(
	struct hpi_message *phm,
	uint16_t wObject,
	uint16_t wFunction
)
{
	uint16_t size;

	if ((wObject > 0) && (wObject <= HPI_OBJ_MAXINDEX))
		size = aMsgSize[wObject];
	else
		size = sizeof(*phm);

	memset(phm, 0, size);
	phm->wSize = size;

	if (gwSSX2Bypass)
		phm->wType = HPI_TYPE_SSX2BYPASS_MESSAGE;
	else
		phm->wType = HPI_TYPE_REQUEST;
	phm->wObject = wObject;
	phm->wFunction = wFunction;
	phm->version = 0;
	phm->wAdapterIndex = HPI_ADAPTER_INDEX_INVALID;
	// Expect actual adapter index to be set by caller
}

/** \internal
  * initialize the HPI response structure
  */
void HPI_InitResponse(
	struct hpi_response *phr,
	uint16_t wObject,
	uint16_t wFunction,
	uint16_t wError
)
{
	uint16_t size;

	if ((wObject > 0) && (wObject <= HPI_OBJ_MAXINDEX))
		size = aResSize[wObject];
	else
		size = sizeof(*phr);

	memset(phr, 0, sizeof(*phr));
	phr->wSize = size;
	phr->wType = HPI_TYPE_RESPONSE;
	phr->wObject = wObject;
	phr->wFunction = wFunction;
	phr->wError = wError;
	phr->wSpecificError = 0;
	phr->version = 0;
}

void HPI_InitMessageResponse(
	struct hpi_message *phm,
	struct hpi_response *phr,
	uint16_t wObject,
	uint16_t wFunction)
{
	HPI_InitMessage(phm, wObject, wFunction);
	/* default error return if the response is
	   not filled in by the callee */
	HPI_InitResponse(phr, wObject, wFunction,
	                 HPI_ERROR_PROCESSING_MESSAGE);
}

static void HPI_InitMessageV1(
	struct hpi_message_header *phm,
	uint16_t wSize,
	uint16_t wObject,
	uint16_t wFunction
)
{
	memset(phm, 0, wSize);
	if ((wObject > 0) && (wObject <= HPI_OBJ_MAXINDEX)) {
		phm->wSize = wSize;
		phm->wType = HPI_TYPE_REQUEST;
		phm->wObject = wObject;
		phm->wFunction = wFunction;
		phm->version = 1;
		// Expect adapter index to be set by caller
	}
}

void HPI_InitResponseV1(
	struct hpi_response_header *phr,
	uint16_t wSize,
	uint16_t wObject,
	uint16_t wFunction
)
{
	(void)wObject;
	(void)wFunction;
	memset(phr, 0, wSize);
	phr->wSize = wSize;
	phr->version = 1;
	phr->wType = HPI_TYPE_RESPONSE;
	phr->wError = HPI_ERROR_PROCESSING_MESSAGE;
}

void HPI_InitMessageResponseV1(
	struct hpi_message_header *phm,
	uint16_t wMsgSize,
	struct hpi_response_header *phr,
	uint16_t wResSize,
	uint16_t wObject,
	uint16_t wFunction
)
{
	HPI_InitMessageV1(phm, wMsgSize, wObject, wFunction);
	HPI_InitResponseV1(phr, wResSize, wObject, wFunction);
}
