// HPDI32 ......
// $URL:$
// $Rev:$
// $Date:$

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "hpdi32_api.h"
#include "main.h"
#include "util_label.h"



/* typedefs	*****************************************************************/

typedef struct
{
	U32	count;
	U32	get;
} fifo_t;



/*****************************************************************************
*
*	Function:	_fifo_fill_level_test
*
*	Purpose:
*
*		Perform a FIFO fill level test.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		which	Which levels to work with.
*
*		defalt	The default fill level.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_fill_level_test(void* handle, U32 which, U32 defalt)
{
	struct
	{
		unsigned long	set;
		unsigned long	get;
	} list[7];

	U32						bsr;
	int						errs;
	unsigned long			get;
	int						i;
	int						j;
	U32						mask;
	const char*				msg		= NULL;
	char					name[64];
	const char*				prefix;
	fifo_info_t				rx_info;
	U32						rx_size;
	U32						size;
	U32						stat;
	U32						status	= GSC_SUCCESS;
	fifo_info_t				tx_info;
	U32						tx_size;

	list[0].set	= GSC_NO_CHANGE;
	list[0].get	= defalt;
	list[1].set	= 32;
	list[1].get	= 32;
	list[2].set	= GSC_DEFAULT;
	list[2].get	= defalt;
	list[3].set	= 64;
	list[3].get	= 64;
	list[4].set	= HPDI32_FIFO_ALMOST_EMPTY_DEFAULT;
	list[4].get	= HPDI32_FIFO_ALMOST_EMPTY_DEFAULT;
	list[5].set	= HPDI32_FIFO_ALMOST_FULL_DEFAULT;
	list[5].get	= HPDI32_FIFO_ALMOST_FULL_DEFAULT;
	list[6].set	= HPDI32_FIFO_ALMOST_LEVEL_MAX;
	list[6].get	= HPDI32_FIFO_ALMOST_LEVEL_MAX;

	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if (which & HPDI32_WHICH_TX)
	{
		mask	= HPDI32_BSR_TX_NOT_EMPTY;
		prefix	= "Tx";
		size	= tx_size;

		if (tx_info == FIFO_NONE)
			msg	= "no Tx FIFOs installed";
		else if ((which & HPDI32_WHICH_AE) && (tx_info != FIFO_SIZE_KNOWN))
			msg	= "Tx FIFO size is unknown";
	}
	else
	{
		mask	= HPDI32_BSR_RX_NOT_EMPTY;
		prefix	= "Rx";
		size	= rx_size;

		if (tx_info == FIFO_NONE)
			msg	= "no Tx FIFOs installed";
		else if ((which & HPDI32_WHICH_AE) && (rx_info != FIFO_SIZE_KNOWN))
			msg	= "Rx FIFO size is unknown";
	}

	if (size < HPDI32_FIFO_ALMOST_LEVEL_MAX)
	{
		i			= ARRAY_ELEMENTS(list) - 1;
		list[i].get	= size;
		list[i].set	= size;
	}

	sprintf(name,
			"%s FIFO Almost %s",
			prefix,
			(which & HPDI32_WHICH_AF) ? "Full" : "Empty");
	label_text(name);

	if (msg == NULL)
	{
		for (i = 0; i < (int) ARRAY_ELEMENTS(list); i++)
		{
			hpdi32_reset(handle);

			// Put data in the Rx FIFO.

			for (j = 0; j <= 10; j++)
			{
				stat	= hpdi32_reg_write(handle, HPDI32_FDR, 0);
				status	= (status == GSC_SUCCESS) ? stat : status;
			}

			stat	= hpdi32_reg_write(	handle,
										HPDI32_BCR,
										HPDI32_BCR_TX_ENABLED |
										HPDI32_BCR_RX_ENABLED |
										HPDI32_BCR_TX_START);
			status	= (status == GSC_SUCCESS) ? stat : status;
			usleep(2000);
			stat	= hpdi32_reg_write(handle, HPDI32_BCR, 0);
			status	= (status == GSC_SUCCESS) ? stat : status;

			// Put data in the Tx FIFO.

			for (j = 0; j <= 10; j++)
			{
				stat	= hpdi32_reg_write(handle, HPDI32_FDR, 0);
				status	= (status == GSC_SUCCESS) ? stat : status;
			}

			/* Invoke the service. */
			stat	= hpdi32_config(handle,
									HPDI32_FIFO_ALMOST_LEVEL,
									which,
									list[i].set,
									&get);
			status	= (status == GSC_SUCCESS) ? stat : status;

			/* See if things went as expected. */

			if ((status == GSC_SUCCESS) && (get != list[i].get))
				status	= GSC_FAILED;

			usleep(2000);
			stat	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);
			status	= (status == GSC_SUCCESS) ? stat : status;

			if (status != GSC_SUCCESS)
			{
			}
			else if (list[i].set == GSC_NO_CHANGE)
			{
				if ((bsr & mask) == 0)
					status	= GSC_FAILED;	// The FIFO was reset.
			}
			else if (bsr & mask)
			{
				status	= GSC_FAILED;	// The FIFO was not reset.
			}

			if (status != GSC_SUCCESS)
				break;
		}

		if (status != GSC_SUCCESS)
			printf("(index %d) ", i);
	}

	hpdi32_reset(handle);
	errs	= (status == GSC_SUCCESS) ? 0 : 1;

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_fill_level_tests
*
*	Purpose:
*
*		Perform FIFO fill level tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_fill_level_tests(void* handle)
{
	static const struct
	{
		U32	which;
		U32	defalt;
	} list[]	=
	{
		/* which								defalt								*/
		{ HPDI32_WHICH_TX | HPDI32_WHICH_AE,	HPDI32_FIFO_ALMOST_EMPTY_DEFAULT	},
		{ HPDI32_WHICH_TX | HPDI32_WHICH_AF,	HPDI32_FIFO_ALMOST_FULL_DEFAULT		},
		{ HPDI32_WHICH_RX | HPDI32_WHICH_AE,	HPDI32_FIFO_ALMOST_EMPTY_DEFAULT	},
		{ HPDI32_WHICH_RX | HPDI32_WHICH_AF,	HPDI32_FIFO_ALMOST_FULL_DEFAULT		}
	};

	int	errs	= 0;
	int	i;

	for (i = 0; i < (int) ARRAY_ELEMENTS(list); i++)
	{
		errs	+= _fifo_fill_level_test(	handle,
											list[i].which,
											list[i].defalt);
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_reset_test
*
*	Purpose:
*
*		Perform a FIFO reset test.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		which	Which FIFO to work with.
*
*		info	This is what is known of the FIFO size.
*
*		tx_info	This is what is known of the Tx FIFO size.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_reset_test(
	void*		handle,
	U32			which,
	fifo_info_t	info,
	fifo_info_t	tx_info)
{
	static const struct
	{
		unsigned long	set;
		unsigned long	get;
	} list[]	=
	{
		/* set							get							*/
		{ GSC_NO_CHANGE,				HPDI32_FIFO_RESET_NO		},
		{ GSC_DEFAULT,					HPDI32_FIFO_RESET_DEFAULT	},
		{ HPDI32_FIFO_RESET_NO,			HPDI32_FIFO_RESET_NO		},
		{ HPDI32_FIFO_RESET_YES,		HPDI32_FIFO_RESET_YES		},
		{ HPDI32_FIFO_RESET_DEFAULT,	HPDI32_FIFO_RESET_DEFAULT	}
	};

	U32				bsr;
	unsigned long	get;
	int				errs;
	int				i;
	int				j;
	U32				mask;
	char			name[64];
	U32				stat;
	U32				status	= GSC_SUCCESS;

	mask	= (which & HPDI32_WHICH_TX) ? HPDI32_BSR_TX_NOT_EMPTY : HPDI32_BSR_RX_NOT_EMPTY;
	sprintf(name, "%s FIFO Reset", (which & HPDI32_WHICH_TX) ? "Tx" : "Rx");
	label_text(name);

	if ((info != FIFO_NONE) && (tx_info != FIFO_NONE))
	{
		for (i = 0; i < (int) ARRAY_ELEMENTS(list); i++)
		{
			hpdi32_reset(handle);

			// Put data in the Rx FIFO.

			for (j = 0; j <= 10; j++)
			{
				stat	= hpdi32_reg_write(handle, HPDI32_FDR, 0);
				status	= (status == GSC_SUCCESS) ? stat : status;
			}

			stat	= hpdi32_reg_write(	handle,
										HPDI32_BCR,
										HPDI32_BCR_TX_ENABLED |
										HPDI32_BCR_RX_ENABLED |
										HPDI32_BCR_TX_START);
			status	= (status == GSC_SUCCESS) ? stat : status;
			usleep(2000);
			stat	= hpdi32_reg_write(handle, HPDI32_BCR, 0);
			status	= (status == GSC_SUCCESS) ? stat : status;

			// Put data in the Tx FIFO.

			for (j = 0; j <= 10; j++)
			{
				stat	= hpdi32_reg_write(handle, HPDI32_FDR, 0);
				status	= (status == GSC_SUCCESS) ? stat : status;
			}

			/* Invoke the service. */
			stat	= hpdi32_config(handle,
									HPDI32_FIFO_RESET,
									which,
									list[i].set,
									&get);
			status	= (status == GSC_SUCCESS) ? stat : status;

			/* See if things went as expected. */

			if ((status == GSC_SUCCESS) && (get != list[i].get))
				status	= GSC_FAILED;

			usleep(2000);
			stat	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);
			status	= (status == GSC_SUCCESS) ? stat : status;

			if (status != GSC_SUCCESS)
			{
			}
			else if (list[i].get == HPDI32_FIFO_RESET_NO)
			{
				if ((bsr & mask) == 0)
					status	= GSC_FAILED;	// The FIFO was reset.
			}
			else if (bsr & mask)
			{
				status	= GSC_FAILED;	// The FIFO was not reset.
			}

			if (status != GSC_SUCCESS)
				break;
		}

		if (status != GSC_SUCCESS)
			printf("(index %d) ", i);
	}

	hpdi32_reset(handle);
	errs	= (status == GSC_SUCCESS) ? 0 : 1;
	errs	= ((info == FIFO_NONE) || (tx_info == FIFO_NONE)) ? 0 : errs;

	if ((which & HPDI32_WHICH_RX) && (info == FIFO_NONE))
		printf("SKIPPED (no Rx FIFOs)\n");
	else if (tx_info == FIFO_NONE)
		printf("SKIPPED (no Tx FIFOs)\n");
	else if (errs)
		printf("FAIL <---\n");
	else
		printf("PASS\n");

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_reset_tests
*
*	Purpose:
*
*		Perform FIFO reset tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_reset_tests(void* handle)
{
	int			errs	= 0;
	fifo_info_t	rx_info;
	U32			size;
	fifo_info_t	tx_info;

	fifo_info_tx(&tx_info, &size);
	fifo_info_rx(&rx_info, &size);
	errs	+= _fifo_reset_test(handle, HPDI32_WHICH_TX, tx_info, tx_info);
	errs	+= _fifo_reset_test(handle, HPDI32_WHICH_RX, rx_info, tx_info);
	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_size_test
*
*	Purpose:
*
*		Perform a FIFO size test.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		which	Which FIFO to work with.
*
*		info	This is what is known of the FIFO size.
*
*		size	This is the FIFO size.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_size_test(void* handle, U32 which, fifo_info_t info, U32 size)
{
	int				errs;
	char*			factor;
	unsigned long	get;
	char			name[64];
	U32				reg;
	U32				stat;
	U32				status	= GSC_SUCCESS;

	reg	= (which & HPDI32_WHICH_TX) ? HPDI32_TFSR : HPDI32_RFSR;
	sprintf(name, "%s FIFO Size", (which & HPDI32_WHICH_TX) ? "Tx" : "Rx");
	label_text(name);

	if (info == FIFO_SIZE_KNOWN)
	{
		printf(".");
		hpdi32_reset(handle);

		/* Invoke the service. */
		stat	= hpdi32_config(handle,
								HPDI32_FIFO_SIZE,
								which,
								GSC_NO_CHANGE,
								&get);
		status	= (status == GSC_SUCCESS) ? stat : status;

		/* See if things went as expected. */
		stat	= hpdi32_reg_read(handle, reg, &size);
		status	= (status == GSC_SUCCESS) ? stat : status;

		if ((status == GSC_SUCCESS) && (get != size))
			status	= GSC_FAILED;
	}

	hpdi32_reset(handle);
	errs	= (info == FIFO_NONE) ? 0 : (status == GSC_SUCCESS) ? 0 : 1;

	if (info == FIFO_NONE)
	{
		if (which & HPDI32_WHICH_TX)
			printf("SKIPPED (no Tx FIFOs)\n");
		else
			printf("SKIPPED (no Rx FIFOs)\n");
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		factor	= "";

		if ((size % 1024) == 0)
		{
			factor	= "K";
			size	/= 1024;
		}

		if ((size % 1024) == 0)
		{
			factor	= "M";
			size	/= 1024;
		}

		printf("PASS   (%ld%s samples)\n", (long) size, factor);
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_size_tests
*
*	Purpose:
*
*		Perform FIFO size tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_size_tests(void* handle)
{
	int			errs	= 0;
	fifo_info_t	info;
	U32			size;

	fifo_info_tx(&info, &size);
	errs	+= _fifo_size_test(handle, HPDI32_WHICH_TX, info, size);
	fifo_info_rx(&info, &size);
	errs	+= _fifo_size_test(handle, HPDI32_WHICH_RX, info, size);
	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_status_test
*
*	Purpose:
*
*		Perform a FIFO status test.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		which	Which FIFO are we to test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_status_test(void* handle, U32 which)
{
	struct
	{
		U32				count;
		unsigned long	get;
		U32				mask;
		U32				value;
	} list[11];

	U32				ae;		// Almost Empty level
	U32				af;		// Almost Full level
	U32				almost;
	U32				bsr;
	int				errs;
	unsigned long	get;
	int				i;
	const char*		msg;
	char			name[64];
	const char*		prefix;
	U32				reg;
	fifo_info_t		rx_info;
	U32				rx_size;
	U32				size;
	U32				stat;
	U32				status	= GSC_SUCCESS;
	fifo_info_t		tx_info;
	U32				tx_size;

	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_rx(&rx_info, &rx_size);

	if (tx_info == FIFO_NONE)
		msg		= "no Tx FIFOs installed";
	else if (tx_info == FIFO_SIZE_UNKNOWN)
		msg		= "Tx FIFO size is unknown";
	else
		msg	= NULL;

	if (which & HPDI32_WHICH_TX)
	{
		prefix	= "Tx";
	}
	else
	{
		prefix	= "Rx";

		if (msg)
			;
		else if (rx_info == FIFO_NONE)
			msg	= "no Rx FIFOs installed";
		else if (rx_info == FIFO_SIZE_UNKNOWN)
			msg	= "Rx FIFO size is unknown";
		else
			msg	= NULL;
	}

	sprintf(name, "%s FIFO Status", prefix);
	label_text(name);

	if (msg == NULL)
	{
		hpdi32_reset(handle);
		reg		= (which & HPDI32_WHICH_TX) ? HPDI32_TFSR : HPDI32_RFSR;
		stat	= hpdi32_reg_read(handle, reg, &size);
		status	= (status == GSC_SUCCESS) ? stat : status;
		reg		= (which & HPDI32_WHICH_TX) ? HPDI32_TAR : HPDI32_RAR;
		stat	= hpdi32_reg_read(handle, reg, &almost);
		status	= (status == GSC_SUCCESS) ? stat : status;
		ae		= HPDI32_DECODE_EMPTY(almost);
		af		= HPDI32_DECODE_FULL(almost);

		// The EMPTY flag should be LOW.
		list[0].count	= 0;
		list[0].get		= HPDI32_FIFO_STATUS_EMPTY;
		list[0].mask	= HPDI32_BSR_TX_NOT_EMPTY;
		list[0].value	= 0;

		// The EMPTY flag should go HI.
		list[1].count	= 1;
		list[1].get		= HPDI32_FIFO_STATUS_ALMOST_EMPTY;
		list[1].mask	= HPDI32_BSR_TX_NOT_EMPTY;
		list[1].value	= HPDI32_BSR_TX_NOT_EMPTY;

		// The ALMOST EMPTY flag should be LOW.
		list[2].count	= 0;
		list[2].get		= HPDI32_FIFO_STATUS_ALMOST_EMPTY;
		list[2].mask	= HPDI32_BSR_TX_NOT_AE;
		list[2].value	= 0;

		// The ALMOST EMPTY flag should remain LOW.
		list[3].count	= ae - 1;
		list[3].get		= HPDI32_FIFO_STATUS_ALMOST_EMPTY;
		list[3].mask	= HPDI32_BSR_TX_NOT_AE;
		list[3].value	= 0;

		// The ALMOST EMPTY flag should go HI.
		list[4].count	= 1;
		list[4].get		= HPDI32_FIFO_STATUS_MEDIAN;
		list[4].mask	= HPDI32_BSR_TX_NOT_AE;
		list[4].value	= HPDI32_BSR_TX_NOT_AE;

		// The ALMOST FULL flag should be HI.
		list[5].count	= 0;
		list[5].get		= HPDI32_FIFO_STATUS_MEDIAN;
		list[5].mask	= HPDI32_BSR_TX_NOT_AF;
		list[5].value	= HPDI32_BSR_TX_NOT_AF;

		// The ALMOST FULL flag should remain HI.
		list[6].count	= size - af - ae - 2;
		list[6].get		= HPDI32_FIFO_STATUS_MEDIAN;
		list[6].mask	= HPDI32_BSR_TX_NOT_AF;
		list[6].value	= HPDI32_BSR_TX_NOT_AF;

		// The ALMOST FULL flag should go LOW.
		list[7].count	= 1;
		list[7].get		= HPDI32_FIFO_STATUS_ALMOST_FULL;
		list[7].mask	= HPDI32_BSR_TX_NOT_AF;
		list[7].value	= 0;

		// The FULL flag should be HI.
		list[8].count	= 0;
		list[8].get		= HPDI32_FIFO_STATUS_ALMOST_FULL;
		list[8].mask	= HPDI32_BSR_TX_NOT_FULL;
		list[8].value	= HPDI32_BSR_TX_NOT_FULL;

		// The FULL flag should remain HI.
		list[9].count	= af - 1;
		list[9].get		= HPDI32_FIFO_STATUS_ALMOST_FULL;
		list[9].mask	= HPDI32_BSR_TX_NOT_FULL;
		list[9].value	= HPDI32_BSR_TX_NOT_FULL;

		// The FULL flag should go LOW.
		list[10].count	= 1;
		list[10].get	= HPDI32_FIFO_STATUS_FULL;
		list[10].mask	= HPDI32_BSR_TX_NOT_FULL;
		list[10].value	= 0;

		for (i = 0; i < (int) ARRAY_ELEMENTS(list); i++)
		{
			/* Put data in the FIFO. */

			if (which & HPDI32_WHICH_RX)
				status	= rx_write(handle, list[i].count);
			else
				status	= tx_write(handle, list[i].count);

			/* Invoke the service. */
			stat	= hpdi32_config(handle,
									HPDI32_FIFO_STATUS,
									which,
									GSC_NO_CHANGE,
									&get);
			status	= (status == GSC_SUCCESS) ? stat : status;

			/* See if things went as expected. */

			if ((status == GSC_SUCCESS) && (get != list[i].get))
				status	= GSC_FAILED;

			stat	= hpdi32_reg_read(handle, HPDI32_BSR, &bsr);
			status	= (status == GSC_SUCCESS) ? stat : status;

			if (which & HPDI32_WHICH_RX)
				bsr	>>= 4;		// Mode the Rx Status to the Tx Status position.

			bsr	&= list[i].mask;

			if ((status == GSC_SUCCESS) && (bsr != list[i].value))
				status	= GSC_FAILED;

			if (status != GSC_SUCCESS)
			{
				printf("(index %d) ", i);
				break;
			}
		}
	}

	hpdi32_reset(handle);
	errs	= (status == GSC_SUCCESS) ? 0 : 1;

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_status_tests
*
*	Purpose:
*
*		Perform FIFO status tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_status_tests(void* handle)
{
	int	errs	= 0;

	errs	+= _fifo_status_test(handle, HPDI32_WHICH_TX);
	errs	+= _fifo_status_test(handle, HPDI32_WHICH_RX);
	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_transfer_size_test
*
*	Purpose:
*
*		Perform a FIFO Transfer Size test using the given data list.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*		status	The status acquired so far for this test.
*
*		which	Which FIFO are we to test.
*
*		list	The data list to process.
*
*		size	The size of the above list.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_transfer_size_test(void*	handle,
									U32		status,
									U32		which,
									fifo_t*	list,
									size_t	size)
{
	int				errs;
	unsigned long	get;
	int				i;
	const char*		msg;
	char			name[64];
	fifo_info_t		rx_info;
	U32				rx_size;
	U32				stat;
	fifo_info_t		tx_info;
	U32				tx_size;

	sprintf(name, "%s FIFO Transfer Size", (which & HPDI32_WHICH_TX) ? "Tx" : "Rx");
	label_text(name);

	hpdi32_reset(handle);
	fifo_info_tx(&tx_info, &tx_size);
	fifo_info_tx(&rx_info, &rx_size);

	if (tx_info == FIFO_NONE)
		msg		= "no Tx FIFOs installed";
	else if (tx_info == FIFO_SIZE_UNKNOWN)
		msg		= "Tx FIFO size is unknown";
	else if ((which & HPDI32_WHICH_RX) && (tx_info == FIFO_NONE))
		msg		= "no Rx FIFOs installed";
	else if ((which & HPDI32_WHICH_RX) && (tx_info == FIFO_SIZE_UNKNOWN))
		msg		= "Rx FIFO size is unknown";
	else
		msg	= NULL;

	if (msg == NULL)
	{
		hpdi32_reset(handle);

		for (i = 0; i < (int) size; i++)
		{
			/* Put data in the FIFO. */
			if (which & HPDI32_WHICH_RX)
				stat	= rx_write(handle, list[i].count);
			else
				stat	= tx_write(handle, list[i].count);

			status	= (status == GSC_SUCCESS) ? stat : status;

			/* Invoke the service. */
			stat	= hpdi32_config(handle,
									HPDI32_FIFO_TRANSFER_SIZE,
									which,
									GSC_NO_CHANGE,
									&get);
			status	= (status == GSC_SUCCESS) ? stat : status;

			/* See if things went as expected. */

			if ((status == GSC_SUCCESS) && (get != list[i].get))
			{
				status	= GSC_FAILED;
				printf(	"(%d. %ld -> %ld) ",
						i,
						(long) list[i].get,
						(long) get);
				break;
			}

			if (status != GSC_SUCCESS)
				break;
		}
	}

	hpdi32_reset(handle);
	errs	= (status == GSC_SUCCESS) ? 0 : 1;

	if (msg)
	{
		errs	= 0;
		printf("SKIPPED (%s)\n", msg);
	}
	else if (errs)
	{
		printf("FAIL <---\n");
	}
	else
	{
		printf("PASS\n");
	}

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_transfer_size_tx_test
*
*	Purpose:
*
*		Perform a FIFO Transfer Size test for the Tx FIFO.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_transfer_size_tx_test(void* handle)
{
	U32			ae;		// Almost Empty level
	U32			af;		// Almost Full level
	U32			almost;
	int			errs;
	fifo_info_t	info;
	fifo_t		list[8];
	U32			size;
	U32			stat;
	U32			status	= GSC_SUCCESS;

	hpdi32_reset(handle);
	fifo_info_tx(&info, &size);
	stat	= hpdi32_reg_read(handle, HPDI32_TAR, &almost);
	status	= (status == GSC_SUCCESS) ? stat : status;
	ae		= HPDI32_DECODE_EMPTY(almost);
	af		= HPDI32_DECODE_FULL(almost);

	// The FIFO is Empty.
	// space = FIFO size
	list[0].count	= 0;
	list[0].get		= size;

	// The FIFO is Almost Empty.
	// space = FIFO size - Almost Empty
	list[1].count	= 1;
	list[1].get		= size - ae;

	// The FIFO is still Almost Empty.
	// space = FIFO size - Almost Empty
	list[2].count	= ae - 1;
	list[2].get		= size - ae;

	// The FIFO is between Almost Empty and Almost Full.
	// space = at least Almost Full
	list[3].count	= 1;
	list[3].get		= af;

	// The FIFO is still between Almost Empty and Almost Full.
	// space = at least Almost Full
	list[4].count	= size - ae - af - 2;
	list[4].get		= af;

	// The FIFO is Almost Full.
	// space = 1
	list[5].count	= 1;
	list[5].get		= 1;

	// The FIFO is still Almost Full.
	// space = 1
	list[6].count	= af - 1;
	list[6].get		= 1;

	// The FIFO is Full.
	// space = 0
	list[7].count	= 1;
	list[7].get		= 0;

	errs	= _fifo_transfer_size_test(	handle,
										status,
										HPDI32_WHICH_TX,
										list,
										ARRAY_ELEMENTS(list));

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_transfer_size_rx_test
*
*	Purpose:
*
*		Perform a FIFO Transfer Size test for the Rx FIFO.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_transfer_size_rx_test(void* handle)
{
	U32			ae;		// Almost Empty level
	U32			af;		// Almost Full level
	U32			almost;
	int			errs;
	fifo_info_t	info;
	fifo_t		list[8];
	U32			size;
	U32			stat;
	U32			status	= GSC_SUCCESS;

	hpdi32_reset(handle);
	fifo_info_rx(&info, &size);
	stat	= hpdi32_reg_read(handle, HPDI32_RAR, &almost);
	status	= (status == GSC_SUCCESS) ? stat : status;
	ae		= HPDI32_DECODE_EMPTY(almost);
	af		= HPDI32_DECODE_FULL(almost);

	// The FIFO is Empty.
	// data = 0
	list[0].count	= 0;
	list[0].get		= 0;

	// The FIFO is Almost Empty.
	// data = 1
	list[1].count	= 1;
	list[1].get		= 1;

	// The FIFO is still Almost Empty.
	// data = 1
	list[2].count	= ae - 1;
	list[2].get		= 1;

	// The FIFO is between Almost Empty and Almost Full.
	// data = at least Almost Empty
	list[3].count	= 1;
	list[3].get		= ae;

	// The FIFO is still between Almost Empty and Almost Full.
	// data = at least Almost Empty
	list[4].count	= size - ae - af - 2;
	list[4].get		= ae;

	// The FIFO is Almost Full.
	// data = FIFO size - Almost Empty
	list[5].count	= 1;
	list[5].get		= size - af;

	// The FIFO is still Almost Full.
	// data = FIFO size - Almost Empty
	list[6].count	= af - 1;
	list[6].get		= size - af;

	// The FIFO is Full.
	// data = FIFO size
	list[7].count	= 1;
	list[7].get		= size;

	errs	= _fifo_transfer_size_test(	handle,
										status,
										HPDI32_WHICH_RX,
										list,
										ARRAY_ELEMENTS(list));

	return(errs);
}



/*****************************************************************************
*
*	Function:	_fifo_transfer_size_tests
*
*	Purpose:
*
*		Perform FIFO Transfer Size tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

static int _fifo_transfer_size_tests(void* handle)
{
	int	errs;

	errs	= _fifo_transfer_size_tx_test(handle);
	errs	= _fifo_transfer_size_rx_test(handle);
	return(errs);
}



/*****************************************************************************
*
*	Function:	fifo_config_tests
*
*	Purpose:
*
*		Perform FIFO configuration tests.
*
*	Arguments:
*
*		handle	The handle used to access the device under test.
*
*	Returned:
*
*		0		All went well.
*		> 0		The number of errors seen.
*
*****************************************************************************/

int fifo_config_tests(void* handle)
{
	int	errs	= 0;

	label_text("FIFO Configuration");
	printf("\n");
	label_level_inc();

	errs	+= _fifo_size_tests(handle);
	errs	+= _fifo_reset_tests(handle);
	errs	+= _fifo_fill_level_tests(handle);
	errs	+= _fifo_status_tests(handle);
	errs	+= _fifo_transfer_size_tests(handle);

	label_level_dec();
	return(errs);
}



/*****************************************************************************
*
*	Function:	fifo_info_rx
*
*	Purpose:
*
*		Retrieve what we know of the Rx FIFO.
*
*	Arguments:
*
*		info	Record here what is know of the size of the Rx FIFO.
*
*		size	Record the size of the Rx FIFO here.
*
*	Returned:
*
*		None.
*
*****************************************************************************/

void fifo_info_rx(fifo_info_t* info, U32* size)
{
	size[0]	= rx_size;

	if (rx_size < 0)
		info[0]	= FIFO_SIZE_UNKNOWN;
	if (rx_size > 0)
		info[0]	= FIFO_SIZE_KNOWN;
	else
		info[0]	= FIFO_NONE;
}



/*****************************************************************************
*
*	Function:	fifo_info_tx
*
*	Purpose:
*
*		Retrieve what we know of the Tx FIFO.
*
*	Arguments:
*
*		info	Record here what is know of the size of the Tx FIFO.
*
*		size	Record the size of the Tx FIFO here.
*
*	Returned:
*
*		None.
*
*****************************************************************************/

void fifo_info_tx(fifo_info_t* info, U32* size)
{
	size[0]	= tx_size;

	if (tx_size < 0)
		info[0]	= FIFO_SIZE_UNKNOWN;
	if (tx_size > 0)
		info[0]	= FIFO_SIZE_KNOWN;
	else
		info[0]	= FIFO_NONE;
}


