/***************************************************************************
*	NAME:  IWPNP.C $Revision: 1.13 $
**	COPYRIGHT:
**	"Copyright (c) 1994,1995 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: iwpnp.c $
* Revision 1.13  1995/10/16 10:13:27  sdsmith
* Added code to issue and revoke PNP key
* Revision 1.12  1995/09/28 14:44:09  mleibow
* Added DMA channel 0 support for synth DMA1 and synth DMA2.
* Revision 1.11  1995/09/12 18:58:47  mleibow
* Moved dma and irq validation code to after VxD get_resource call.
* Revision 1.10  1995/09/11 13:01:20  unknown
* changes for win95
* Revision 1.9  1995/09/11 05:51:35  unknown
* Revision 1.8  1995/09/11 05:42:26  unknown
* Changes for Win95 support
* Revision 1.7  1995/06/09 14:13:53  sdsmith
* Mike's changes
* Revision 1.6  1995/06/09 05:01:33  mleibow
* If pnp settings for DMA2 or IRQ2 are invalid, they will combine to DMA1 aIRQ1
* Revision 1.5  1995/05/25 15:14:27  mleibow
* Fixed base port bug, added MLS support.
* Revision 1.4  1995/05/19 01:27:56  mleibow
* Added more code to determine if card is actually programmed properly.
* Revision 1.3  1995/04/21 19:15:24  mleibow
* Modified iwl_get_pnp_config to return error status if card not found
* Revision 1.2  1995/04/14 09:19:53  sdsmith
* Added support for B0 silicon
* Revision 1.1  1995/02/23 11:07:17  unknown
* Initial revision
***************************************************************************/
#include "iw.h"
#include "iwl.h"
#include "globals.h"
#include "codec.h"
#define _WIN95
#if defined(_WINDOWS) || defined(_WIN95)
extern unsigned long Virtual_API;
#include "..\windows\viwd\viwd.h"
#endif

#define ON 1
#define OFF 0

