/*
 **********************************************************************
 *     hwaccess.h
 *     Copyright 1999, 2000 Creative Labs, Inc.
 *
 **********************************************************************
 *
 *     Date		    Author	    Summary of changes
 *     ----		    ------	    ------------------
 *     October 20, 1999     Bertrand Lee    base code release
 *
 **********************************************************************
 *
 *     This program is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation; either version 2 of
 *     the License, or (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public
 *     License along with this program; if not, write to the Free
 *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *     USA.
 *
 **********************************************************************
 */

#ifndef _HWACCESS_H
#define _HWACCESS_H

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/sound.h>
#include <linux/malloc.h>
#include <linux/soundcard.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

#include <asm/io.h>
#include <asm/dma.h>

typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#define spin_lock_init(lock) {}
#define spin_lock_irqsave(lock,flags) do { save_flags(flags); cli(); } while (0)
#define spin_unlock_irqrestore(lock,flags) restore_flags(flags)

typedef int (*CALLBACKFN)(unsigned long,unsigned long ,unsigned long);

enum GlobalErrorCode
{
    CTSTATUS_SUCCESS = 0x0000,
    CTSTATUS_ERROR,
    CTSTATUS_INVALIDPARAM,
    CTSTATUS_NOTSUPPORTED,
    CTSTATUS_NOMEMORY,
    CTSTATUS_INVALIDIO,
    CTSTATUS_INVALIDIRQ,
    CTSTATUS_INVALIDDMA,
    CTSTATUS_INVALIDID,
    CTSTATUS_INVALIDVALUE,
    CTSTATUS_BADFORMAT_BITS,
    CTSTATUS_BADFORMAT_RATE,
    CTSTATUS_BADFORMAT_CHANNELS,
    CTSTATUS_INUSE,
    CTSTATUS_STILLPLAYING,
    CTSTATUS_ALLOCATED,
    CTSTATUS_INVALID_FORMAT,
    CTSTATUS_OUT_OF_RESOURCE,
    CTSTATUS_CHIP_INUSE,
    CTSTATUS_NOCHIPRESOURCE,
    CTSTATUS_PORTS_INUSE
};

enum LocalErrorCode
{
    CTSTATUS_NOTENABLED = 0x7000,
    CTSTATUS_READY,
    CTSTATUS_BUSY,
    CTSTATUS_DATAAVAIL,
    CTSTATUS_NODATA,
    CTSTATUS_NEXT_BYTE
};

#define FLAGS_ENABLED       0x0001
#define FLAGS_AVAILABLE     0x0002
#define FLAGS_READY         0x0004
#define FLAGS_CLOSEPENDING  0x0008

/* FIXME: Make this stuff go away please */
#ifndef TRUE
#define TRUE    1
#endif

#ifndef FALSE
#define FALSE   0
#endif

#ifndef NULL
#define NULL    0
#endif

#define _stdcall
#define __cdecl

#define min(x,y) ((x) < (y)) ? (x) : (y)

#define MM_CREATIVE         2
#define MAXPNAMELEN         32      /* max product name length (including NULL) */
#define MAX_CARD_DESC       80

#define MM_CREATIVE_DRIVER_NAME     "SoundBlaster"
#define MM_CREATIVE_DRIVER_VERSION  0x400
#define MM_CREATIVE_MIXER_PID       409
#define MM_CREATIVE_WAVEOUT_PID     104
#define MM_CREATIVE_WAVEIN_PID      4
#define MM_CREATIVE_MIDIOUT_PID     302
#define MM_CREATIVE_MIDIIN_PID      202

#if !defined(DLIST)
#define DLIST(x)    struct {x  *next,  *pPrev;} DList

#define dlAddNode(list,node) \
	  { \
		  (node)->DList.next = *(list); \
		  (node)->DList.pPrev = NULL; \
		  if (*list) (*(list))->DList.pPrev = (node); *(list) = (node); \
	  }

#define dlDelNode(list, node) \
	{ \
	if ((node)->DList.pPrev == NULL) \
	  *(list) = (node)->DList.next; \
	else \
	  ((node)->DList.pPrev)->DList.next = (node)->DList.next; \
	if ((node)->DList.next != NULL) \
	  ((node)->DList.next)->DList.pPrev = (node)->DList.pPrev; \
	(node)->DList.next = (node)->DList.pPrev = NULL; \
}


#define dlFirstNode(list)       (*(list))
#define dlNextNode(curnode)     ((curnode)->DList.next)
#define dlPrevNode(curnode)     ((curnode)->DList.pPrev)
#endif

