/***************************************************************************
*	NAME:  CODEC.C $Revision: 1.9 $
**	COPYRIGHT:
**	"Copyright (c) 1994, by e-Tek Labs"
**
**       "This software is furnished under a license and may be used,
**       copied, or disclosed only in accordance with the terms of such
**       license and with the inclusion of the above copyright notice.
**       This software or any other copies thereof may not be provided or
**       otherwise made available to any other person. No title to and
**       ownership of the software is hereby transfered."
****************************************************************************
* $Log: codec.c $
* Revision 1.9  1995/11/21 17:29:09  sdsmith
* Changes for new Windows init.
* Revision 1.8  1995/09/28 15:52:00  wconway
* Changed reference to "iwlmacros.h" to "iwlmacro.h"
* Revision 1.7  1995/07/27 17:21:10  mleibow
* ideci was being set wrong for codec on IRQ2, and not being set at all
* for codec on IRQ1.
* Revision 1.6  1995/04/26 16:24:47  sdsmith
* Fixed public function commentary and made sure the close
* functions return the chip to a good known state
* Revision 1.5  1995/03/22 14:57:16  mleibow
* moved #include "codec.h" to iwl.h
* Revision 1.4  1995/03/08 15:27:50  mleibow
* add chip revision check for pre-release checks
* Revision 1.3  1995/02/24 13:50:13  mleibow
* Revision 1.2  1995/02/24 12:03:48  unknown
* Removed IDECI code, and added missing typecast to iw_add_handler call
* Revision 1.1  1995/02/23 11:06:56  unknown
* Initial revision
***************************************************************************/
/***************************************************************************
OVERVIEW:
codec.c - CODEC initialization and shutdown functions

This file contains the routines necessary to initialize and shutdown
the CODEC.
*/
#include <dos.h>
#include <string.h>

#include "iw.h"
#include "iwl.h"
#include "digital.h"
#include "globals.h"
#include "codec.h" 
#include "iwlmacro.h"

extern char iwl_set_channel_codec(int);
extern void init_codec_nodes(void);
extern int iwl_process_codec_interrupt(void);
extern struct dig_voice_status codec_playback_voice;
extern struct dig_voice_status codec_record_voice;


int codec_loaded = 0;
int codec_dma = 0;

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

FUNCTION DEFINITION:
iwl_codec_revision - get the codec version number 

DESCRIPTION:
This routine reads the codec version number from the codec register.

RETURNS: unsigned char - CODEC version number
*/
static unsigned char iwl_codec_revision(void)
{
    unsigned char version;

    OS_PUSH_DISABLE();
    OS_OUTPORTB(iwl_codec_base,MODE_SELECT_ID);
    version = OS_INPORTB(iwl_codec_data) & 0x8f;
    version = ((version & 0x80) >> 3) + (version & 0x0f);
    OS_POP_FLAGS();

    return(version);
}

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

FUNCTION DEFINITION:
iw_init_codec - find and initialize the codec

DESCRIPTION:
iw_init_codec performs the following steps to initialize the CODEC:

- attempt to read the version info from the codec
- if the codec is there:
  - initialize the mixer data structures
  - if the user has specified full initialization reset the mixer to
    the settings specified in the init string
  - set up the codec interrupt vector
  - set up the output voltage levels
  - set up the initial playback frequency, playback format and
    record format

RETURNS: IW_OK if the codec exists
         IW_CODEC_NOT_FOUND if not

*/
int iw_init_codec(struct load_kernel_cfg RFAR *cfg)
{
    int rc = IW_OK;

    OS_PUSH_DISABLE();

    if (codec_loaded) {
	codec_loaded++;
	OS_POP_FLAGS();
	return(IW_OK);
    }

    if (iwl_codec_base) {
	iwl_codec_data = iwl_codec_base + 1;
	iwl_codec_status = iwl_codec_base + 2;
	iwl_codec_pio = iwl_codec_base + 3;	

	/* Set the CEXTI register */
	iwl_cexti = CODEC_CEXTI_DEFAULT;
	IWL_CODEC_OUT(EXTERNAL_CONTROL, iwl_cexti);

	/* Disable Interrupts */
	iwl_codec_disable_irqs();

	/* Set the CODEC to Operate in Mode 3 */
	IWL_CODEC_OUT(MODE_SELECT_ID, 0x6C);
	iwl_cmodei = OS_INPORTB(iwl_codec_data);

	/* Set the configuration registers to their default values */
	iwl_cfig1i = CODEC_CFIG1I_DEFAULT;
	if (iwl_channel_in == iwl_channel_out) iwl_cfig1i |= CODEC_SINGLE_DMA;
	IWL_CODEC_OUT(CONFIG_1|CODEC_MCE, iwl_cfig1i);
	OS_OUTPORTB(iwl_codec_base, CONFIG_1);
	iwl_cfig2i = CODEC_CFIG2I_DEFAULT;
	IWL_CODEC_OUT(CONFIG_2, iwl_cfig2i);
	iwl_cfig3i = CODEC_CFIG3I_DEFAULT;

	/* the previous line of code is for pre-release chips */
	IWL_CODEC_OUT(CONFIG_3, iwl_cfig3i);

#ifdef IWL_CODEC_IRQ2
	iwl_ideci |= IWL_IDECI_IAC22;
	IWL_OUT_B(IW_IDECI, iwl_ideci);
	iwl_set_irq(iwl_irq2);
#else
	iwl_ideci &= ~IWL_IDECI_IAC22;
	IWL_OUT_B(IW_IDECI, iwl_ideci);
	iwl_set_irq(iwl_irq1);
#endif
	iw_add_handler(IW_IRQ_HANDLER_CODEC, (int (RFAR *)(void))iwl_process_codec_interrupt);

	if (cfg->UseDma) codec_dma = 1;

	/* Initialize the data structures */
	iwl_init_codec_voice(&codec_playback_voice);
	iwl_init_codec_voice(&codec_record_voice);

	iwl_flags |= F_IW_CODEC_LOADED;
	codec_loaded++;
    }
    else rc = IW_CODEC_NOT_FOUND;
    OS_POP_FLAGS();
    return(rc);
}
