/*

 *            Copyright (c) 1998-2004 by NETsilicon Inc.

 *

 *  This software is copyrighted by and is the sole property of

 *  NETsilicon.  All rights, title, ownership, or other interests

 *  in the software remain the property of NETsilicon.  This

 *  software may only be used in accordance with the corresponding

 *  license agreement.  Any unauthorized use, duplication, transmission,

 *  distribution, or disclosure of this software is expressly forbidden.

 *

 *  This Copyright notice may not be removed or modified without prior

 *  written consent of NETsilicon.

 *

 *  NETsilicon, reserves the right to modify this software

 *  without notice.

 *

 *  NETsilicon

 *  411 Waverley Oaks Road                  USA 781.647.1234

 *  Suite 227                               http://www.netsilicon.com

 *  Waltham, MA 02452                       AmericaSales@netsilicon.com

 *

 */



#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <tx_port.h>

#include <semaphore.h>

#include <ddi.h>

#include <netosIo.h>

#include <reg_def.h>



#include <serParam.h>



#include "netos_spi.h"

#include <NA_ISR.h>

#include <Dma_def.h>

#include <sysClock.h>

#include <reg_def.h>

#include <bool.h>

#include <tx_api.h>

#include <ncc_init.h>

#include "spi_mod.h"



/* #define EEPROM_SUPPORT    1 */



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

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiIntWr40()                                             ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 *** Function Calls: None                                                       ***

 ***                                                                            ***

 *** Comments: This routine handles write interrupts from the NCC.              ***

 **********************************************************************************

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



void onspiIntWr40 (ONSPI_CHAN * pChan)

{

    char outChar;

    UINT32 reg;

    SPIBUFFER volatile *q;

       

#if 0

    /* PORTC0 used for timing set it HI */

    reg = SER_REG (pChan->port, CTRL_REGA);

    if (intCount < 40)

    {

    	statreg[intCount++] = (SER_REG (pChan->port, STAT_REG)); 

    }



    *NARM_PORTC_ADDR |= 4;

#endif



    q = &(spiDataBuffer[pChan->port]);

    

    if ( (q->countServData + q->countForBufferData)  == 0)

    { /* We send out all data */ 



        /* disable transmitter interrupt */

        reg = SER_REG (pChan->port, CTRL_REGA);

        reg &= (~XMITR_CLOSED_IRQ);

    	reg &= (~XMITR_HALF_FULL_IRQ);

        SER_REG (pChan->port, CTRL_REGA) = reg;

	    /* if no read or slave - release samaphore */

    	if ( (!pChan->readInProgres || pChan->slaveMode ) && (pChan->ISRlevel == -1))

        {

	        tx_semaphore_put (&((pChan->spi_int_sem)->sem));

        }



    	return;

    }

    

#ifdef EEPROM_SUPPORT

    if (q->countServData != 0)

    {

    	/* remove a char from the server buffer */

	    outChar = *(q->ptrSerData++);

    	q->countServData--;

	    SER_REG_BYTE (pChan->port, DATA_REG) = outChar;

    }

    else

#endif



    {

    	if (q->countForBufferData !=0 )

	    {

	        /* remove byte from the main buffer */

    	    outChar = *(q->ptrDataBuffer++);

	        q->countForBufferData--;

	        SER_REG_BYTE (pChan->port, DATA_REG) = outChar;

    	}

    }



    if ((q->countServData + q->countForBufferData)  == 0)

    { 

        /* We send out all data */         

        reg = SER_REG (pChan->port, CTRL_REGA);

        reg &= (~XMITR_RDY_IRQ); 

        reg |= XMITR_HALF_FULL_IRQ; /* Problem with HW. We need only XMITR_CLOSED_IRQ at this time */

	    reg |= XMITR_CLOSED_IRQ ;

        SER_REG (pChan->port, CTRL_REGA) = reg;

    }

#if 0

    /* PORTC2 used for timing set it LOW */

    if (intCount < 40)

    {

	    statreg[intCount++] = (SER_REG (pChan->port, STAT_REG));

    }



    *NARM_PORTC_ADDR &= 0xFEFFFFFB; 

#endif

}



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

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiIntWr50()                                             ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 *** Function Calls: None                                                       ***

 ***                                                                            ***

 *** Comments: This routine handles write interrupts from the NCC.              ***

 **********************************************************************************

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