typedef struct memhandle 
{
	unsigned long physaddx;
	void *virtaddx;
	u32 order;
} LMEMHANDLE, *PLMEMHANDLE;

typedef struct tCTDPC 
{
	CALLBACKFN DPCCallBackFn;
	u32 refdata;
	u32 param;
	int is_active;
} CTDPC,  * PCTDPC;

struct sblive_list 
{
	struct sblive_list  *next;
};

int osAllocMemPhysical(u32, u32 *, void **, unsigned long *);
int osFreeMemPhysical(u32);
int osCopyPageTable(char *, u32, u32, u32 *);
int osListAttach(struct sblive_list **head, struct sblive_list *new);
int osListRemove(struct sblive_list **head, struct sblive_list *pDead);
struct sblive_list *osListGetNext(struct sblive_list *head, struct sblive_list *curr);
int osScheduleDPC(PCTDPC);

#define MAX_MEMREGISTER     1
#define MAX_IOPORT          4
#define MAX_IRQ             2
#define MAX_DMA             2

struct sblive_config
{
    u32 vendorid;			/* Vendor ID			*/
    u32 serialno;			/* Serial number		*/
    u32 logdevid;			/* Logical device ID		*/
    u32 chiprev;			/* Chip revision		*/
    u16 nummemwindows;			/* Number of memory windows	*/
    u32 membase[MAX_MEMREGISTER];	/* Memory window base		*/
    u32 memlength[MAX_MEMREGISTER];	/* Memory window length		*/
    u16 memattrib[MAX_MEMREGISTER];	/* Memory window attributes	*/
    u16 numioports;			/* Number of I/O ports		*/
    u16 ioportbase[MAX_IOPORT];		/* I/O port base		*/
    u16 ioportlenh[MAX_IOPORT];		/* I/O port length		*/
    u16 numirq;				/* Number of IRQs		*/
    u8  IRQregs[MAX_IRQ];		/* IRQ list			*/
    u8  irqattr[MAX_IRQ];		/* IRQ attributes list		*/
    u16 numdma;				/* Number of DMA channels	*/
    u8  dmalst[MAX_DMA];		/* DMA list			*/
    u16 dmaattr[MAX_DMA];		/* DMA attributes list		*/
};

#ifdef EMU10K1_DEBUG
#    define DPD(x,y...) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y )
#    define DPF(x)   printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ )
#else
#  define DPD(x,y...) /* not debugging: nothing */
#  define DPF(x)
#endif /* EMU10K1_DEBUG */


#include "8010.h"

struct sblive_hw;

#include "voicemgr.h"

struct emuaddr_allocdesc
{
    struct sblive_hw *      sb_hw;
    u32     ownertype;
    CALLBACKFN  callback;
    u32     callback_data;
    u32     size;     /* Size in bytes requested */
    u32     flags;    /* stereo/mono  8/16 */
};

struct emu_page
{
    u16  flags;
    struct sblive_hw *sb_hw;
    u32 emustartaddr;
};

struct emu_addrmgr
{
    struct emu_page emupagetable[MAXPAGES];
};

int emu10kaddxmgrInit(struct sblive_hw *);
int emu10kaddxmgrExit(struct sblive_hw *);
int emu10kaddxmgrAlloc(struct emuaddr_allocdesc *,struct emu_page *  *);
int emu10kaddxmgrFree(struct emu_page *);


#include "timer.h"
#include "irqmgr.h"
#include "efxmgr.h"

/* DATA STRUCTURES */

struct sblive_hw 
{
	struct sblive_hw *next, *prev;

	unsigned long         mixeraddx;
	unsigned long         hwconfigaddx;

	u32 *virtualpagetableptr;
	u32 virtualpagetable;
	unsigned long PTBphysaddr;

	u32 *tankmemptr;
	u32 tankmem;
	unsigned long tmemphysaddr;

	u32 *silentpageptr;
	u32 silentpage;
	unsigned long         silentpagephysaddx;

	spinlock_t emu_lock;

	struct voice_mgr  voice_manager;
	struct emu_addrmgr      emu_addrmgr;

	struct emu_timer	*emu_timer;

	struct sblive_irq          hw_irq;

	unsigned long         hwaddr;

	unsigned        numvoices;
	unsigned        awecount;
	u32         tmemsize;
	u32         intrstate;

