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

#ifndef __GUS_H
#define __GUS_H

#if defined( LINUX ) || defined( __LINUX__ )
#include <linux/ioctl.h>
#endif

/*
 *  Section for direct support of GF1 synthesizer - /dev/gus
 */

#define GUS_MAX_SAMPLES		128	/* max samples in GUS DRAM */
#define GUS_SYNTH_VERSION	0x0300	/* current version of protocol - 3.01 */
					/* main mask is 0xff00 - changes in low */
					/* 8 bites -> protocols are backwards */
					/* compatible; high 8. bites -> protocols */
					/* are totaly uncompatible */

/* commands over ioctl funtion - misc */
 
#define GUS_IOCTL_VERSION	_IO  ( 'g', 0x01 )
			/* return version of protocol (current GUS_SYNTH_VERSION) */
#define GUS_IOCTL_RESET0	_IO  ( 'g', 0x02 )
			/* reset synth engine only - not GF1 */
#define GUS_IOCTL_RESET		_IOW ( 'g', 0x02, int )
			/* first arg is number of active voices 14-32 */
#define GUS_IOCTL_INFO		_IOW ( 'g', 0x03, struct GUS_STRU_INFO )
			/* arg is ptr to GUS_STRU_INFO */

/* commands over ioctl funtion - setup */

#define GUS_IOCTL_VOL_TYPE	_IOW ( 'g', 0x20, int )
			/* volume type - see GUS_VOL_TYPE_XXXX constants */
#define GUS_IOCTL_FREQ_TYPE	_IOW ( 'g', 0x21, int )
			/* frequency type - see GUS_FREQ_TYPE_XXXX constants */
#define GUS_IOCTL_SET_AUTO_RAMP	_IOW ( 'g', 0x22, int )
			/* set auto ramp speed, 0 = off */
#define GUS_IOCTL_GET_AUTO_RAMP _IO  ( 'g', 0x22 )
			/* get auto ramp speed */
#define GUS_IOCTL_SET_SPAN	_IOW ( 'g', 0x23, int )
			/* set smooth pan speed in 80 us */
#define GUS_IOCTL_GET_SPAN	_IO  ( 'g', 0x23 )
			/* get smooth pan speed in 80 us */

/* commands over ioctl funtion - timer */

#define GUS_IOCTL_START_TIMER	_IOW ( 'g', 0x40, int )
			/* arg is count in one us */
			/* this ioctl select timer1 and timer2 automaticaly */
#define GUS_IOCTL_STOP_TIMER	_IO  ( 'g', 0x40 )
			/* stop timer */
#define GUS_IOCTL_START_TIMER1	_IOW ( 'g', 0x41, int )
			/* arg is 80us count */
#define GUS_IOCTL_STOP_TIMER1	_IO  ( 'g', 0x41 )
			/* stop timer 1 */
#define GUS_IOCTL_START_TIMER2	_IOW ( 'g', 0x42, int )
			/* arg is 320us count */
#define GUS_IOCTL_STOP_TIMER2	_IO  ( 'g', 0x42 )
			/* stop timer 2 */

/* commands over ioctl funtion - samples */

#define GUS_IOCTL_DOWNLOAD	_IOWR( 'g', 0x60, struct GUS_STRU_DOWNLOAD )
			/* arg is ptr to GUS_STRU_DOWNLOAD */

/* commands over ioctl funtion - samples */

#define GUS_IOCTL_FLUSH		_IO  ( 'g', 0x80 )
			/* flush command queue */
#define GUS_IOCTL_ABORT		_IO  ( 'g', 0x81 )
			/* abort command queue and stop gf1 */
#define GUS_IOCTL_QABORT	_IO  ( 'g', 0x82 )
			/* abort only command queue to command STOP */
#define GUS_IOCTL_SET_TICK	_IOW ( 'g', 0x83, int )
			/* set current absolute song tick */
#define GUS_IOCTL_GET_TICK	_IO  ( 'g', 0x83 )
			/* get current absolute song tick */