void onspiIntWr50 (ONSPI_CHAN * pChan)

{

    char outChar;

    UINT32 reg;

    SPIBUFFER volatile *q;

       

#if 0

    /* PORTC0 used for timing set it HI */

    *NARM_PORTC_ADDR |= 4;

    reg = SER_REG (pChan->port, CTRL_REGA);

    if (intCount < 40)

	    statreg[intCount++] = (SER_REG (pChan->port, STAT_REG)); 

   

#endif

 

    q = &(spiDataBuffer[pChan->port]);

    

    if ((q->countServData + q->countForBufferData)  == 0)

    { /* We send out all data  */



        /* disable transmitter interrupt */

        reg = SER_REG (pChan->port, CTRL_REGA);

    	reg &= (~XMITR_RDY_IRQ); 

        reg &= (~XMITR_CLOSED_IRQ);

	    reg &= (~XMITR_HALF_FULL_IRQ);

        SER_REG (pChan->port, CTRL_REGA) = reg;

    	/* if no read or slave - release samaphore */

	    if ( (!pChan->readInProgres || pChan->slaveMode ) && (pChan->ISRlevel == -1) )

        {

	        tx_semaphore_put (&((pChan->spi_int_sem)->sem));

        }

#if 0

        /* PORTC2 used for timing set it LOW */

    	*NARM_PORTC_ADDR &= 0xFEFFFFFB; 

	    if (intCount < 40)

        {

	        statreg[intCount++] = (SER_REG (pChan->port, STAT_REG)); 

        }

#endif

	    return;

    }



#ifdef EEPROM_SUPPORT 

    if (q->countServData != 0)

    {

    	/* remove a char from the server buffer */

	    outChar = *(q->ptrSerData++);

    	q->countServData--;

	    SER_REG_BYTE (pChan->port, DATA_REG) = outChar;

    }

    else

#endif



    {

    	if (q->countForBufferData !=0 )

	    {

    	    /* remove byte from the main buffer */

	        outChar = *(q->ptrDataBuffer++);

	        q->countForBufferData--;

    	    SER_REG_BYTE (pChan->port, DATA_REG) = outChar;

	    }

    }

#if 0

    /* PORTC2 used for timing set it LOW */

    *NARM_PORTC_ADDR &= 0xFEFFFFFB; 

    if (intCount < 40)

    {

    	statreg[intCount++] = (SER_REG (pChan->port, STAT_REG)); 

    }

#endif

}



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

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiIntRd()                                               ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 *** Function Calls: None                                                       ***

 ***                                                                            ***

 *** Comments: This routine handles read interrupts from the NCC.        	***

 **********************************************************************************

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

void onspiIntRd (ONSPI_CHAN * pChan)

