/*
 *  Copyright (c) 1994/95 by Jaroslav Kysela (Perex soft)
 */

/* IO ports */

#define GUSP( x ) ( gus_port + g_u_s_##x )

#define g_u_s_GF1PAGE		(0x322-0x220)
#define g_u_s_GF1REGSEL		(0x323-0x220)
#define g_u_s_GF1DATALOW	(0x324-0x220)
#define g_u_s_GF1DATAHIGH	(0x325-0x220)
#define g_u_s_IRQSTAT		(0x226-0x220)
#define g_u_s_TIMERCNTRL	(0x228-0x220)
#define g_u_s_TIMERDATA		(0x229-0x220)
#define g_u_s_DRAM		(0x327-0x220)
#define g_u_s_MIXCNTRLREG	(0x220-0x220)
#define g_u_s_IRQDMACNTRLREG	(0x22b-0x220)
#define g_u_s_REGCNTRLS		(0x22f-0x220)
#define g_u_s_BOARDVERSION	(0x726-0x220)
#define g_u_s_MIXCNTRLPORT	(0x726-0x220)
#define g_u_s_MIXDATAPORT	(0x326-0x220)
#define g_u_s_MAXCNTRLPORT	(0x326-0x220)

/* memory things */

#define GUS_MEM_BANK_SHIFT	18
#define GUS_MEM_BANK_SIZE	( 1L << GUS_MEM_BANK_SHIFT )
#define MAX_GUS_MEMORY_BANKS	( ( 1024L * 1024L ) / GUS_MEM_BANK_SIZE )

/* ICS registers */

#define ICS_MIC_DEV		0
#define ICS_LINE_DEV		1
#define ICS_CD_DEV		2
#define ICS_GF1_DEV		3
#define ICS_NONE_DEV		4
#define ICS_MASTER_DEV		5

/* structures */

struct GUS_STRU_SAMPLE {
  int gbegin;                     /* begin sample in GUS MEM */
  int gstart;                     /* start address of loop */
  int gend;                       /* end address of loop */
  int length;                     /* size of sample */
  unsigned char voice_cntrl_reg;  /* this is reg. 0 of GF1 for this sample */
                                  /* bits 7,6,5,1,0 are ignored */
};

/* ramp ranges */

#define MIN_RAMP_RANGE_8        gf1_min_ramp_8
#define MIN_RAMP_RANGE_16       gf1_min_ramp_16
#define MAX_RAMP_RANGE_8        gf1_max_ramp_8
#define MAX_RAMP_RANGE_16       gf1_max_ramp_16

extern unsigned char gf1_min_ramp_8;
extern unsigned short gf1_min_ramp_16;
extern unsigned char gf1_max_ramp_8;
extern unsigned short gf1_max_ramp_16;

#define GF1_RAMP_AUTO		20

extern int gf1_ramp_auto;

extern void recompute_gf1_ramp_ranges( void );

/* some inline functions */

extern int gus_port;

extern inline void gus_write8( unsigned char reg, unsigned char data )
{
  OUTB( reg, GUSP( GF1REGSEL ) ); MB();
  OUTB( data, GUSP( GF1DATAHIGH ) ); MB();
}

extern inline unsigned char gus_read8( unsigned char reg )
{
  OUTB( reg | 0x80, GUSP( GF1REGSEL ) ); MB();
  return INB( GUSP( GF1DATAHIGH ) );
}
    
extern inline unsigned char gus_look8( unsigned char reg )
{
  OUTB( reg, GUSP( GF1REGSEL ) ); MB();
  return INB( GUSP( GF1DATAHIGH ) );
}

extern inline void gus_write16( unsigned char reg, unsigned int data )
{
  OUTB( reg, GUSP( GF1REGSEL ) ); MB();
  OUTB( (unsigned char)(data & 0xff), GUSP( GF1DATALOW ) );
  OUTB( (unsigned char)((data >> 8) & 0xff), GUSP( GF1DATAHIGH ) ); MB();
}
       
extern inline unsigned short gus_read16( unsigned char reg )
{
  OUTB( reg | 0x80, GUSP( GF1REGSEL ) ); MB();
  return ( (unsigned short)INB( GUSP( GF1DATAHIGH ) ) << 8 ) | 
           INB( GUSP( GF1DATALOW ) );
}

extern inline void gus_adlib_write( unsigned char reg, unsigned char data )
{
  OUTB( reg, GUSP( TIMERCNTRL ) );
  OUTB( data, GUSP( TIMERDATA ) );
}

extern short gus_active_voices;
extern unsigned int gf1_playback_freq;
extern unsigned int get_gf1_playback_freq( short voices );

extern inline void gus_select_active_voices( unsigned char voices )
{
  if ( voices < 14 ) voices = 14;
  if ( voices > 32 ) voices = 32;
  gus_active_voices = voices;
  gf1_playback_freq = get_gf1_playback_freq( voices );
  gus_write8( 0x0e, 0xc0 | ( voices - 1 ) );
}