void iwl_pnp_key(void)
{
    UCHAR code=0x6A;
    UCHAR msb;
    UCHAR i;
	
    /* Reset Linear Feedback Shift Reg. */

    OS_OUTPORTB(iwl_pnp_index,0x00);
    OS_OUTPORTB(iwl_pnp_index,0x00);

    OS_OUTPORTB(iwl_pnp_index,code);          /* Initial value */

    for (i=1; i<32; i++) {
	msb = ((code&0x01)^((code&0x02)>>1))<<7;
	code = (code>>1)|msb;
	OS_OUTPORTB(iwl_pnp_index,code);
    }
}
void iwl_pnp_revoke_key(void)
{
    OS_OUTPORTB(iwl_pnp_index, IW_PCCCI);
    OS_OUTPORTB(iwl_pnp_write, 0x02);
}
void iwl_pnp_wake(UCHAR csn)
{
    OS_OUTPORTB(iwl_pnp_index,IW_PWAKEI);     /* select PWAKEI */
    OS_OUTPORTB(iwl_pnp_write,csn);          /* write csn */
}
void iwl_pnp_select_dev(UCHAR dev)
{
    OS_OUTPORTB(iwl_pnp_index,IW_PLDNI);      /* select PLDNI */
    OS_OUTPORTB(iwl_pnp_write,dev);          /* write PLDNI */
}
void iwl_pnp_activate_dev(UCHAR dev, UCHAR bool)
{
    iwl_pnp_select_dev(dev);		/* select audio device */

    OS_OUTPORTB(iwl_pnp_index,IW_PUACTI);	/* select Activate Register */
    OS_OUTPORTB(iwl_pnp_write,bool);		/* write register */
}
#ifdef NEVER
#if defined(_WINDOWS) || defined(_WIN95)
unsigned char iwl_get_pnp_resource(
  UCHAR res,
  USHORT RFAR *val)
{
    unsigned char rc = 1;

    _asm {
	mov dx, IWAPI_GETRESOURCECONFIG
        xor ax,ax
        mov al, res
	call dword ptr[Virtual_API]
        les bx,val
        mov word ptr es:[bx],ax
        jnc Success
    }
    rc = 0;
Success:
    return(rc);
}
#endif
#endif
/***************************************************************************

FUNCTION DEFINITION:
iwl_get_pnp_config - read the PNP configuration registers

DESCRIPTION:
This function reads the PNP configuration registers in the InterWave
chip.

RETURN VALUE: int
	IW_OK
	IW_CARD_NOT_FOUND

*/
int iwl_get_pnp_config(void)
{
    unsigned short tmp;
    int rc = IW_OK;

    OS_PUSH_DISABLE();
    if (!os_get_vxd_info())
    	{
	  if (iwl_pnp_read) {

      /* Wake up the card into the config state */
            iwl_pnp_key();
	    iwl_pnp_wake(iwl_pnp_csn);
    
      /* Set the logical device number for device 0 */
	    iwl_pnp_select_dev(IWL_PNP_AUDIO);
    
      /* Read the address control registers */
	    OS_OUTPORTB(iwl_pnp_index, IW_P2X0HI);
	    tmp = OS_INPORTB(iwl_pnp_read);
	    OS_OUTPORTB(iwl_pnp_index, IW_P2X0LI);
	    iwl_base_port = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
	    if (iwl_revision >= 4) {
		OS_OUTPORTB(iwl_pnp_index, IW_P3X0HI);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_P3X0LI);
		iwl_synth_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_PHCAI);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_PLCAI);
		iwl_codec_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
	    }
	    else {
	      /* This else clause is for pre-production chips */
		OS_OUTPORTB(iwl_pnp_index, 0x66);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, 0x67);
		iwl_synth_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, 0x68);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, 0x69);
		iwl_codec_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
	    }
    
      /* Read the IRQ channel registers */
	    OS_OUTPORTB(iwl_pnp_index, IW_PUI1SI);
	    iwl_irq1 = OS_INPORTB(iwl_pnp_read);
	    OS_OUTPORTB(iwl_pnp_index, IW_PUI2SI);
	    iwl_irq2 = OS_INPORTB(iwl_pnp_read);
    
      /* Read the DMA channel registers */
	    OS_OUTPORTB(iwl_pnp_index, IW_PUD1SI);
	    iwl_channel_out = (UCHAR)OS_INPORTB(iwl_pnp_read);
	    iwl_codec_rec_chan = iwl_channel_out;
	    OS_OUTPORTB(iwl_pnp_index, IW_PUD2SI);
	    iwl_channel_in = (UCHAR)OS_INPORTB(iwl_pnp_read);
    
      /* Set the logical device number for device 4 */
	    if (iwl_revision >= 4) {
		iwl_pnp_select_dev(IWL_PNP_ADLIB);
		OS_OUTPORTB(iwl_pnp_index, IW_P388HI);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_P388LI);
		iwl_adlib_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_PSBISI);
		iwl_adlib_irq = OS_INPORTB(iwl_pnp_read);
		iwl_pnp_select_dev(IWL_PNP_MPU401);
		OS_OUTPORTB(iwl_pnp_index, IW_P401HI);
		tmp = OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_P401LI);
		iwl_mpu_base = (tmp << 8) + (USHORT)OS_INPORTB(iwl_pnp_read);
		OS_OUTPORTB(iwl_pnp_index, IW_PMISI);
		iwl_mpu_irq = OS_INPORTB(iwl_pnp_read);
	    }
    
      /* Activate the card */
	    iwl_pnp_activate_dev(IWL_PNP_AUDIO, ON);
	    iwl_pnp_activate_dev(IWL_PNP_MPU401, ON);
    
      /* Take the card out of Config state */
	    OS_OUTPORTB(iwl_pnp_index, IW_PWAKEI);
	    OS_OUTPORTB(iwl_pnp_write, 0x00);

	    if (iwl_synth_base != 0xFFFF && iwl_synth_base != 0) {
		if (iw_detect_card(iwl_base_port)) {
		    rc = IW_OK;
		} else {
		    rc = IW_CARD_NOT_FOUND;
		}
	    } else {
		rc = IW_CARD_NOT_FOUND;
	    }
	    iwl_pnp_revoke_key();
	} else rc = IW_CARD_NOT_FOUND;
    }
    if (iwl_irq2 == 0) iwl_irq2 = iwl_irq1;
    if (iwl_channel_in == 4) {
	iwl_channel_in = iwl_channel_out;
    }
    iwl_codec_play_chan = iwl_channel_in;

    OS_POP_FLAGS();
    return(rc);
}