/*
 *  error codes
 */
 
#define EBADVOICE	322000
#define EBADSAMPLE	322001
#define EBADRAMP	322002

/*
 *  commands in write queue
 *
 *  format of queue:
 *  
 *    unsigned char	size		size of command
 *    unsigned char	command		see GUS_CMD_XXXX constants
 *    unsigned char	[size-2]	command argument bytes
 */

#define GUS_CMD_VOICE_SELECT	0x01	/* voice select - (unsigned char) 0-31 */
#define GUS_CMD_SAMPLE_SELECT	0x02	/* sample select - (unsigned short) 0-(GUS_MAX_SAMPLES-1) */

#define GUS_CMD_VOICE_CONTROL	0x10	/* voice control register (unsigned char) */
#define GUS_CMD_FREQUENCY	0x11	/* voice frequency (unsigned short) */
#define GUS_CMD_LOOP_START	0x12	/* voice loop start (long) - relative to begin of sample */
#define GUS_CMD_LOOP_END	0x13	/* voice loop end (long) - relative to begin of sample */
#define GUS_CMD_RAMP_RATE	0x14	/* voice ramp rate (unsigned char) */
#define GUS_CMD_RAMP_START	0x15	/* voice ramp start (unsigned char) */
#define GUS_CMD_RAMP_END	0x16	/* voice ramp end (unsigned char) */
#define GUS_CMD_CURRENT_VOL	0x17	/* voice current volume (unsigned short) */
#define GUS_CMD_CURRENT_LOC	0x18	/* voice current location (long) - relative to begin of sample */
#define GUS_CMD_CURRENT_PAN	0x19	/* voice current pan position (unsigned char) */
#define GUS_CMD_RAMP_CONTROL	0x1a	/* voice ramp control (unsigned char) */
#define GUS_CMD_FREQ_AND_VOL	0x1b	/* select voice & freq setup */
#define GUS_CMD_LOOP_ALL	0x1c	/* set all loop parameters: voice control, loop start, loop end */
#define GUS_CMD_RAMP_ALL	0x1d	/* set all ramp parameters: ramp control, ramp rate, ramp start, ramp end */
#define GUS_CMD_VOICE_STOP	0x1e	/* stop voice */

/*
 * commands 0x20-0x2f are equivalents to 0x10-0x1f, but
 * first byte of argument is number of voice (channel)
 */

#define GUS_CMD_VS_VOICE_CONTROL 0x20
#define GUS_CMD_VS_FREQUENCY	0x21
#define GUS_CMD_VS_LOOP_START	0x22
#define GUS_CMD_VS_LOOP_END	0x23
#define GUS_CMD_VS_RAMP_RATE	0x24
#define GUS_CMD_VS_RAMP_START	0x25
#define GUS_CMD_VS_RAMP_END	0x26
#define GUS_CMD_VS_CURRENT_VOL	0x27
#define GUS_CMD_VS_CURRENT_LOC	0x28
#define GUS_CMD_VS_CURRENT_PAN	0x29
#define GUS_CMD_VS_RAMP_CONTROL	0x2a
#define GUS_CMD_VS_FREQ_AND_VOL	0x2b
#define GUS_CMD_VS_LOOP_ALL	0x2c
#define GUS_CMD_VS_RAMP_ALL	0x2d
#define GUS_CMD_VS_VOICE_STOP	0x2e

#define GUS_CMD_SAMPLE_START	0x40	/* voice (short), start sample (short) 0-128, */
 					/* frequency (unsigned short), volume (unsigned short) */
#define GUS_CMD_SAMPLE_START1	0x41

#define GUS_CMD_SET_TIMER	0x50	/* set timer - us */
#define GUS_CMD_SET_TIMER1	0x51	/* set timer 1 - 80us */
#define GUS_CMD_SET_TIMER2	0x52	/* set timer 2 - 320us */
#define GUS_CMD_WAIT		0x53	/* wait n ticks (short) 1-(short max) */
#define GUS_CMD_STOP		0x54	/* see GUS_IOCTL_ABORT ioctl */