{

    UINT32 reg ;

    UINT32 inchar;

    UINT8  *ptr;

    int nread;

    int i;

    SPIBUFFER volatile *q;



#ifdef debug_spi

    /* PORTC0 used for timing set it HI */

    reg = SER_REG (pChan->port, CTRL_REGA);

    if (intCount < 40)

    {

	    statreg[intCount++] = (SER_REG (pChan->port, STAT_REG)); 

    }

    *NARM_PORTC_ADDR |= 4;

#endif



    reg = (SER_REG(pChan->port, STAT_REG));

    

    SER_REG(pChan->port, STAT_REG) |= CLR_ALL_RX_CONDITIONS;

    inchar = SER_REG(pChan->port, DATA_REG);



#if 0

     /* PORTC0 used for timing set it HI */

     

    if (intCount < 40)

    {

    	statreg[intCount++] = reg;

    }



    if (intCount < 40)

    {

	    statreg[intCount++] = SER_REG(pChan->port, STAT_REG); 

    }

#endif

    

    q = &(spiInBuffer[pChan->port]);



    nread = 0;

    if (reg & RECV_RDY)

    {

    	nread = (reg  & NUM_DATA_BYTES) >> 20;

	    if (nread == 0)

        {

	        nread = 4;

        }

    }

    ptr = (UINT8*) &inchar;

    

    for (i = 0 ; i < nread; i++)

    {



#ifdef EEPROM_SUPPORT

    	if (q->countServData != 0)

    	{

	        /* add a char from the server buffer */

	        *(q->ptrSerData++) = *(ptr+i);

	        q->countServData--;

	    }

	    else

#endif

	    {

	        if (q->countForBufferData !=0 )

	        {

		        /* add byte from the main buffer */

		        *(q->ptrDataBuffer++) = *(ptr+i);

		        q->countForBufferData--;

	        }

	    }

    }                     /* End of for nread*/

    

    if ((q->countServData + q->countForBufferData) == 0)

    {



    	/* disable transmitter interrupt */

        reg = SER_REG (pChan->port, CTRL_REGA);

        reg &= ~(RECV_RDY_IRQ |RECV_CLOSED_IRQ|RECV_HALF_FULL_IRQ);

        SER_REG (pChan->port, CTRL_REGA) = reg;

    	if (pChan->ISRlevel == -1)

        {

	        tx_semaphore_put (&((pChan->spi_int_sem)->sem));

        }

    }

     SER_REG(pChan->port, STAT_REG) |= RECV_CLOSED;

#ifdef debug_spi

     /* PORTC0 used for timing set it HI */

     

    if (intCount < 40)

    {

	    statreg[intCount++] = SER_REG(pChan->port, STAT_REG); 

    }



    /* PORTC2 used for timing set it LOW */

    *NARM_PORTC_ADDR &= 0xFEFFFFFB; 

#endif

}



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

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiRxStartup()                                           ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 ***                                                                            ***

 *** Comments: Call interrupt level character output routine and enable         ***

 *** interrupt.  Function returns: OK on success, ENOSYS if the device is       ***

 *** polled-only, or EIO on hardware error.                                     ***

 **********************************************************************************

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

 int onspiRxStartup (ONSPI_CHAN* pChan)

{

    int status;



    if (pChan->slaveMode)

    {

    	status = sem_trywait(pChan->spi_int_sem);

	    if (status != TX_SUCCESS)

    	{

            /* something is wrong */

	        sem_post(pChan->spi_int_sem);

	        return status;

	    }



    	if (pChan->ISRlevel != -1)

        {

	        NAEnableIsr(pChan->ISRlevel);

        }

    }

    else

    {

    	status = TX_SUCCESS;

    }



    if (pChan->SSport != NULL && !pChan->slaveMode)

    {

	    *(pChan->SSport) &= pChan->SSsetLowMask;

    }

    

    /* tx int is enabled in tx_startup() */

    NAEnableIsr (pChan->rxlevel);

    

    SER_REG (pChan->port, CTRL_REGA) |= (RECV_RDY_IRQ |RECV_CLOSED_IRQ|RECV_HALF_FULL_IRQ);



    return status;

    

}



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

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiTxStartup()                                           ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 ***                                                                            ***

 *** Comments: Call interrupt level character output routine and enable         ***

 *** interrupt.  Function returns: OK on success, ENOSYS if the device is       ***

 *** polled-only, or EIO on hardware error.                                     ***

 **********************************************************************************



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



int onspiTxStartup (ONSPI_CHAN* pChan)

{



    int status;

    

    status = sem_trywait(pChan->spi_int_sem);

    if (status != TX_SUCCESS)

    {

        /* something wrong */

    	sem_post(pChan->spi_int_sem);

    	return status;

    }



    if (pChan->ISRlevel != -1)

    {

    	NAEnableIsr(pChan->ISRlevel);

    }

    

    if (pChan->SSport != NULL && !pChan->slaveMode)

    {

    	*(pChan->SSport) &= pChan->SSsetLowMask;

    }

    

    /* enable transmitter interrupts */

    NAEnableIsr (pChan->txlevel);

    /* We need

     * XMITR_HALF_FULL_IRQ to add data to the FIFO

     * XMITR_CLOSED_IRQ to clean it

     * XMITR_RDY_IRQ to know that XMITR_RDY_IRQ clear has been accknowledged by the HW

       and we can write data to the FIFO.

     */

    SER_REG (pChan->port, CTRL_REGA) |= XMITR_RDY_IRQ  ;

     

    return status;

}

