/**********************************************************************
*
*  nvhw.h
*
*  Descripion  - Header file used for the common structures
*
*  Copyright (c) 2002-2003 NVIDIA Corporation
*
***********************************************************************
*/
#ifndef _NVHW_H_
#define _NVHW_H_

#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/ac97_codec.h>
#include <linux/wrapper.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>

#include "chaninfo.h"
#include "nvioctl.h"

//#define DRIVER_VERSION "1.0-0262"

/*number of channels supported */
#define NR_HW_CH   3

/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
#define NR_AC97    2

#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
#define DMABUF_MINORDER 1


#define Nvaudio_MODULE_NAME "Nvaudio"

#ifdef CONFIG_PM
#define PM_SUSPENDED(card) (card->pm_suspended)
#else
#define PM_SUSPENDED(card) (0)
#endif

#define AC97REG_SIGMATEL_ID1       0x8384  // "ST"
#define AC97REG_SIGMATEL_ID2       0x7608  // "E"

#define AC97REG_ADI1885_ID1        0x4144  
#define AC97REG_ADI1885_ID2        0x5360  

#define AC97_ADI_MULTICHN          0x74
#define ADI_FRONTSPKRS             0x1000
#define ADI_CENLFESPKRS            0x2000
#define ADI_SURRSPKRS              0x5000


#define AC97_SIGMATEL_MULTICHN     0x74	/* Multi-Channel programming */
#define AC97_SIGMATEL_CIC1         0x76
#define AC97_SIGMATEL_CIC2         0x78

#define REALTEK_MULTI_CHANNEL      0x6A
#define REALTEK_SWAP_MICIN         0x0400
#define REALTEK_SWAP_LINEIN        0x0200

#define AC97_MICBOOST_MASK         0x0040
#define PREMIX_COUNT               0x6
#define PREMIX_MIN                 0x1F
#define PREMIX_RIGHTMIN            0x001F
#define PREMIX_LEFTMIN             0x1F00
 
#define NO_SECONDARY               0x0
#define SIGMATEL_SECONDARY         0x1

#define CHANNEL_STEREO             0x2 
#define CHANNEL_QUAD               0x4
#define CHANNEL_51                 0x6

#define TRUE    1
#define FALSE   0
  
#define SAMPLERATE_48K   48000
 
#define MAXVOLRANGE  32767
#define MINVOLRANGE -32768
#define RANGECHECK(val,min,max) { if (val < min) val = min; else if(val > max ) val=max;}
#define RECHECK_DMA(val,min,max) {if(val > max) { printk(KERN_ERR" LOOP OVER \n"); val = min;}}

typedef struct ListNode* nodePtr;
typedef struct ListNode
{
  char  *data;       /* data buffer */
  int   position;    /* position of data */
  int   analogposn;  /* to keep track of analog posn in copy */
  int   digitalposn; /* to keep track of digital posn in copy */
  int   size;        /* size of out buffer */
  int   wavoutused;  /* wavout used or not */
  int   spoutused;   /* spout used or not */
  nodePtr next;      /* next node to the list */
} listnode;

typedef struct LList *listPtr;
typedef struct LList
{
  nodePtr head;         /* Head in the List */
  nodePtr tail;         /* Tail in the List */
  nodePtr curnode;      /* curnode in the List */
  nodePtr newnode;      /* current one in process */
  nodePtr wavoutnode;   /* wavout write node */
  nodePtr spoutnode;    /* spout write node */
  int     nodecount;    /* total node count */
  int     wavoutcount;  /* wave nodes in the list */
  int     spoutcount;   /* sp nodes in the list */
} llist;

struct Nvaudio_channel
{
    /* these sg guys should probably be allocated
    seperately as nocache. Must be 8 byte aligned */
    struct sg_item sg[SG_LEN];  /* 32*8 */
};


/* This struct keep all the dma info */
struct dmabuf {
        /* OSS buffer management stuff */
        void *rawbuf;
        dma_addr_t dma_handle;
        unsigned buforder;
        unsigned numfrag;
        unsigned fragshift;

        /* our buffer acts like a circular ring */
        unsigned hwptr;         /* where dma last started, updated by update_ptr */
        unsigned swptr;         /* where driver last clear/filled, updated by read/write */
        int count;              /* bytes to be consumed or been generated by dma machine */
        unsigned total_bytes;   /* total bytes dmaed by hardware */

        unsigned error;         /* number of over/underruns */
        wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */

        /* redundant, but makes calculations easier */
        /* what the hardware uses */
        unsigned dmasize;
        unsigned fragsize;
        unsigned fragsamples;

        /* what we tell the user to expect */
        unsigned userfrags;
        unsigned userfragsize;

        /* OSS stuff */
        unsigned update_flag;
        unsigned ossfragsize;
        unsigned ossmaxfrags;
        unsigned subdivision;
    };

/* This structure keep all the info needed for each channel*/

struct Nvaudio_state{

    struct Nvaudio_card *card;  /* Card info */
	spinlock_t lock;

    /* single open lock mechanism, only used for recording */
    struct semaphore open_sem;
    wait_queue_head_t open_wait;

    /* file mode */
    mode_t open_mode;


#ifdef CONFIG_PM
    unsigned int pm_saved_adc_rate;
    unsigned int pm_saved_dac_rate;
    unsigned int pm_saved_spdif_rate;
#endif

    /* wave sample stuff */
    unsigned int  rate;
    unsigned char fmt;
    unsigned char trigger;
    unsigned char enable;

    unsigned mapped:1;
    unsigned ready:1;
    unsigned spdif_enable:1;
    struct dmabuf  dmabuffer;
};