/* macros for implemented commands */

#ifdef __i386__
#define _gus_size_( size ) 	*_seq_buf++ = (2 + size)
#define _gus_cmd_( cmd ) 	*_seq_buf++ = GUS_CMD_##cmd
#define _gus_byte_( byte ) 	*_seq_buf++ = byte
#define _gus_word_( word ) 	*((unsigned short *)_seq_buf)++ = word
#define _gus_dword_( dword ) 	*((unsigned int *)_seq_buf)++ = dword
#else
#define _gus_size_( size ) 	*_seq_buf++ = (2 + size)
#define _gus_cmd_( cmd ) 	*_seq_buf++ = GUS_CMD_##cmd
#define _gus_byte_( byte ) 	*_seq_buf++ = byte
#define _gus_word_( word ) 	*_seq_buf++ = word & 0xff; \
                           	*_seq_buf++ = ( word >> 8 ) & 0xff;
#define _gus_dword_( dword ) 	*_seq_buf++ = dword & 0xff; \
			     	*_seq_buf++ = ( dword >> 8 ) & 0xff; \
                             	*_seq_buf++ = ( dword >> 16 ) & 0xff; \
                             	*_seq_buf++ = ( dword >> 24 ) & 0xff;
#endif

#define GUS_DO_VOICE_SELECT( voice ) \
  { _gus_size_( 1 ); _gus_cmd_( VOICE_SELECT ); _gus_byte_( voice ); }
#define GUS_DO_SAMPLE_SELECT( sample ) \
  { _gus_size_( 2 ); _gus_cmd_( SAMPLE_SELECT ); _gus_word_( sample ); }

#define GUS_DO_VOICE_CONTROL( cntrl ) \
  { _gus_size_( 1 ); _gus_cmd_( VOICE_CONTROL ); _gus_byte_( cntrl ); }
#define GUS_DO_FREQUENCY( freq ) \
  { _gus_size_( 4 ); _gus_cmd_( FREQUENCY ); _gus_dword_( freq ); }
#define GUS_DO_LOOP_START( start ) \
  { _gus_size_( 4 ); _gus_cmd_( LOOP_START ); _gus_dword_( start ); }
#define GUS_DO_LOOP_END( end ) \
  { _gus_size_( 4 ); _gus_cmd_( LOOP_END ); _gus_dword_( end ); }
#define GUS_DO_RAMP_RATE( rate ) \
  { _gus_size_( 1 ); _gus_cmd_( RAMP_RATE ); _gus_byte_( rate ); }
#define GUS_DO_RAMP_START( start ) \
  { _gus_size_( 1 ); _gus_cmd_( RAMP_START ); _gus_byte_( start ); }
#define GUS_DO_RAMP_END( end ) \
  { _gus_size_( 1 ); _gus_cmd_( RAMP_END ); _gus_byte_( end ); }
#define GUS_DO_CURRENT_VOL( vol ) \
  { _gus_size_( 2 ); _gus_cmd_( CURRENT_VOL ); _gus_word_( vol ); }   
#define GUS_DO_CURRENT_LOC( loc ) \
  { _gus_size_( 4 ); _gus_cmd_( CURRENT_LOC ); _gus_dword_( loc ); }   
#define GUS_DO_CURRENT_PAN( pan ) \
  { _gus_size_( 1 ); _gus_cmd_( CURRENT_PAN ); _gus_byte_( pan ); }   
#define GUS_DO_RAMP_CONTROL( cntrl ) \
  { _gus_size_( 1 ); _gus_cmd_( RAMP_CONTROL ); _gus_byte_( cntrl ); }   
#define GUS_DO_FREQ_AND_VOL( freq, vol ) \
  { _gus_size_( 6 ); _gus_cmd_( FREQ_AND_VOL ); _gus_dword_( freq ); _gus_word_( vol ); }
#define GUS_DO_LOOP_ALL( cntrl, start, end ) \
  { _gus_size_( 9 ); _gus_cmd_( LOOP_ALL ); _gus_byte_( cntrl ); _gus_dword_( start ); _gus_dword_( end ); }
#define GUS_DO_RAMP_ALL( cntrl, rate, start, end ) \
  { _gus_size_( 4 ); _gus_cmd_( RAMP_ALL ); _gus_byte_( cntrl ); _gus_byte_( rate ); _gus_byte_( start ); _gus_byte_( end ); }
#define GUS_DO_VOICE_STOP() \
  { _gus_size_( 0 ); _gus_cmd_( VOICE_STOP ); }

#define GUS_DO_VS_VOICE_CONTROL( voice, cntrl ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_VOICE_CONTROL ); _gus_byte_( voice ); _gus_byte_( cntrl ); }
#define GUS_DO_VS_FREQUENCY( voice, freq ) \
  { _gus_size_( 5 ); _gus_cmd_( VS_FREQUENCY ); _gus_byte_( voice ); _gus_dword_( freq ); }
#define GUS_DO_VS_LOOP_START( voice, start ) \
  { _gus_size_( 5 ); _gus_cmd_( VS_LOOP_START ); _gus_byte_( voice ); _gus_dword_( start ); }
#define GUS_DO_VS_LOOP_END( voice, end ) \
  { _gus_size_( 5 ); _gus_cmd_( VS_LOOP_END ); _gus_byte_( voice ); _gus_dword_( end ); }
#define GUS_DO_VS_RAMP_RATE( voice, rate ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_RAMP_RATE ); _gus_byte_( voice ); _gus_byte_( rate ); }
#define GUS_DO_VS_RAMP_START( voice, start ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_RAMP_START ); _gus_byte_( voice ); _gus_byte_( start ); }
#define GUS_DO_VS_RAMP_END( voice, end ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_RAMP_END ); _gus_byte_( voice ); _gus_byte_( end ); }
#define GUS_DO_VS_CURRENT_VOL( voice, vol ) \
  { _gus_size_( 3 ); _gus_cmd_( VS_CURRENT_VOL ); _gus_byte_( voice ); _gus_word_( vol ); }
#define GUS_DO_VS_CURRENT_LOC( voice, loc ) \
  { _gus_size_( 5 ); _gus_cmd_( VS_CURRENT_LOC ); _gus_byte_( voice ); _gus_dword_( loc ); }
#define GUS_DO_VS_CURRENT_PAN( voice, pan ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_CURRENT_PAN ); _gus_byte_( voice ); _gus_byte_( pan ); }
#define GUS_DO_VS_RAMP_CONTROL( voice, cntrl ) \
  { _gus_size_( 2 ); _gus_cmd_( VS_RAMP_CONTROL ); _gus_byte_( voice ); _gus_byte_( cntrl ); }
#define GUS_DO_VS_FREQ_AND_VOL( voice, freq, vol ) \
  { _gus_size_( 7 ); _gus_cmd_( VS_FREQ_AND_VOL ); _gus_byte_( voice ); _gus_dword_( freq ); _gus_word_( vol ); }
#define GUS_DO_VS_LOOP_ALL( voice, cntrl, start, end ) \
  { _gus_size_( 10 ); _gus_cmd_( VS_LOOP_ALL ); _gus_byte_( voice ); _gus_byte_( cntrl ); _gus_dword_( start ); _gus_dword_( end ); }
#define GUS_DO_VS_RAMP_ALL( voice, cntrl, rate, start, end ) \
  { _gus_size_( 5 ); _gus_cmd_( VS_RAMP_ALL ); _gus_byte_( voice ); _gus_byte_( cntrl ); _gus_byte_( rate ); _gus_byte_( start ); _gus_byte_( end ); }
#define GUS_DO_VS_VOICE_STOP( voice ) \
  { _gus_size_( 1 ); _gus_cmd_( VS_VOICE_STOP ); _gus_byte_( voice ); }