	unsigned long  joybase;
	struct pci_dev  *pcidev_joy;
	u32         tmemsizeIdx;
	unsigned long          audio_num;
	unsigned long          mixer_num;
	unsigned long          midi_num;
	unsigned long          stat_num;
	struct sblive_waveout *card_waveout;
	struct sblive_wavein *card_wavein;
	struct sblive_mpuout *card_mpuout;
	struct sblive_mpuin *card_mpuin;
	u16          arrwVol[25]; /* Size is hardcoded.  Bad! */
	unsigned int    modcnt;
	struct semaphore  open_sem;
	mode_t            open_mode;
	struct wait_queue *open_wait;


	u8	    paneffectsbus;
	u8	    auxeffectsbus;
	u8	    choruseffectsbus;
	u8	    reverbeffectsbus;

	CALLBACKFN  PCIBusErrorCallback;
	CALLBACKFN  MixerButtonCallback;    // VI,VD,MU bits in IP register
	CALLBACKFN  RecordCallback;	    // AF,AH bits in IP register
	CALLBACKFN  VoiceCallback;	    // CL bits in IP register
	CALLBACKFN  MpuOutCallback;	    // TX bits in IP register
	CALLBACKFN  MpuInCallback;	    // RX bits in IP register
	CALLBACKFN  TimerCallback;	    // IT bit in IP register
	CALLBACKFN  SPDIFCallback;	    // SS & CS bits in IP register
	CALLBACKFN  DSPCallback;	    // DSP bit in IP register

	u32	    pcierrorrefdata;
	u32	    mixerbuttonrefdata;
	u32	    recordrefdata;
	u32	    voicerefdata;
	u32	    mpuoutrefdata;
	u32	    mpuinrefdata;
	u32	    timerrefdata;
	u32	    spdifrefdata;
	u32	    DSPrefdata;

	u32	    powerstate; 	  // Current Power State
	u32	    mpuacqcount;	  // Mpu acquire count
	struct sblive_config	  dsCardCfg;
	u32	    has_toslink;	       // TOSLink detection
};

#define ENABLE 			0xffffffff
#define DISABLE 		0x00000000

#define ENV_ON			0x80
#define ENV_OFF			0x00

/* EMU Irq Types */
#define IRQTYPE_PCIBUSERROR	    IPR_PCIERROR 
#define IRQTYPE_MIXERBUTTON	    (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
#define IRQTYPE_VOICE		    (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
#define IRQTYPE_RECORD		    (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
#define IRQTYPE_MPUOUT		    IPR_MIDITRANSBUFEMPTY 
#define IRQTYPE_MPUIN		    IPR_MIDIRECVBUFEMPTY 
#define IRQTYPE_TIMER		    IPR_INTERVALTIMER 
#define IRQTYPE_SPDIF		    (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
#define IRQTYPE_DSP		    IPR_FXDSP 

#define TIMEOUT 		    16384

u32 srToPitch(u32);
u8 sumVolumeToAttenuation(u32);

int halInit(struct sblive_hw *, struct sblive_config *, u32 *);
int halExit(struct sblive_hw *);

extern u8 gabMsgLenChannel[];
extern u8 gabMsgLenSystem[];

/* Hardware Abstraction Layer access functions */

#define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f))

#define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f)

#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))

void sblive_writefn0(struct sblive_hw *, u8 , u32 );
void sblive_wrtmskfn0(struct sblive_hw *, u8 , u32 , u32 );

u32 sblive_readfn0(struct sblive_hw *, u8 );
u32 sblive_rdmskfn0(struct sblive_hw *, u8, u32 );

void sblive_writeptr(struct sblive_hw *, u32 , u32 , u32 );
u32 sblive_readptr(struct sblive_hw *, u32 , u32 );

void halVoiceIntrEnable(struct sblive_hw *, u32);
void halVoiceIntrDisable(struct sblive_hw *, u32);
void halSetStopOnLoop(struct sblive_hw *, u32);
void halClearStopOnLoop(struct sblive_hw *, u32);
void halWC_WAIT(struct sblive_hw *, u32);

/* AC97 Mixer access function */
int sblive_readac97(struct sblive_hw *, u8, u16 *);
int sblive_writeac97(struct sblive_hw *, u8, u16);
int sblive_rmwac97(struct sblive_hw *, u8, u16, u16);

/* MPU access function*/
int hwmpuWriteData(struct sblive_hw *, u8);
int hwmpuReadData(struct sblive_hw *, u8 *);
int hwmpuReset(struct sblive_hw *);
int hwmpuAcquire(struct sblive_hw *);
int hwmpuRelease(struct sblive_hw *);

#endif  /* _HWACCESS_H */
