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

📄 emu10k1x.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> *  Driver EMU10K1X chips * *  Parts of this code were adapted from audigyls.c driver which is *  Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> * *  BUGS: *    -- * *  TODO: * *  Chips (SB0200 model): *    - EMU10K1X-DBQ *    - STAC 9708T * *   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 * */#include <sound/driver.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/initval.h>#include <sound/pcm.h>#include <sound/ac97_codec.h>#include <sound/info.h>#include <sound/rawmidi.h>MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>");MODULE_DESCRIPTION("EMU10K1X");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Dell Creative Labs,SB Live!}");// module parameters (see "Module Parameters")static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for the EMU10K1X soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for the EMU10K1X soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");// some definitions were borrowed from emu10k1 driver as they seem to be the same/************************************************************************************************//* PCI function 0 registers, address = <val> + PCIBASE0						*//************************************************************************************************/#define PTR			0x00		/* Indexed register set pointer register	*/						/* NOTE: The CHANNELNUM and ADDRESS words can	*/						/* be modified independently of each other.	*/#define DATA			0x04		/* Indexed register set data register		*/#define IPR			0x08		/* Global interrupt pending register		*/						/* Clear pending interrupts by writing a 1 to	*/						/* the relevant bits and zero to the other bits	*/#define IPR_MIDITRANSBUFEMPTY   0x00000001	/* MIDI UART transmit buffer empty		*/#define IPR_MIDIRECVBUFEMPTY    0x00000002	/* MIDI UART receive buffer empty		*/#define IPR_CH_0_LOOP           0x00000800      /* Channel 0 loop                               */#define IPR_CH_0_HALF_LOOP      0x00000100      /* Channel 0 half loop                          */#define IPR_CAP_0_LOOP          0x00080000      /* Channel capture loop                         */#define IPR_CAP_0_HALF_LOOP     0x00010000      /* Channel capture half loop                    */#define INTE			0x0c		/* Interrupt enable register			*/#define INTE_MIDITXENABLE       0x00000001	/* Enable MIDI transmit-buffer-empty interrupts	*/#define INTE_MIDIRXENABLE       0x00000002	/* Enable MIDI receive-buffer-empty interrupts	*/#define INTE_CH_0_LOOP          0x00000800      /* Channel 0 loop                               */#define INTE_CH_0_HALF_LOOP     0x00000100      /* Channel 0 half loop                          */#define INTE_CAP_0_LOOP         0x00080000      /* Channel capture loop                         */#define INTE_CAP_0_HALF_LOOP    0x00010000      /* Channel capture half loop                    */#define HCFG			0x14		/* Hardware config register			*/#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache */						/* NOTE: This should generally never be used.  	*/#define HCFG_AUDIOENABLE	0x00000001	/* 0 = CODECs transmit zero-valued samples	*/						/* Should be set to 1 when the EMU10K1 is	*/						/* completely initialized.			*/#define GPIO			0x18		/* Defaults: 00001080-Analog, 00001000-SPDIF.   */#define AC97DATA		0x1c		/* AC97 register set data register (16 bit)	*/#define AC97ADDRESS		0x1e		/* AC97 register set address register (8 bit)	*//********************************************************************************************************//* Emu10k1x pointer-offset register set, accessed through the PTR and DATA registers			*//********************************************************************************************************/#define PLAYBACK_LIST_ADDR	0x00		/* Base DMA address of a list of pointers to each period/size */						/* One list entry: 4 bytes for DMA address, 						 * 4 bytes for period_size << 16.						 * One list entry is 8 bytes long.						 * One list entry for each period in the buffer.						 */#define PLAYBACK_LIST_SIZE	0x01		/* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000  */#define PLAYBACK_LIST_PTR	0x02		/* Pointer to the current period being played */#define PLAYBACK_DMA_ADDR	0x04		/* Playback DMA addresss */#define PLAYBACK_PERIOD_SIZE	0x05		/* Playback period size */#define PLAYBACK_POINTER	0x06		/* Playback period pointer. Sample currently in DAC */#define PLAYBACK_UNKNOWN1       0x07#define PLAYBACK_UNKNOWN2       0x08/* Only one capture channel supported */#define CAPTURE_DMA_ADDR	0x10		/* Capture DMA address */#define CAPTURE_BUFFER_SIZE	0x11		/* Capture buffer size */#define CAPTURE_POINTER		0x12		/* Capture buffer pointer. Sample currently in ADC */#define CAPTURE_UNKNOWN         0x13/* From 0x20 - 0x3f, last samples played on each channel */#define TRIGGER_CHANNEL         0x40            /* Trigger channel playback                     */#define TRIGGER_CHANNEL_0       0x00000001      /* Trigger channel 0                            */#define TRIGGER_CHANNEL_1       0x00000002      /* Trigger channel 1                            */#define TRIGGER_CHANNEL_2       0x00000004      /* Trigger channel 2                            */#define TRIGGER_CAPTURE         0x00000100      /* Trigger capture channel                      */#define ROUTING                 0x41            /* Setup sound routing ?                        */#define ROUTING_FRONT_LEFT      0x00000001#define ROUTING_FRONT_RIGHT     0x00000002#define ROUTING_REAR_LEFT       0x00000004#define ROUTING_REAR_RIGHT      0x00000008#define ROUTING_CENTER_LFE      0x00010000#define SPCS0			0x42		/* SPDIF output Channel Status 0 register	*/#define SPCS1			0x43		/* SPDIF output Channel Status 1 register	*/#define SPCS2			0x44		/* SPDIF output Channel Status 2 register	*/#define SPCS_CLKACCYMASK	0x30000000	/* Clock accuracy				*/#define SPCS_CLKACCY_1000PPM	0x00000000	/* 1000 parts per million			*/#define SPCS_CLKACCY_50PPM	0x10000000	/* 50 parts per million				*/#define SPCS_CLKACCY_VARIABLE	0x20000000	/* Variable accuracy				*/#define SPCS_SAMPLERATEMASK	0x0f000000	/* Sample rate					*/#define SPCS_SAMPLERATE_44	0x00000000	/* 44.1kHz sample rate				*/#define SPCS_SAMPLERATE_48	0x02000000	/* 48kHz sample rate				*/#define SPCS_SAMPLERATE_32	0x03000000	/* 32kHz sample rate				*/#define SPCS_CHANNELNUMMASK	0x00f00000	/* Channel number				*/#define SPCS_CHANNELNUM_UNSPEC	0x00000000	/* Unspecified channel number			*/#define SPCS_CHANNELNUM_LEFT	0x00100000	/* Left channel					*/#define SPCS_CHANNELNUM_RIGHT	0x00200000	/* Right channel				*/#define SPCS_SOURCENUMMASK	0x000f0000	/* Source number				*/#define SPCS_SOURCENUM_UNSPEC	0x00000000	/* Unspecified source number			*/#define SPCS_GENERATIONSTATUS	0x00008000	/* Originality flag (see IEC-958 spec)		*/#define SPCS_CATEGORYCODEMASK	0x00007f00	/* Category code (see IEC-958 spec)		*/#define SPCS_MODEMASK		0x000000c0	/* Mode (see IEC-958 spec)			*/#define SPCS_EMPHASISMASK	0x00000038	/* Emphasis					*/#define SPCS_EMPHASIS_NONE	0x00000000	/* No emphasis					*/#define SPCS_EMPHASIS_50_15	0x00000008	/* 50/15 usec 2 channel				*/#define SPCS_COPYRIGHT		0x00000004	/* Copyright asserted flag -- do not modify	*/#define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/#define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/#define SPDIF_SELECT		0x45		/* Enables SPDIF or Analogue outputs 0-Analogue, 0x700-SPDIF *//* This is the MPU port on the card                      					*/#define MUDATA		0x47#define MUCMD		0x48#define MUSTAT		MUCMD/* From 0x50 - 0x5f, last samples captured *//** * The hardware has 3 channels for playback and 1 for capture. *  - channel 0 is the front channel *  - channel 1 is the rear channel *  - channel 2 is the center/lfe chanel * Volume is controlled by the AC97 for the front and rear channels by * the PCM Playback Volume, Sigmatel Surround Playback Volume and  * Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects * the front/rear channel mixing in the REAR OUT jack. When using the * 4-Speaker Stereo, both front and rear channels will be mixed in the * REAR OUT. * The center/lfe channel has no volume control and cannot be muted during * playback. */typedef struct snd_emu10k1x_voice emu10k1x_voice_t;typedef struct snd_emu10k1x emu10k1x_t;typedef struct snd_emu10k1x_pcm emu10k1x_pcm_t;struct snd_emu10k1x_voice {	emu10k1x_t *emu;	int number;	int use;  	emu10k1x_pcm_t *epcm;};struct snd_emu10k1x_pcm {	emu10k1x_t *emu;	snd_pcm_substream_t *substream;	emu10k1x_voice_t *voice;	unsigned short running;};typedef struct {	struct snd_emu10k1x *emu;	snd_rawmidi_t *rmidi;	snd_rawmidi_substream_t *substream_input;	snd_rawmidi_substream_t *substream_output;	unsigned int midi_mode;	spinlock_t input_lock;	spinlock_t output_lock;	spinlock_t open_lock;	int tx_enable, rx_enable;	int port;	int ipr_tx, ipr_rx;	void (*interrupt)(emu10k1x_t *emu, unsigned int status);} emu10k1x_midi_t;// definition of the chip-specific recordstruct snd_emu10k1x {	snd_card_t *card;	struct pci_dev *pci;	unsigned long port;	struct resource *res_port;	int irq;	unsigned int revision;		/* chip revision */	unsigned int serial;            /* serial number */	unsigned short model;		/* subsystem id */	spinlock_t emu_lock;	spinlock_t voice_lock;	ac97_t *ac97;	snd_pcm_t *pcm;	emu10k1x_voice_t voices[3];	emu10k1x_voice_t capture_voice;	u32 spdif_bits[3]; // SPDIF out setup	struct snd_dma_buffer dma_buffer;	emu10k1x_midi_t midi;};/* hardware definition */static snd_pcm_hardware_t snd_emu10k1x_playback_hw = {	.info =			(SNDRV_PCM_INFO_MMAP | 				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(32*1024),	.period_bytes_min =	64,	.period_bytes_max =	(16*1024),	.periods_min =		2,	.periods_max =		8,	.fifo_size =		0,};static snd_pcm_hardware_t snd_emu10k1x_capture_hw = {	.info =			(SNDRV_PCM_INFO_MMAP | 				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_48000,	.rate_min =		48000,	.rate_max =		48000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	(32*1024),	.period_bytes_min =	64,	.period_bytes_max =	(16*1024),	.periods_min =		2,	.periods_max =		2,	.fifo_size =		0,};static unsigned int snd_emu10k1x_ptr_read(emu10k1x_t * emu, 					  unsigned int reg, 					  unsigned int chn){	unsigned long flags;	unsigned int regptr, val;  	regptr = (reg << 16) | chn;	spin_lock_irqsave(&emu->emu_lock, flags);	outl(regptr, emu->port + PTR);	val = inl(emu->port + DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);	return val;}static void snd_emu10k1x_ptr_write(emu10k1x_t *emu, 				   unsigned int reg, 				   unsigned int chn, 				   unsigned int data){	unsigned int regptr;	unsigned long flags;	regptr = (reg << 16) | chn;	spin_lock_irqsave(&emu->emu_lock, flags);	outl(regptr, emu->port + PTR);	outl(data, emu->port + DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);}static void snd_emu10k1x_intr_enable(emu10k1x_t *emu, unsigned int intrenb){	unsigned long flags;	unsigned int enable;  	spin_lock_irqsave(&emu->emu_lock, flags);	enable = inl(emu->port + INTE) | intrenb;	outl(enable, emu->port + INTE);	spin_unlock_irqrestore(&emu->emu_lock, flags);}static void snd_emu10k1x_intr_disable(emu10k1x_t *emu, unsigned int intrenb){	unsigned long flags;	unsigned int enable;  	spin_lock_irqsave(&emu->emu_lock, flags);	enable = inl(emu->port + INTE) & ~intrenb;	outl(enable, emu->port + INTE);	spin_unlock_irqrestore(&emu->emu_lock, flags);}static void snd_emu10k1x_gpio_write(emu10k1x_t *emu, unsigned int value){	unsigned long flags;	spin_lock_irqsave(&emu->emu_lock, flags);	outl(value, emu->port + GPIO);	spin_unlock_irqrestore(&emu->emu_lock, flags);}static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime){	kfree(runtime->private_data);}static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice){	emu10k1x_pcm_t *epcm;	if ((epcm = voice->epcm) == NULL)		return;	if (epcm->substream == NULL)		return;#if 0	snd_printk(KERN_INFO "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n",		   epcm->substream->ops->pointer(epcm->substream),		   snd_pcm_lib_period_bytes(epcm->substream),		   snd_pcm_lib_buffer_bytes(epcm->substream));#endif	snd_pcm_period_elapsed(epcm->substream);}/* open callback */static int snd_emu10k1x_playback_open(snd_pcm_substream_t *substream){	emu10k1x_t *chip = snd_pcm_substream_chip(substream);	emu10k1x_pcm_t *epcm;	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {		return err;	}	if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0)                return err;	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);	if (epcm == NULL)		return -ENOMEM;	epcm->emu = chip;	epcm->substream = substream;  	runtime->private_data = epcm;	runtime->private_free = snd_emu10k1x_pcm_free_substream;  	runtime->hw = snd_emu10k1x_playback_hw;	return 0;}

⌨️ 快捷键说明

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