#define GUS_DO_SAMPLE_START( voice, sample, freq, vol ) \
  { _gus_size_( 9 ); _gus_cmd_( SAMPLE_START ); _gus_byte_( voice ); _gus_word_( sample ); _gus_dword_( freq ); _gus_word_( vol ); }
#define GUS_DO_SAMPLE_START1() \
  { _gus_size_( 0 ); _gus_cmd_( SAMPLE_START1 ); }

#define GUS_DO_SET_TIMER( count ) \
  { _gus_size_( 4 ); _gus_cmd_( SET_TIMER ); _gus_dword_( count ); }
#define GUS_DO_SET_TIMER1( count ) \
  { _gus_size_( 2 ); _gus_cmd_( SET_TIMER1 ); _gus_word_( count ); }   
#define GUS_DO_SET_TIMER2( count ) \
  { _gus_size_( 2 ); _gus_cmd_( SET_TIMER2 ); _gus_word_( count ); }   
#define GUS_DO_WAIT( ticks ) \
  { _gus_size_( 2 ); _gus_cmd_( WAIT ); _gus_word_( ticks ); }   
#define GUS_DO_STOP() \
  { _gus_size_( 0 ); _gus_cmd_( STOP ); }

/* bits for voice_cntrl_reg variable in GUS_STRU_SAMPLE */

#define GUS_WAVE_LOOP_BACK	0x40	/* loop back */
#define GUS_WAVE_BIDIRECTIONAL	0x10	/* bidirectional loop enable */
#define GUS_WAVE_LOOP		0x08	/* loop enable */
#define GUS_WAVE_16BIT		0x04	/* 16 bit sample width */
#define GUS_WAVE_INVERT		0x01	/* invert high bit */

/* defines for GUS_IOCTL_VOL_TYPE */

#define GUS_VOL_TYPE_GF1	0x00	/* volume type is GF1 */
#define GUS_VOL_TYPE_LINEAR	0x01	/* 0-128 - linear volume */

/* defines for GUS_IOCTL_FREQ_TYPE */

#define GUS_FREQ_TYPE_GF1	0x00	/* frequency type - GF1 */
#define GUS_FREQ_TYPE_HZ2	0x01	/* frequency type - HZ * 2 */
#define GUS_FREQ_TYPE_HZ	0x02	/* frequency type - HZ */

/* structures */

struct GUS_STRU_INFO {
  short port;
  short irq;
  short dma1;			  /* DMA1 - GF1 download & codec record */
  short dma2;			  /* DMA2 - GF1 record & codec playback */
  short version;		  /* version of gus 0x24, 0x37 or 0xa0 (MAX) */
  int memory_size;		  /* in bytes */
  int memory_free;		  /* in bytes */
};

struct GUS_STRU_DOWNLOAD {
  unsigned char *sample_ptr;	  /* pointer to sample */
  int loop_start;		  /* start of loop */
  int loop_end;		  	  /* end of loop */
  int length;			  /* size of sample */
  unsigned char voice_cntrl_reg;  /* see GUS_STRU_SAMPLE */
 /* returned: */
  int gus_addr;		  	  /* where is sample stored in GUS DRAM */
};

/*
 *  Compatibility section for VoxWare 3.00.
 *  VoxWare 3.00 - Copyright (c) by Hannu Savolainen.
 *  Code for gus module driver isn't copied from VoxWare driver - 
 *  It's copyrighted by me (Jaroslav Kysela).
 */

#ifndef SOUND_VERSION
#include <sys/soundcard.h>
#include <sys/ultrasound.h>
#if SOUND_VERSION < 300 && SOUND_VERSION > 301
#error Bad version of VoxWare header files... You must use VoxWare version 3.00-3.01.
#endif
#endif

#if 0
#include <sys/voxware_soundcard.h>
#endif

/*
 *
 */
 
#endif /* __GUS_H */
