⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 via82xx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   ALSA driver for VIA VT82xx (South Bridge) * *   VT82C686A/B/C, VT8233A/C, VT8235 * *	Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> *	                   Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com> *                    2002 Takashi Iwai <tiwai@suse.de> * *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * *//* * Changes: * * Dec. 19, 2002	Takashi Iwai <tiwai@suse.de> *	- use the DSX channels for the first pcm playback. *	  (on VIA8233, 8233C and 8235 only) *	  this will allow you play simultaneously up to 4 streams. *	  multi-channel playback is assigned to the second device *	  on these chips. *	- support the secondary capture (on VIA8233/C,8235) *	- SPDIF support *	  the DSX3 channel can be used for SPDIF output. *	  on VIA8233A, this channel is assigned to the second pcm *	  playback. *	  the card config of alsa-lib will assign the correct *	  device for applications. *	- clean up the code, separate low-level initialization *	  routines for each chipset. * * Sep. 26, 2005	Karsten Wiese <annabellesgarden@yahoo.de> *	- Optimize position calculation for the 823x chips.  */#include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/gameport.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/info.h>#include <sound/tlv.h>#include <sound/ac97_codec.h>#include <sound/mpu401.h>#include <sound/initval.h>#if 0#define POINTER_DEBUG#endifMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");MODULE_DESCRIPTION("VIA VT82xx audio");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}");#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))#define SUPPORT_JOYSTICK 1#endifstatic int index = SNDRV_DEFAULT_IDX1;	/* Index 0-MAX */static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */static long mpu_port;#ifdef SUPPORT_JOYSTICKstatic int joystick;#endifstatic int ac97_clock = 48000;static char *ac97_quirk;static int dxs_support;module_param(index, int, 0444);MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge.");module_param(id, charp, 0444);MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge.");module_param(mpu_port, long, 0444);MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)");#ifdef SUPPORT_JOYSTICKmodule_param(joystick, bool, 0444);MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)");#endifmodule_param(ac97_clock, int, 0444);MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");module_param(ac97_quirk, charp, 0444);MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");module_param(dxs_support, int, 0444);MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)");/* just for backward compatibility */static int enable;module_param(enable, bool, 0444);/* revision numbers for via686 */#define VIA_REV_686_A		0x10#define VIA_REV_686_B		0x11#define VIA_REV_686_C		0x12#define VIA_REV_686_D		0x13#define VIA_REV_686_E		0x14#define VIA_REV_686_H		0x20/* revision numbers for via8233 */#define VIA_REV_PRE_8233	0x10	/* not in market */#define VIA_REV_8233C		0x20	/* 2 rec, 4 pb, 1 multi-pb */#define VIA_REV_8233		0x30	/* 2 rec, 4 pb, 1 multi-pb, spdif */#define VIA_REV_8233A		0x40	/* 1 rec, 1 multi-pb, spdf */#define VIA_REV_8235		0x50	/* 2 rec, 4 pb, 1 multi-pb, spdif */#define VIA_REV_8237		0x60#define VIA_REV_8251		0x70/* *  Direct registers */#define VIAREG(via, x) ((via)->port + VIA_REG_##x)#define VIADEV_REG(viadev, x) ((viadev)->port + VIA_REG_##x)/* common offsets */#define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */#define   VIA_REG_STAT_ACTIVE		0x80	/* RO */#define   VIA8233_SHADOW_STAT_ACTIVE	0x08	/* 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_AUTOSTART	0x20#define   VIA_REG_CTRL_PAUSE		0x08	/* RW */#define   VIA_REG_CTRL_INT_STOP		0x04		#define   VIA_REG_CTRL_INT_EOL		0x02#define   VIA_REG_CTRL_INT_FLAG		0x01#define   VIA_REG_CTRL_RESET		0x01	/* RW - probably reset? undocumented */#define   VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)#define VIA_REG_OFFSET_TYPE		0x02	/* byte - channel type (686 only) */#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_STOP_IDX		0x08	/* dword - stop index, channel type, sample rate */#define   VIA8233_REG_TYPE_16BIT	0x00200000	/* RW */#define   VIA8233_REG_TYPE_STEREO	0x00100000	/* RW */#define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count (24 bit) */#define VIA_REG_OFFSET_CURR_INDEX	0x0f	/* byte - channel current index (for via8233 only) */#define DEFINE_VIA_REGSET(name,val) \enum {\	VIA_REG_##name##_STATUS		= (val),\	VIA_REG_##name##_CONTROL	= (val) + 0x01,\	VIA_REG_##name##_TYPE		= (val) + 0x02,\	VIA_REG_##name##_TABLE_PTR	= (val) + 0x04,\	VIA_REG_##name##_CURR_PTR	= (val) + 0x04,\	VIA_REG_##name##_STOP_IDX	= (val) + 0x08,\	VIA_REG_##name##_CURR_COUNT	= (val) + 0x0c,\}/* playback block */DEFINE_VIA_REGSET(PLAYBACK, 0x00);DEFINE_VIA_REGSET(CAPTURE, 0x10);DEFINE_VIA_REGSET(FM, 0x20);/* 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_CODEC_ID_PRIMARY	0x00#define   VIA_REG_AC97_CODEC_ID_SECONDARY 0x01#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 *//* via686 */#define   VIA_REG_SGD_STAT_PB_FLAG	(1<<0)#define   VIA_REG_SGD_STAT_CP_FLAG	(1<<1)#define   VIA_REG_SGD_STAT_FM_FLAG	(1<<2)#define   VIA_REG_SGD_STAT_PB_EOL	(1<<4)#define   VIA_REG_SGD_STAT_CP_EOL	(1<<5)#define   VIA_REG_SGD_STAT_FM_EOL	(1<<6)#define   VIA_REG_SGD_STAT_PB_STOP	(1<<8)#define   VIA_REG_SGD_STAT_CP_STOP	(1<<9)#define   VIA_REG_SGD_STAT_FM_STOP	(1<<10)#define   VIA_REG_SGD_STAT_PB_ACTIVE	(1<<12)#define   VIA_REG_SGD_STAT_CP_ACTIVE	(1<<13)#define   VIA_REG_SGD_STAT_FM_ACTIVE	(1<<14)/* via8233 */#define   VIA8233_REG_SGD_STAT_FLAG	(1<<0)#define   VIA8233_REG_SGD_STAT_EOL	(1<<1)#define   VIA8233_REG_SGD_STAT_STOP	(1<<2)#define   VIA8233_REG_SGD_STAT_ACTIVE	(1<<3)#define VIA8233_INTR_MASK(chan) ((VIA8233_REG_SGD_STAT_FLAG|VIA8233_REG_SGD_STAT_EOL) << ((chan) * 4))#define   VIA8233_REG_SGD_CHAN_SDX	0#define   VIA8233_REG_SGD_CHAN_MULTI	4#define   VIA8233_REG_SGD_CHAN_REC	6#define   VIA8233_REG_SGD_CHAN_REC1	7#define VIA_REG_GPI_STATUS		0x88#define VIA_REG_GPI_INTR		0x8c/* multi-channel and capture registers for via8233 */DEFINE_VIA_REGSET(MULTPLAY, 0x40);DEFINE_VIA_REGSET(CAPTURE_8233, 0x60);/* via8233-specific registers */#define VIA_REG_OFS_PLAYBACK_VOLUME_L	0x02	/* byte */#define VIA_REG_OFS_PLAYBACK_VOLUME_R	0x03	/* byte */#define VIA_REG_OFS_MULTPLAY_FORMAT	0x02	/* byte - format and channels */#define   VIA_REG_MULTPLAY_FMT_8BIT	0x00#define   VIA_REG_MULTPLAY_FMT_16BIT	0x80#define   VIA_REG_MULTPLAY_FMT_CH_MASK	0x70	/* # channels << 4 (valid = 1,2,4,6) */#define VIA_REG_OFS_CAPTURE_FIFO	0x02	/* byte - bit 6 = fifo  enable */#define   VIA_REG_CAPTURE_FIFO_ENABLE	0x40#define VIA_DXS_MAX_VOLUME		31	/* max. volume (attenuation) of reg 0x32/33 */#define VIA_REG_CAPTURE_CHANNEL		0x63	/* byte - input select */#define   VIA_REG_CAPTURE_CHANNEL_MIC	0x4#define   VIA_REG_CAPTURE_CHANNEL_LINE	0#define   VIA_REG_CAPTURE_SELECT_CODEC	0x03	/* recording source codec (0 = primary) */#define VIA_TBL_BIT_FLAG	0x40000000#define VIA_TBL_BIT_EOL		0x80000000/* pci space */#define VIA_ACLINK_STAT		0x40#define  VIA_ACLINK_C11_READY	0x20#define  VIA_ACLINK_C10_READY	0x10#define  VIA_ACLINK_C01_READY	0x04 /* secondary codec ready */#define  VIA_ACLINK_LOWPOWER	0x02 /* low-power state */#define  VIA_ACLINK_C00_READY	0x01 /* primary codec ready */#define VIA_ACLINK_CTRL		0x41#define  VIA_ACLINK_CTRL_ENABLE	0x80 /* 0: disable, 1: enable */#define  VIA_ACLINK_CTRL_RESET	0x40 /* 0: assert, 1: de-assert */#define  VIA_ACLINK_CTRL_SYNC	0x20 /* 0: release SYNC, 1: force SYNC hi */#define  VIA_ACLINK_CTRL_SDO	0x10 /* 0: release SDO, 1: force SDO hi */#define  VIA_ACLINK_CTRL_VRA	0x08 /* 0: disable VRA, 1: enable VRA */#define  VIA_ACLINK_CTRL_PCM	0x04 /* 0: disable PCM, 1: enable PCM */#define  VIA_ACLINK_CTRL_FM	0x02 /* via686 only */#define  VIA_ACLINK_CTRL_SB	0x01 /* via686 only */#define  VIA_ACLINK_CTRL_INIT	(VIA_ACLINK_CTRL_ENABLE|\				 VIA_ACLINK_CTRL_RESET|\				 VIA_ACLINK_CTRL_PCM|\				 VIA_ACLINK_CTRL_VRA)#define VIA_FUNC_ENABLE		0x42#define  VIA_FUNC_MIDI_PNP	0x80 /* FIXME: it's 0x40 in the datasheet! */#define  VIA_FUNC_MIDI_IRQMASK	0x40 /* FIXME: not documented! */#define  VIA_FUNC_RX2C_WRITE	0x20#define  VIA_FUNC_SB_FIFO_EMPTY	0x10#define  VIA_FUNC_ENABLE_GAME	0x08#define  VIA_FUNC_ENABLE_FM	0x04#define  VIA_FUNC_ENABLE_MIDI	0x02#define  VIA_FUNC_ENABLE_SB	0x01#define VIA_PNP_CONTROL		0x43#define VIA_FM_NMI_CTRL		0x48#define VIA8233_VOLCHG_CTRL	0x48#define VIA8233_SPDIF_CTRL	0x49#define  VIA8233_SPDIF_DX3	0x08#define  VIA8233_SPDIF_SLOT_MASK	0x03#define  VIA8233_SPDIF_SLOT_1011	0x00#define  VIA8233_SPDIF_SLOT_34		0x01#define  VIA8233_SPDIF_SLOT_78		0x02#define  VIA8233_SPDIF_SLOT_69		0x03/* */#define VIA_DXS_AUTO	0#define VIA_DXS_ENABLE	1#define VIA_DXS_DISABLE	2#define VIA_DXS_48K	3#define VIA_DXS_NO_VRA	4#define VIA_DXS_SRC	5/* * pcm stream */struct snd_via_sg_table {	unsigned int offset;	unsigned int size;} ;#define VIA_TABLE_SIZE	255struct viadev {	unsigned int reg_offset;	unsigned long port;	int direction;	/* playback = 0, capture = 1 */        struct snd_pcm_substream *substream;	int running;	unsigned int tbl_entries; /* # descriptors */	struct snd_dma_buffer table;	struct snd_via_sg_table *idx_table;	/* for recovery from the unexpected pointer */	unsigned int lastpos;	unsigned int fragsize;	unsigned int bufsize;	unsigned int bufsize2;	int hwptr_done;		/* processed frame position in the buffer */	int in_interrupt;	int shadow_shift;};enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 };enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A };#define VIA_MAX_DEVS	7	/* 4 playback, 1 multi, 2 capture */struct via_rate_lock {	spinlock_t lock;	int rate;	int used;};struct via82xx {	int irq;	unsigned long port;	struct resource *mpu_res;	int chip_type;	unsigned char revision;	unsigned char old_legacy;	unsigned char old_legacy_cfg;#ifdef CONFIG_PM	unsigned char legacy_saved;	unsigned char legacy_cfg_saved;	unsigned char spdif_ctrl_saved;	unsigned char capture_src_saved[2];	unsigned int mpu_port_saved;#endif	unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */	unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */	unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */	struct pci_dev *pci;	struct snd_card *card;	unsigned int num_devs;	unsigned int playback_devno, multi_devno, capture_devno;	struct viadev devs[VIA_MAX_DEVS];	struct via_rate_lock rates[2]; /* playback and capture */	unsigned int dxs_fixed: 1;	/* DXS channel accepts only 48kHz */	unsigned int no_vra: 1;		/* no need to set VRA on DXS channels */	unsigned int dxs_src: 1;	/* use full SRC capabilities of DXS */	unsigned int spdif_on: 1;	/* only spdif rates work to external DACs */	struct snd_pcm *pcms[2];	struct snd_rawmidi *rmidi;	struct snd_ac97_bus *ac97_bus;	struct snd_ac97 *ac97;	unsigned int ac97_clock;	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */	spinlock_t reg_lock;	struct snd_info_entry *proc_entry;#ifdef SUPPORT_JOYSTICK	struct gameport *gameport;#endif};static struct pci_device_id snd_via82xx_ids[] = {	/* 0x1106, 0x3058 */	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, },	/* 686A */	/* 0x1106, 0x3059 */	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, },	/* VT8233 */	{ 0, }};MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);/* *//* * allocate and initialize the descriptor buffers * periods = number of periods * fragsize = period size in bytes */static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substream,			   struct pci_dev *pci,			   unsigned int periods, unsigned int fragsize){	unsigned int i, idx, ofs, rest;	struct via82xx *chip = snd_pcm_substream_chip(substream);	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);	if (dev->table.area == NULL) {		/* the start of each lists must be aligned to 8 bytes,		 * but the kernel pages are much bigger, so we don't care		 */		if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),					PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8),					&dev->table) < 0)			return -ENOMEM;	}	if (! dev->idx_table) {		dev->idx_table = kmalloc(sizeof(*dev->idx_table) * VIA_TABLE_SIZE, GFP_KERNEL);		if (! dev->idx_table)			return -ENOMEM;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -