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

📄 ca0106_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit *  Version: 0.0.23 * *  FEATURES currently supported: *    Front, Rear and Center/LFE. *    Surround40 and Surround51. *    Capture from MIC an LINE IN input. *    SPDIF digital playback of PCM stereo and AC3/DTS works. *    (One can use a standard mono mini-jack to one RCA plugs cable. *     or one can use a standard stereo mini-jack to two RCA plugs cable. *     Plug one of the RCA plugs into the Coax input of the external decoder/receiver.) *    ( In theory one could output 3 different AC3 streams at once, to 3 different SPDIF outputs. ) *    Notes on how to capture sound: *      The AC97 is used in the PLAYBACK direction. *      The output from the AC97 chip, instead of reaching the speakers, is fed into the Philips 1361T ADC. *      So, to record from the MIC, set the MIC Playback volume to max, *      unmute the MIC and turn up the MASTER Playback volume. *      So, to prevent feedback when capturing, minimise the "Capture feedback into Playback" volume. *    *    The only playback controls that currently do anything are: - *    Analog Front *    Analog Rear *    Analog Center/LFE *    SPDIF Front *    SPDIF Rear *    SPDIF Center/LFE *    *    For capture from Mic in or Line in. *    Digital/Analog ( switch must be in Analog mode for CAPTURE. ) *  *    CAPTURE feedback into PLAYBACK *  *  Changelog: *    Support interrupts per period. *    Removed noise from Center/LFE channel when in Analog mode. *    Rename and remove mixer controls. *  0.0.6 *    Use separate card based DMA buffer for periods table list. *  0.0.7 *    Change remove and rename ctrls into lists. *  0.0.8 *    Try to fix capture sources. *  0.0.9 *    Fix AC3 output. *    Enable S32_LE format support. *  0.0.10 *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".) *  0.0.11 *    Add Model name recognition. *  0.0.12 *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period. *    Remove redundent "voice" handling. *  0.0.13 *    Single trigger call for multi channels. *  0.0.14 *    Set limits based on what the sound card hardware can do. *    playback periods_min=2, periods_max=8 *    capture hw constraints require period_size = n * 64 bytes. *    playback hw constraints require period_size = n * 64 bytes. *  0.0.15 *    Minor updates. *  0.0.16 *    Implement 192000 sample rate. *  0.0.17 *    Add support for SB0410 and SB0413. *  0.0.18 *    Modified Copyright message. *  0.0.19 *    Finally fix support for SB Live 24 bit. SB0410 and SB0413. *    The output codec needs resetting, otherwise all output is muted. *  0.0.20 *    Merge "pci_disable_device(pci);" fixes. *  0.0.21 *    Add 4 capture channels. (SPDIF only comes in on channel 0. ) *    Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) *  0.0.22 *    Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 *  0.0.23 *    Implement support for Line-in capture on SB Live 24bit. * *  BUGS: *    Some stability problems when unloading the snd-ca0106 kernel module. *    -- * *  TODO: *    4 Capture channels, only one implemented so far. *    Other capture rates apart from 48khz not implemented. *    MIDI *    -- *  GENERAL INFO: *    Model: SB0310 *    P17 Chip: CA0106-DAT *    AC97 Codec: STAC 9721 *    ADC: Philips 1361T (Stereo 24bit) *    DAC: WM8746EDS (6-channel, 24bit, 192Khz) * *  GENERAL INFO: *    Model: SB0410 *    P17 Chip: CA0106-DAT *    AC97 Codec: None *    ADC: WM8775EDS (4 Channel) *    DAC: CS4382 (114 dB, 24-Bit, 192 kHz, 8-Channel D/A Converter with DSD Support) *    SPDIF Out control switches between Mic in and SPDIF out. *    No sound out or mic input working yet. *  *  GENERAL INFO: *    Model: SB0413 *    P17 Chip: CA0106-DAT *    AC97 Codec: None. *    ADC: Unknown *    DAC: Unknown *    Trying to handle it like the SB0410. * *  This code was initally based on code from ALSA's emu10k1x.c which is: *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * *   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/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/moduleparam.h>#include <linux/dma-mapping.h>#include <sound/core.h>#include <sound/initval.h>#include <sound/pcm.h>#include <sound/ac97_codec.h>#include <sound/info.h>MODULE_AUTHOR("James Courtier-Dutton <James@superbug.demon.co.uk>");MODULE_DESCRIPTION("CA0106");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}");// 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 CA0106 soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for the CA0106 soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard.");#include "ca0106.h"static ca0106_details_t ca0106_chip_details[] = {	 /* AudigyLS[SB0310] */	 { .serial = 0x10021102,	   .name   = "AudigyLS [SB0310]",	   .ac97   = 1 } , 	 /* Unknown AudigyLS that also says SB0310 on it */	 { .serial = 0x10051102,	   .name   = "AudigyLS [SB0310b]",	   .ac97   = 1 } ,	 /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */	 { .serial = 0x10061102,	   .name   = "Live! 7.1 24bit [SB0410]",	   .gpio_type = 1,	   .i2c_adc = 1 } ,	 /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */	 { .serial = 0x10071102,	   .name   = "Live! 7.1 24bit [SB0413]",	   .gpio_type = 1,	   .i2c_adc = 1 } ,	 /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */	 { .serial = 0x10091462,	   .name   = "MSI K8N Diamond MB [SB0438]",	   .gpio_type = 1,	   .i2c_adc = 1 } ,	 /* Shuttle XPC SD31P which has an onboard Creative Labs Sound Blaster Live! 24-bit EAX	  * high-definition 7.1 audio processor".	  * Added using info from andrewvegan in alsa bug #1298	  */	 { .serial = 0x30381297,	   .name   = "Shuttle XPC SD31P [SD31P]",	   .gpio_type = 1,	   .i2c_adc = 1 } ,	 { .serial = 0,	   .name   = "AudigyLS [Unknown]" }};/* hardware definition */static snd_pcm_hardware_t snd_ca0106_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 | SNDRV_PCM_FMTBIT_S32_LE,	.rates =		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,	.rate_min =		48000,	.rate_max =		192000,	.channels_min =		2,  //1,	.channels_max =		2,  //6,	.buffer_bytes_max =	((65536 - 64) * 8),	.period_bytes_min =	64,	.period_bytes_max =	(65536 - 64),	.periods_min =		2,	.periods_max =		8,	.fifo_size =		0,};static snd_pcm_hardware_t snd_ca0106_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 | SNDRV_PCM_FMTBIT_S32_LE,	.rates =		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,	.rate_min =		44100,	.rate_max =		192000,	.channels_min =		2,	.channels_max =		2,	.buffer_bytes_max =	((65536 - 64) * 8),	.period_bytes_min =	64,	.period_bytes_max =	(65536 - 64),	.periods_min =		2,	.periods_max =		2,	.fifo_size =		0,};unsigned int snd_ca0106_ptr_read(ca0106_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;}void snd_ca0106_ptr_write(ca0106_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);}int snd_ca0106_i2c_write(ca0106_t *emu,				u32 reg,				u32 value){	u32 tmp;	int timeout=0;	int status;	int retry;	if ((reg > 0x7f) || (value > 0x1ff))	{		snd_printk(KERN_ERR "i2c_write: invalid values.\n");		return -EINVAL;	}	tmp = reg << 25 | value << 16;	/* Not sure what this I2C channel controls. */	/* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */	/* This controls the I2C connected to the WM8775 ADC Codec */	snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp);	for(retry=0;retry<10;retry++)	{		/* Send the data to i2c */		tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);		tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);		snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);		/* Wait till the transaction ends */		while(1)		{			status = snd_ca0106_ptr_read(emu, I2C_A, 0);                	//snd_printk("I2C:status=0x%x\n", status);			timeout++;			if((status & I2C_A_ADC_START)==0)				break;			if(timeout>1000)				break;		}		//Read back and see if the transaction is successful		if((status & I2C_A_ADC_ABORT)==0)			break;	}	if(retry==10)	{		snd_printk(KERN_ERR "Writing to ADC failed!\n");		return -EINVAL;	}        	return 0;}static void snd_ca0106_intr_enable(ca0106_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_ca0106_intr_disable(ca0106_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_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime){	kfree(runtime->private_data);}/* open_playback callback */static int snd_ca0106_pcm_open_playback_channel(snd_pcm_substream_t *substream, int channel_id){	ca0106_t *chip = snd_pcm_substream_chip(substream);        ca0106_channel_t *channel = &(chip->playback_channels[channel_id]);	ca0106_pcm_t *epcm;	snd_pcm_runtime_t *runtime = substream->runtime;	int err;	epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);	if (epcm == NULL)		return -ENOMEM;	epcm->emu = chip;	epcm->substream = substream;        epcm->channel_id=channel_id;  	runtime->private_data = epcm;	runtime->private_free = snd_ca0106_pcm_free_substream;  	runtime->hw = snd_ca0106_playback_hw;        channel->emu = chip;        channel->number = channel_id;

⌨️ 快捷键说明

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