struct Nvaudio_card {

    unsigned int magic;
    /* We keep Nvaudio cards in a linked list */
    struct Nvaudio_card *next;

    spinlock_t lock;

    /* PCI device stuff */
    struct pci_dev * pci_dev;
    u16 pci_id;

#ifdef CONFIG_PM
    u16 pm_suspended;
    u32 pm_save_state[64/sizeof(u32)];
    int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
#endif

    /* soundcore stuff */
    int dev_audio;

    /* structures for abstraction of hardware facilities, codecs, banks and channels*/
    struct ac97_codec *ac97_codec[NR_AC97];
    struct Nvaudio_state   *wavin;
    struct Nvaudio_state   *wavout;
    struct Nvaudio_state   *spout;

    /* for the prdlist physical addr */
    struct Nvaudio_channel *channel;
    dma_addr_t chandma;

    u16 ac97_features;
    u16 ac97_status;
    u16 channels;

    /* hardware resources */
    unsigned long iobase;
    unsigned long ac97base;
    u32 irq;

    /* Function support */
    u32 wavoutused;
    u32 wavinused;
    u32 spdifused;

    u32 ac3passthrough;
    u32 verifyac3;
    u32 numchannels;

    int waveformat;
    int codecsec;
    int spkrselect;
    int curspkr;
    int codecType;

    /* Params for SRC */
    float ncurstepsize;
    float nCurTimeFract;
    float nCurTimeInt;
    float nCurbuffStep;
    listPtr outList;

    int micboost;
    int analogstate;
    int digitalstate;
    int premix_volume[PREMIX_COUNT];
    int mastermute;
    /* We have a *very* long init time possibly, so use this to block */
    /* attempts to open our devices before we are ready (stops oops'es) */
    int initializing;
};

u16  Nvaudio_ac97_get(struct ac97_codec *dev, u8 reg);
void Nvaudio_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
int  alloc_dmabuf(struct Nvaudio_state *state);
void dealloc_dmabuf(struct Nvaudio_state *state);
int  prog_dmabuf(struct Nvaudio_state *state,unsigned rec);
void Nvaudio_SetSpkrRegister(struct Nvaudio_card* card);
int  Nvaudio_MultiChannel_volume(struct Nvaudio_card* card, int channel);
int  Nvaudio_Recalfreespace(struct Nvaudio_card* card,int cnt);

/* Functions that help for mixdown */
u32  Nvaudio_MixDown5_1ToStereo(const char* pIn,struct Nvaudio_state *state,int cnt,int carrylimit,int bSpdif);
u32  Nvaudio_MixDown5_1ToQuad(const char* pIn,struct Nvaudio_state *state,int cnt,int carrylimit,int bSpdif);
u32  Nvaudio_MixDownQuadToStereo(const char* pIn,struct Nvaudio_state *state,int cnt,int carrylimit,int bSpdif);
u32  Nvaudio_MixNormal(const char* pIn,struct Nvaudio_state *state,int cnt,int carrylimit,int bSpdif);
u32  Nvaudio_UseLeftOverToQuad(short** pIn, short** pOut,struct dmabuf *dmabuf, int loopend,int carrylimit, u32* StartIndex, int bSpdif);
u32  Nvaudio_UseLeftOver(short** pIn, short** pOut,struct dmabuf *dmabuf, int loopend, int carrylimit, u32* StartIndex, int bSpdif, int ToQuad);
void Nvaudio_StoreLeftOver(int loop, int loopend, short** pSrc, int bSpdif);
long Nvaudio_MixDown( long channel, long center, long lfe, long schannel);

/* Function for Replicate the waves*/
u32  Nvaudio_UseLeftOverToStereo(short** pIn, short** pOut,struct dmabuf *dmabuf, int loopend,int carrylimit, u32* StartIndex);
u32  Nvaudio_ReplicateStereotoRear(const char* pIn,struct Nvaudio_state *state,int cnt,int carrylimit);

/* Set/Get the premix volume registers */
int Nvaudio_getpremix_volume(struct Nvaudio_card* card, int premixreg, int *pmute);
int Nvaudio_setpremix_volume(struct Nvaudio_card* card, int premixreg, int value);
int Nvaudio_set_mixermute(struct Nvaudio_card* card,int regIndex, int value);
int Nvaudio_get_mixermute(struct Nvaudio_card* card,int regIndex);

/*Function to set the bus master properly */
int Nvaudio_setbusmaster(struct Nvaudio_card* card,int index, int value);

/* Function to get/set swap linein & micIn */
int Nvaudio_getswapinfo(struct Nvaudio_card *card, int index);
int Nvaudio_setswapinfo(struct Nvaudio_card *card, int index, int value);

/* function to get the device info */
int Nvaudio_getinfo(struct Nvaudio_card* card, int index, char *name);

/* function to apply linear SRC and linklist allocation*/
nodePtr Nvaudio_deletenode(struct Nvaudio_card *card);
nodePtr Nvaudio_allocatenode(struct Nvaudio_card *card,int prdsize);
void    Nvaudio_resetnode(struct Nvaudio_card *card);
char*   Nvaudio_linearSRC(struct Nvaudio_card *card, const char *pInBuffer, int cnt);
int     Nvaudio_outbuffersize( struct Nvaudio_card *card, int buffersize);
int     Nvaudio_copydatatowavprd(struct Nvaudio_card *card,int cnt);
int     Nvaudio_copydatatospprd(struct Nvaudio_card *card,int count);

#endif /* _NVHW_H_ */



