/*
 *   ALSA driver for VIA VT82C686A (South Bridge)
 *
 *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
 *
 *   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.
 *
 */      

#include "pcm1.h"
#include "mixer.h"
#include "midi.h"
#include "sndpci.h"
#include "ac97_codec.h"

/*
 *  PCI IDs
 */

#ifndef PCI_VENDOR_ID_VIA
#define PCI_VENDOR_ID_VIA               0x1106
#endif

#ifndef PCI_DEVICE_ID_VIA_82C686_5
#define PCI_DEVICE_ID_VIA_82C686_5      0x3058
#endif

/*
 *  Direct registers
 */

#ifndef PCI_DEVICE_ID_VIA_82C686_5
#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
#endif

#define VIAREG(via, x) ((via)->port + VIA_REG_##x)

/* offsets */
#define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */
#define   VIA_REG_STAT_ACTIVE		0x80	/* RO */
#define   VIA_REG_STAT_PAUSED		0x40	/* RO */
#define   VIA_REG_STAT_TRIGGER_QUEUED	0x08	/* RO */
#define   VIA_REG_STAT_STOPPED		0x04	/* RWC */
#define   VIA_REG_STAT_EOL		0x02	/* RWC */
#define   VIA_REG_STAT_FLAG		0x01	/* RWC */
#define VIA_REG_OFFSET_CONTROL		0x01	/* byte - channel control */
#define   VIA_REG_CTRL_START		0x80	/* WO */
#define   VIA_REG_CTRL_TERMINATE	0x40	/* WO */
#define   VIA_REG_CTRL_PAUSE		0x08	/* RW */
#define   VIA_REG_CTRL_RESET		0x01	/* RW - probably reset? undocumented */
#define VIA_REG_OFFSET_TYPE		0x02	/* byte - channel type */
#define   VIA_REG_TYPE_AUTOSTART	0x80	/* RW - autostart at EOL */
#define   VIA_REG_TYPE_16BIT		0x20	/* RW */
#define   VIA_REG_TYPE_STEREO		0x10	/* RW */
#define   VIA_REG_TYPE_INT_LLINE	0x00
#define   VIA_REG_TYPE_INT_LSAMPLE	0x04
#define   VIA_REG_TYPE_INT_LESSONE	0x08
#define   VIA_REG_TYPE_INT_MASK		0x0c
#define   VIA_REG_TYPE_INT_EOL		0x02
#define   VIA_REG_TYPE_INT_FLAG		0x01
#define VIA_REG_OFFSET_TABLE_PTR	0x04	/* dword - channel table pointer */
#define VIA_REG_OFFSET_CURR_PTR		0x04	/* dword - channel current pointer */
#define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count */
/* playback block */
#define VIA_REG_PLAYBACK_STATUS		0x00	/* byte - channel status */
#define VIA_REG_PLAYBACK_CONTROL	0x01	/* byte - channel control */
#define VIA_REG_PLAYBACK_TYPE		0x02	/* byte - channel type */
#define VIA_REG_PLAYBACK_TABLE_PTR	0x04	/* dword - channel table pointer */
#define VIA_REG_PLAYBACK_CURR_PTR	0x04	/* dword - channel current pointer */
#define VIA_REG_PLAYBACK_CURR_COUNT	0x0c	/* dword - channel current count */
/* capture block */
#define VIA_REG_CAPTURE_STATUS		0x10	/* byte - channel status */
#define VIA_REG_CAPTURE_CONTROL		0x11	/* byte - channel control */
#define VIA_REG_CAPTURE_TYPE		0x12	/* byte - channel type */
#define VIA_REG_CAPTURE_TABLE_PTR	0x14	/* dword - channel table pointer */
#define VIA_REG_CAPTURE_CURR_PTR	0x14	/* dword - channel current pointer */
#define VIA_REG_CAPTURE_CURR_COUNT	0x1c	/* dword - channel current count */
/* FM block */
#define VIA_REG_FM_STATUS		0x20	/* byte - channel status */
#define VIA_REG_FM_CONTROL		0x21	/* byte - channel control */
#define VIA_REG_FM_TYPE			0x22	/* byte - channel type */
#define VIA_REG_FM_TABLE_PTR		0x24	/* dword - channel table pointer */
#define VIA_REG_FM_CURR_PTR		0x24	/* dword - channel current pointer */
#define VIA_REG_FM_CURR_COUNT		0x2c	/* dword - channel current count */
/* AC'97 */
#define VIA_REG_AC97			0x80	/* dword */
#define   VIA_REG_AC97_CODEC_ID_MASK	(3<<30)
#define   VIA_REG_AC97_CODEC_ID_SHIFT	30
#define   VIA_REG_AC97_SECONDARY_VALID	(1<<27)
#define   VIA_REG_AC97_PRIMARY_VALID	(1<<25)
#define   VIA_REG_AC97_BUSY		(1<<24)
#define   VIA_REG_AC97_READ		(1<<23)
#define   VIA_REG_AC97_CMD_SHIFT	16
#define   VIA_REG_AC97_CMD_MASK		0x7e
#define   VIA_REG_AC97_DATA_SHIFT	0
#define   VIA_REG_AC97_DATA_MASK	0xffff
#define VIA_REG_SGD_SHADOW		0x84	/* dword */

/*
 *  
 */

typedef struct {
	unsigned int reg_offset;
	unsigned int *table;
	unsigned int min_rate;
	unsigned int max_rate;
	snd_pcm1_t *pcm1;
	unsigned long physbuf;
	unsigned int size;
	unsigned int fragsize;
	unsigned int position;
} viadev_t;

typedef struct snd_stru_via686a via686a_t;

struct snd_stru_via686a {
	snd_dma_t * dma_pbk;	/* playback */
	snd_dma_t * dma_rec;	/* capture */
	snd_dma_t * dma_fm;	/* FM playback */
	snd_irq_t * irqptr;

	unsigned int port;
	unsigned char revision;

	struct snd_pci_dev *pci;
	snd_card_t *card;

	snd_pcm_t *pcm;
	snd_pcm_t *pcm_fm;
	viadev_t playback;
	viadev_t record;
	viadev_t playback_fm;

	ac97_t *ac97;
	unsigned short ac97_ext_id;
	snd_kmixer_t *mixer;

	snd_mutex_define(reg_lock);
	snd_info_entry_t *proc_entry;

	void *tables;
};

int snd_via686a_detect(snd_card_t *card, struct snd_pci_dev *pci, int pci_index, int device);
int alsa_card_via686a_init(void);
void alsa_card_via686a_cleanup(void);
