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

#ifdef LINUX

#define __KERNEL__

#include <linux/module.h>

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/malloc.h>

#include <linux/ioport.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/string.h>

#include <linux/fs.h>
#include <linux/fcntl.h>

#include "gus.h"

#define	GUS_MAJOR	26
#ifdef FTAPE_DMA
#define FTAPE_MAJOR	27
#endif

#define PRINTK printk

#define OUTB( value, reg ) outb( value, reg )
#define OUTW( value, reg ) outw( value, reg )
#define INB( reg ) inb( reg )
#define INW( reg ) inw( reg )
#define STI() sti()
#define CLI() cli()

#define MB() 			/* 386+ architecture doesn't need io sync */

#define SLEEP_EXTERN( ident ) \
  extern struct wait_queue *sleeper_##ident; \
  extern unsigned long end_jiffies_##ident;
#define SLEEP_PREPARE( ident ) \
  struct wait_queue *sleeper_##ident = NULL; \
  unsigned long end_jiffies_##ident;
#define SLEEP( ident, hz18 ) \
  end_jiffies_##ident = current -> timeout = jiffies + hz18; \
  interruptible_sleep_on( &sleeper_##ident );
#define SLEEPU( ident, hz18 ) \
  end_jiffies_##ident = current -> timeout = jiffies + hz18; \
  sleep_on( &sleeper_##ident );
#define TABORT( ident ) \
  ( current -> signal & ~current -> blocked & \
    ~( ( 1 << ( SIGALRM - 1 ) ) | ( 1 << ( SIGVTALRM - 1 ) ) ) )
#define WAKEUP( ident ) wake_up( &sleeper_##ident );
#define TIMEOUT( ident ) ( end_jiffies_##ident < jiffies )
#define TIMEOUT_VALUE( ident ) ( end_jiffies_##ident - jiffies )

#define VERIFY_AREA verify_area

#define MEMCPY memcpy

#define MEMCPY_FROMFS memcpy_fromfs
#define MEMCPY_TOFS memcpy_tofs

#define VMALLOC vmalloc
#define VFREE vfree

#define IOCTL_IN( arg )		get_fs_int( (int *)arg )
#define IOCTL_OUT( arg, val )	gus_ioctl_out( (int *)arg, val )

#define get_fs_int get_fs_long
#define put_fs_int put_fs_long

#elif OSF1

#define LDBL_DEBUG

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/map.h>
#include <sys/buf.h>
#include <sys/vm.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/devio.h>
#include <hal/cpuconf.h>
#include <sys/exec.h>
#include <io/common/devdriver.h>
#include <sys/sysconfig.h>
#include <io/dec/eisa/isa.h> 
#include <machine/cpu.h>
#include <sys/malloc.h>

#include <io/gus/gus.h>

#define	GUS_MAJOR	70

#define PRINTK printf

#define OUTB( value, reg ) WRITE_BUS_D8( osf_io_handle + reg, value )
#define OUTW( value, reg ) WRITE_BUS_D16( osf_io_handle + reg, value )
#define INB( reg ) READ_BUS_D8( osf_io_handle + reg )
#define INW( reg ) READ_BUS_D16( osf_io_handle + reg )
#define STI()
#define CLI()

#define MB() mb()			/* synchronize IO with cache */

#define HZ (hz*18)

#define SLEEP_EXTERN( ident ) \
  extern int sleep_res_##ident;
#define SLEEP_PREPARE( ident ) \
  int sleep_res_##ident = 0;
#define SLEEP( ident, hz18 ) \
  sleep_res_##ident = mpsleep( (caddr_t)&sleep_res_##ident, PCATCH, "Zzzzzz", ( ( hz18 ) * hz ) / 18, (void *)NULL, 0 );
#define WAKEUP( ident ) \
  wakeup( (caddr_t)&sleep_res_##ident );
#define TIMEOUT( ident ) ( sleep_res_##ident == EWOULDBLOCK )

#define VERIFY_READ 0
#define VERIFY_WRITE 1
#define VERIFY_AREA( what, ptr, size ) 0

#define MEMCPY( dest, src, size ) bcopy( src, dest, size )

#define MEMCPY_FROMFS( dest, src, size ) copyin( (caddr_t)src, (caddr_t)dest, size )
#define MEMCPY_TOFS( dest, src, size ) copyout( (caddr_t)src, (caddr_t)dest, size )

#define VMALLOC( size ) malloc( (u_long)(size), BUCKETINDEX( size ), M_DEVBUF, M_WAITOK )
#define VFREE( ptr ) free( (void *)(ptr), M_DEVBUF )

#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT

#define IOCTL_IN( arg )		get_fs_int( (int *)arg )
#define IOCTL_OUT( arg, val )	gus_ioctl_out( (int *)arg, val )

#define outb 1
#define outw 1
#define inb 1
#define inw 1
#define cli 1
#define sti 1
#define printk 1
#define memcpy_fromfs 1
#define memcpy_tofs 1

extern int hz;

extern io_handle_t osf_io_handle;	/* it must begin with port 0 !!!! */
extern struct controller *osf_controller;
extern dma_handle_t osf_dma1_handle;
extern dma_handle_t osf_dma2_handle;

int timeout_fcn( int *cnt );
char get_fs_byte( char *ptr );
int get_fs_int( int *ptr );
void put_fs_word( short data, short *ptr );
void put_fs_int( int data, int *ptr );

#else

#error Unknown system!!!

#endif

/*
 *  ==========================================================================
 */

#include "gf1.h"
#include "codec.h"

#define VERSION "1.25a"

#define VERSION_AND_COPYRIGHT \
"Version " VERSION ", Copyright (c) 1994/95 by Jaroslav Kysela (Perex soft)"

#define SNDSTAT_STRING \
"GUS - compatibility string for gmod : 3.0\n"

/* MINOR numbers */ 

#define GUS_MINOR_GSYNTH	1	/* gus synth */
#define GUS_MINOR_MIXER		2	/* mixer - VoxWare 3.00 compatible */
#define GUS_MINOR_PCM_8		3	/* 8bit PCM - VoxWare 3.00 compatible */
#define GUS_MINOR_PCM_16	4	/* 16bit PCM - VoxWare 3.00 compatible */
#define GUS_MINOR_AUDIO		5	/* /dev/audio - SunSparc compatible */
#ifdef VOXWARE_SEQUENCER
#define GUS_MINOR_SEQUENCER	6	/* /dev/sequencer - VoxWare 3.00 compatible */
#define GUS_MINOR_SEQUENCER2	7	/* /dev/sequencer2 - VoxWare 3.00 compatible */
#define GUS_MINOR_SNDSTAT	254	/* /dev/sndstat - for compatibility with VoxWare */
#endif
#ifndef PROC_SUPPORT
#define GUS_MINOR_INFO		255	/* show information about gus device driver */
#endif

/* sleep & wakeup state */

#define WK_NONE			0x00
#define WK_LOCK			0x01		/* lock this DMA channel */
#define WK_WAKEUP		0x02		/* DMA transfer done */
#define WK_SLEEP		0x04		/* DMA sleep */

/* defines for gf1_mode */

#define GF1_MODE_NONE		0x00
#define GF1_MODE_SYNTH		0x01
#define GF1_MODE_PCM		0x02

/* defines for codec_mode */

#define CODEC_MODE_NONE		0x00
#define CODEC_MODE_USED		0x01

/* defines for mixer */

#define MIX_MIC         0
#define MIX_LINE        1
#define MIX_CD          2
#define MIX_GF1         3
#define MIX_PCM         4
#define MIX_GAIN        5
#define MIX_MASTER      6
#define MIX_GF1_MASTER	7
#define MIX_LAST        (MIX_GF1_MASTER+1)

struct current_mix_stru {
  short left_mute;      /* 0 = mute on */
  short left;
  short right_mute;     /* 0 = mute on */
  short right;
};

/* device.c */

extern int gus_ioctl_out( int *addr, int value );

/* gus_io.c */

extern void gus_delay( void );
extern void gus_write8( unsigned char reg, unsigned char data );
extern unsigned char gus_read8( unsigned char reg );
extern unsigned char gus_look8( unsigned char reg );
extern void gus_write16( unsigned char reg, unsigned int data );
extern unsigned short gus_read16( unsigned char reg );
extern void gus_poke( unsigned int addr, unsigned char data );
extern unsigned char gus_peek( unsigned int addr );
extern void gus_write_addr( unsigned char reg, unsigned int addr, short w_16bit );
extern unsigned int gus_read_addr( unsigned char reg, short w_16bit );
extern void codec_outm( unsigned char reg, unsigned char mask, unsigned char value );
#if 0
extern void codec_debug( void );
#endif

/* init.c */

extern short ics_flag;
extern short codec_flag;
extern short max_flag;
extern int gus_port;
extern int codec_port;
extern int use_codec;
extern int gus_irq;
extern int gus_dma1;
extern int gus_dma2;
extern int gus_version;
extern int gus_mem;
extern short gus_active_voices;
extern unsigned int gf1_playback_freq;
extern struct GUS_STRU_SAMPLE samples[];
extern short gus_last_sample;
extern short max_cntrl_val;
extern short dma1_lock;
extern short dma2_lock;
extern unsigned char *dma1_buf;
extern unsigned char *dma2_buf;
extern int dma1_buf_size;
extern int dma2_buf_size;
extern char *dma1_owner;
extern char *dma2_owner;
extern int gus_init( void );
extern int gus_reset( short voices );
extern void gus_stop( void );
extern void gus_reset_samples( void );
extern int gus_mem_free( void );
extern int gus_download( struct GUS_STRU_DOWNLOAD *sample );
extern int gus_download1( struct GUS_STRU_DOWNLOAD *sample );
extern int gus_info( struct GUS_STRU_INFO *info );
extern int get_info_init( char *buffer );

/* gus_irq.c */

extern volatile long gf1_synth_irqs;
extern void gus_interrupt( int unused, struct pt_regs *regs );

/* gf1_synth.c */
 
extern short gf1_mode;
extern void gf1_synth_interrupt( unsigned char status );
extern int do_gus_command( void );
extern int gus_ioctl_gf1( unsigned int cmd, unsigned long arg );
extern int gus_open_gf1( void );
extern void gus_release_gf1( void );
extern int gus_read_gf1( char *buf, int count );
extern int gus_write_gf1( char *buf, int count );

/* gf1_utils.c */

extern unsigned short volumeTable[];
#define hz2_to_gf1_freq( hz ) ( ( ( (unsigned int)hz << 9 ) + ( gf1_playback_freq >> 1 ) ) / gf1_playback_freq )
extern unsigned short lvol_to_gf1_vol( unsigned vol );
extern unsigned short lvol_to_gf1_vol_16( unsigned vol );
extern unsigned int get_gf1_playback_freq( short voices );
extern short gus_ramp_ok( unsigned char *start, unsigned char *end );
extern short gus_set_ramp( unsigned char start, unsigned char end, unsigned char cntrl );
extern void gf1_init_dma_transfer( unsigned int addr, unsigned char *buf, int count, short w_unsigned, short w_16bit );
extern void gf1_done_dma_transfer( void );
extern void gf1_init_rdma_transfer( unsigned char *buf, int count, unsigned char rctrl_reg );
extern void gf1_done_rdma_transfer( void );

/* mixer.c */

extern struct current_mix_stru current_mix[];
extern unsigned char gus_mix_ctrl_reg;
extern short codec_mute_output;
extern void mixer_init( void );
extern void codec_set_mute( unsigned char dev, short left, short right );
extern int gus_ioctl_mixer( unsigned int cmd, unsigned long arg );
extern int gus_open_mixer( void );
extern void gus_release_mixer( void );

/* pcm.c */

extern int gus_ioctl_pcm( short minor, unsigned int cmd, unsigned long arg );
extern int gus_open_pcm( short minor, unsigned short f_flags );
extern void gus_release_pcm( short minor, unsigned short f_flags );
extern int gus_read_pcm( short minor, char *buf, int count );
extern int gus_write_pcm( short minor, char *buf, int count );

/* gf1_pcm.c */

extern void gf1_pcm_new_volume( void );
extern void gf1_pcm_interrupt( unsigned char status );

/* codec_pcm.c */

extern short codec_mode;
extern int codec_init( void );
extern void codec_interrupt( unsigned char status );

/* info.c */

#ifdef PROC_SUPPORT
extern void gus_proc_file_init( void );
extern void gus_proc_file_done( void );
#else
extern int gus_read_info( char *buf, off_t *offset, int count );
extern int gus_open_info( void );
extern void gus_release_info( void );
#endif
extern int gus_read_sndstat( char *buf, off_t *offset, int count );
extern int gus_open_sndstat( void );
extern void gus_release_sndstat( void );

/* sequencer.c */

#ifdef VOXWARE_SEQUENCER
extern int gus_lseek_sequencer( short minor, off_t offset, int orig );
extern int gus_read_sequencer( short minor, char *buf, int count );
extern int gus_write_sequencer( short minor, char *buf, int count );
extern int gus_open_sequencer( short minor, unsigned short f_flags );
extern void gus_release_sequencer( short minor, unsigned short f_flags );
extern int gus_select_sequencer( short minor, unsigned short f_flags );
extern int gus_ioctl_sequencer( short minor, unsigned int cmd, unsigned long arg );
#endif

/* another things */

SLEEP_EXTERN( dma1 )
SLEEP_EXTERN( dma2 )
