/*---------------------------------------------------------------------------*\

    FILE....: HIP.CPP
    TYPE....: C+ Functions
    AUTHOR..: David Rowe
    DATE....: 19/11/97

    VPB access functions that implement the PC side of the Host Interface 
    Port (HIP) - the interface between the PC and DSP.


         Voicetronix Voice Processing Board (VPB) Software
         Copyright (C) 1999-2006 Voicetronix www.voicetronix.com.au

         This library is free software; you can redistribute it and/or
         modify it under the terms of the GNU Lesser General Public
         License as published by the Free Software Foundation; either
         version 2.1 of the License, or (at your option) any later version.

         This library is distributed in the hope that it will be useful,
         but WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
         MA  02110-1301  USA

\*---------------------------------------------------------------------------*/

#include <assert.h>
#include <stdio.h>
#include <memory.h>

#include "hip.h"
#include "generic.h"
#include "mess.h"
#include "vpbapi.h"   // for VpbException
#include "vpbreg.h"   // for DD_PCI


/* general */

#define	SPAN		4	/* number of I/O ports used 	*/
#define	NO_VPB		0xffff	/* indicates no valid VPB	*/

/* HIP registers */

#define	DATA		0x0	/* offset of data register	*/
#define	CNTRL		0x1	/* offset of control register	*/
#define	ADDRLO		0x2	/* low byte of address register	*/
#define	ADDRHI		0x3	/* hi byte of address register	*/

/* Control register bits */

#define	RESET		0x1	/* assert to place DSP in reset	*/
#define	CNTEN		0x2	/* assert to enable addr cntr	*/
#define UP		0x4     /* ==1 for up count, else down	*/


// pure virtual base class implementation

class baseHipData {
public:
	baseHipData() {}
	virtual ~baseHipData() {}
	virtual void InitVpb(unsigned short base) = 0;
	virtual void DspReset(unsigned short board) = 0;
	virtual void DspRun(unsigned short board) = 0;
	virtual void WriteDspSram(unsigned short board, unsigned short addr,
				  unsigned short length, uint16_t *buf) = 0;
	virtual void ReadDspSram(unsigned short board, unsigned short addr,
				 unsigned short length, uint16_t *buf) = 0;
#ifndef __FreeBSD__
	virtual void WriteIic(unsigned short board, unsigned short addr,
			      unsigned short length, uint16_t *buf) = 0;
	virtual void ReadIic(unsigned short board, unsigned short addr,
			     unsigned short length, uint16_t *buf) = 0;
#endif
	virtual void EeRead(unsigned short board, unsigned short addr,
			    unsigned short length, uint16_t *buf) = 0;
	virtual void *GethndFile() = 0;
	virtual int GetDeviceDriverModel() = 0;
};

// HIP implementation for V4PCI

class HipDataPCI : public baseHipData {

	int     hndFile;
	int	DeviceDriverModel;
public:
	HipDataPCI(int DeviceDriverModel);
	~HipDataPCI();
	void InitVpb(unsigned short base);
	void DspReset(unsigned short board);
	void DspRun(unsigned short board);
	void WriteDspSram(unsigned short board, unsigned short addr,
			  unsigned short length, uint16_t *buf);
	void ReadDspSram(unsigned short board, unsigned short addr,
			 unsigned short length, uint16_t *buf);
	void WriteIic(unsigned short board, unsigned short addr,
		      unsigned short length, uint16_t *buf);
	void ReadIic(unsigned short board, unsigned short addr,
		     unsigned short length, uint16_t *buf);
	void EeRead(unsigned short board, unsigned short addr,
		    unsigned short length, uint16_t *buf);
	void *GethndFile() {return (void*)(intptr_t)hndFile;}
	int  GetDeviceDriverModel() { return DeviceDriverModel; }
};

// used to make access to DSP thread safe

static GENERIC_CRITICAL_SECTION	HipSect;


/*-------------------------------------------------------------------------*\

    FUNCTION.: Hip::Hip
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Initialises Hip states and lower level device driver software.

\*-------------------------------------------------------------------------*/

Hip::Hip(int DeviceDriverModel)
{
	if( DeviceDriverModel != DD_PCI )
		throw VpbException("Hip: Only for V4PCI cards");
	d = new HipDataPCI(DeviceDriverModel);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: Hip::~Hip()
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Closes down the HIP software and lower level drivers.

\*-------------------------------------------------------------------------*/

Hip::~Hip()
{
	delete d;
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: Hip:InitVpb
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Inits a specific VPB card. Must be called before any operations are 
    performed on the VPB.

\*-------------------------------------------------------------------------*/

void Hip::InitVpb(unsigned short base)
//      USHORT base;	base address of card
{
	d->InitVpb(base);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: Hip::DspReset
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Asserts the reset line of the DSP, freezing code execution on the DSP.

\*-------------------------------------------------------------------------*/

void Hip::DspReset(unsigned short board)
//      USHORT board;	VPB board number
{
	d->DspReset(board);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: Hip::DspRun
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    De-asserts the reset line of the DSP, starting code execution on the DSP.

\*-------------------------------------------------------------------------*/

void Hip::DspRun(unsigned short board)
//      USHORT board;	VPB board number
{
	d->DspRun(board);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: Hip::WriteDspSram
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Writes a block of 16bit words to the DSPs SRAM.  The length and address
    values are both specified in words (not bytes).

\*-------------------------------------------------------------------------*/

void Hip::WriteDspSram(unsigned short board, unsigned short addr,
		       unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	d->WriteDspSram(board, addr, length, buf);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: Hip::ReadDspSram
    AUTHOR...: David Rowe
    DATE.....: 19/11/97

    Reads a block of 16bit words from the DSPs SRAM.  The length and address
    values are both specified in words (not bytes).

\*-------------------------------------------------------------------------*/

void Hip::ReadDspSram(unsigned short board, unsigned short addr,
		      unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	d->ReadDspSram(board, addr, length, buf);
}

#ifndef __FreeBSD__
/*-------------------------------------------------------------------------*\
	
    FUNCTION.: Hip::WriteIic
    AUTHOR...: Peter Wintulich
    DATE.....: 


\*-------------------------------------------------------------------------*/

void Hip::WriteIic(unsigned short board, unsigned short addr,
		   unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	Upper byte is device address,
//			lower byte is start of block in IIC device.
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	d->WriteIic(board, addr, length, buf);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: Hip::ReadIic
    AUTHOR...: Peter Wintulich
    DATE.....: 


\*-------------------------------------------------------------------------*/

void Hip::ReadIic(unsigned short board, unsigned short addr,
		  unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	Upper byte is device address,
//		      	lower byte is start of block in IIC device.	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	d->ReadIic(board, addr, length, buf);
}

#endif

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: Hip::EeRead
    AUTHOR...: Peter Wintulich
    DATE.....: 


\*-------------------------------------------------------------------------*/

void Hip::EeRead(unsigned short board, unsigned short addr,
		 unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in EeProm	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
  	d->EeRead(board, addr, length, buf);
}

// helper functions

void *Hip::GethndFile() {return d->GethndFile();}
int  Hip::GetDeviceDriverModel() { return d->GetDeviceDriverModel(); }



/*-------------------------------------------------------------------------*\

    FUNCTION.: HipDataPCI::HipDataPCI
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Initialises Hip states and lower level device driver software.

\*-------------------------------------------------------------------------*/

HipDataPCI::HipDataPCI(int Ddm)
{
	DeviceDriverModel = Ddm;

	// check this operating system supported

	int os = GenericGetOS();
	if (os == -1)
		throw VpbException("HipDataPCI: can't get OS version");

	// initialise appropriate port class for this OS

	switch(os) {
		case GET_OS_LINUX:
		break;
		default:
			throw VpbException("HipDataPCI: OS not supported");
	}

	// Open device driver

	hndFile = Generic_open();

	if (hndFile == -1)        // Was the device opened?
		throw VpbException("HipDataPCI: can't open /dev/vpb0");

	// Tell DD to open hip module
	GenericInitializeCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: HipDataPCI::~HipDataPCI()
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Closes down the HIP software and lower level drivers.

\*-------------------------------------------------------------------------*/

HipDataPCI::~HipDataPCI()
{
	DspReset(0);
	Generic_close(hndFile);
	GenericDeleteCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: HipDataPCI:InitVpb
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Inits a specific VPB card. Must be called before any operations are 
    performed on the VPB.

\*-------------------------------------------------------------------------*/

void HipDataPCI::InitVpb(unsigned short base)
//      USHORT base;	base address of card
{
	(void)base;
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: HipDataPCI::DspReset
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Asserts the reset line of the DSP, freezing code execution on the DSP.

\*-------------------------------------------------------------------------*/

void HipDataPCI::DspReset(unsigned short board)
//  USHORT board;	VPB board number
{
	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_dsp_reset(hndFile, board);
	if (ret == -1)
		assert(0); // HIP_DSP_RESET_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\

    FUNCTION.: HipDataPCI::DspRun
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    De-asserts the reset line of the DSP, starting code execution on the DSP.

\*-------------------------------------------------------------------------*/

void HipDataPCI::DspRun(unsigned short board)
//      USHORT board;	VPB board number
{
	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_dsp_run(hndFile, board);
	if (ret == -1)
		assert(0); // HIP_DSP_RUN_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: HipDataPCI::WriteDspSram
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Writes a block of 16bit words to the DSPs SRAM.  The length and address
    values are both specified in words (not bytes).

\*-------------------------------------------------------------------------*/

void HipDataPCI::WriteDspSram(unsigned short board, unsigned short addr,
			      unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	// validate arguments

//	assert(addr < MAX_LENGTH);
//	assert(length < MAX_LENGTH);
	assert(buf != NULL);

	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_block_write(hndFile, board, addr, length, buf);
	if (ret == -1)
		assert(0); // HIP_WRITE_DSP_SRAM_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: HipDataPCI::ReadDspSram
    AUTHOR...: David Rowe
    DATE.....: 2/10/98

    Reads a block of 16bit words from the DSPs SRAM.  The length and address
    values are both specified in words (not bytes).

\*-------------------------------------------------------------------------*/

void HipDataPCI::ReadDspSram(unsigned short board, unsigned short addr,
			     unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	// validate arguments

//	assert(addr < MAX_LENGTH);
//	assert(length < MAX_LENGTH);
	assert(buf != NULL);

	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_block_read(hndFile, board, addr, length, buf);
	if (ret == -1)
		assert(0); // HIP_READ_DSP_SRAM_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

#ifndef __FreeBSD__
/*-------------------------------------------------------------------------*\
	
    FUNCTION.: HipDataPCI::WriteIic
    AUTHOR...: 
    DATE.....: 

    Writes a block of 16bit 

\*-------------------------------------------------------------------------*/

void HipDataPCI::WriteIic(unsigned short board, unsigned short addr,
			  unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	// validate arguments

//	assert(addr < MAX_LENGTH);
//	assert(length < MAX_LENGTH);
	assert(buf != NULL);

	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_block_iicwrite(hndFile, board, addr, length, buf);
	if (ret == -1)
		assert(0); // HIP_WRITE_I2C_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: HipDataPCI::ReadIic
    AUTHOR...: 
    DATE.....: 

    Reads a block of 16bit 

\*-------------------------------------------------------------------------*/

void HipDataPCI::ReadIic(unsigned short board, unsigned short addr,
			 unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start of block in DSP SRAM	
//      USHORT length;	length of block		
//      uint16_t   *buf;	ptr to block in PC	
{
	// validate arguments

//	assert(addr < MAX_LENGTH);
//	assert(length < MAX_LENGTH);
	assert(buf != NULL);

	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_block_iicread(hndFile, board, addr, length, buf);
	if (ret == -1)
		assert(0); // HIP_READ_I2C_FAIL

	GenericLeaveCriticalSection(&HipSect);
}
#endif

/*-------------------------------------------------------------------------*\
	
    FUNCTION.: HipDataPCI::EeRead
    AUTHOR...: Peter Wintulich
    DATE.....: 12/02/2003

    Reads a block of 16bit words from the PLX Config EEROM.  The length and
    address values are both specified in words (not bytes).

\*-------------------------------------------------------------------------*/

void HipDataPCI::EeRead(unsigned short board, unsigned short addr,
			unsigned short length, uint16_t *buf)
//      USHORT board;	VPB board number
//      USHORT addr;	start location of EEROM	read
//      USHORT length;	Number of words to read		
//      uint16_t   *buf;	ptr to block in PC	
{
	// validate arguments

//	assert(addr < MAX_LENGTH);
//	assert(length < MAX_LENGTH);
	assert(buf != NULL);

	int ret;

	GenericEnterCriticalSection(&HipSect);

	ret = Generic_pci_block_eeread(hndFile, board, addr, length, buf);
	if (ret == -1)
		assert(0); // HIP_READ_EEROM_FAIL

	GenericLeaveCriticalSection(&HipSect);
}

