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

📄 ali5451.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 4 页
字号:
		CTRL |= 0x00000008;	// 16-bit data	if (!snd_pcm_format_unsigned(runtime->format))		CTRL |= 0x00000002;	// signed data	if (runtime->channels > 1)		CTRL |= 0x00000004;	// stereo data	return CTRL;}/* *  PCM part */static int snd_ali_ioctl(struct snd_pcm_substream *substream,				  unsigned int cmd, void *arg){	return snd_pcm_lib_ioctl(substream, cmd, arg);}static int snd_ali_trigger(struct snd_pcm_substream *substream,			       int cmd)				    {	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct list_head *pos;	struct snd_pcm_substream *s;	unsigned int what, whati, capture_flag;	struct snd_ali_voice *pvoice = NULL, *evoice = NULL;	unsigned int val;	int do_start;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		do_start = 1; break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		do_start = 0; break;	default:		return -EINVAL;	}	what = whati = capture_flag = 0;	snd_pcm_group_for_each(pos, substream) {		s = snd_pcm_group_substream_entry(pos);		if ((struct snd_ali *) snd_pcm_substream_chip(s) == codec) {			pvoice = s->runtime->private_data;			evoice = pvoice->extra;			what |= 1 << (pvoice->number & 0x1f);			if (evoice == NULL) {				whati |= 1 << (pvoice->number & 0x1f);			} else {				whati |= 1 << (evoice->number & 0x1f);				what |= 1 << (evoice->number & 0x1f);			}			if (do_start) {				pvoice->running = 1;				if (evoice != NULL)					evoice->running = 1;			} else {				pvoice->running = 0;				if (evoice != NULL)					evoice->running = 0;			}			snd_pcm_trigger_done(s, substream);			if (pvoice->mode)				capture_flag = 1;		}	}	spin_lock(&codec->reg_lock);	if (! do_start) {		outl(what, ALI_REG(codec, ALI_STOP));	}	val = inl(ALI_REG(codec, ALI_AINTEN));	if (do_start) {		val |= whati;	} else {		val &= ~whati;	}	outl(val, ALI_REG(codec, ALI_AINTEN));	if (do_start) {		outl(what, ALI_REG(codec, ALI_START));	}	snd_ali_printk("trigger: what=%xh whati=%xh\n",what,whati);	spin_unlock(&codec->reg_lock);	return 0;}static int snd_ali_playback_hw_params(struct snd_pcm_substream *substream,				 struct snd_pcm_hw_params *hw_params){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	struct snd_ali_voice *evoice = pvoice->extra;	int err;	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));	if (err < 0) return err;		/* voice management */	if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) {		if (evoice == NULL) {			evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1);			if (evoice == NULL)				return -ENOMEM;			pvoice->extra = evoice;			evoice->substream = substream;		}	} else {		if (evoice != NULL) {			snd_ali_free_voice(codec, evoice);			pvoice->extra = evoice = NULL;		}	}	return 0;}static int snd_ali_playback_hw_free(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	struct snd_ali_voice *evoice = pvoice ? pvoice->extra : NULL;	snd_pcm_lib_free_pages(substream);	if (evoice != NULL) {		snd_ali_free_voice(codec, evoice);		pvoice->extra = NULL;	}	return 0;}static int snd_ali_hw_params(struct snd_pcm_substream *substream,				 struct snd_pcm_hw_params *hw_params){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ali_hw_free(struct snd_pcm_substream *substream){	return snd_pcm_lib_free_pages(substream);}static int snd_ali_playback_prepare(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	struct snd_ali_voice *evoice = pvoice->extra;	unsigned int LBA;	unsigned int Delta;	unsigned int ESO;	unsigned int CTRL;	unsigned int GVSEL;	unsigned int PAN;	unsigned int VOL;	unsigned int EC;		snd_ali_printk("playback_prepare ...\n");	spin_lock_irq(&codec->reg_lock);			/* set Delta (rate) value */	Delta = snd_ali_convert_rate(runtime->rate, 0);	if ((pvoice->number == ALI_SPDIF_IN_CHANNEL) || 	    (pvoice->number == ALI_PCM_IN_CHANNEL))		snd_ali_disable_special_channel(codec, pvoice->number);	else if (codec->spdif_support &&		 (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE)		 && (pvoice->number == ALI_SPDIF_OUT_CHANNEL)) {		snd_ali_set_spdif_out_rate(codec, runtime->rate);		Delta = 0x1000;	}		/* set Loop Back Address */	LBA = runtime->dma_addr;	/* set interrupt count size */	pvoice->count = runtime->period_size;	/* set target ESO for channel */	pvoice->eso = runtime->buffer_size; 	snd_ali_printk("playback_prepare: eso=%xh count=%xh\n",pvoice->eso,pvoice->count);	/* set ESO to capture first MIDLP interrupt */	ESO = pvoice->eso -1;	/* set ctrl mode */	CTRL = snd_ali_control_mode(substream);	GVSEL = 1;	PAN = 0;	VOL = 0;	EC = 0;	snd_ali_printk("playback_prepare:\n    ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n",pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL);	snd_ali_write_voice_regs(    codec,				     pvoice->number,				     LBA,				     0,	/* cso */				     ESO,				     Delta,				     0,	/* alpha */				     GVSEL,				     PAN,				     VOL,				     CTRL,				     EC);	if (evoice != NULL) {		evoice->count = pvoice->count;		evoice->eso = pvoice->count << 1;		ESO = evoice->eso - 1;		snd_ali_write_voice_regs(codec,				     evoice->number,				     LBA,				     0,	/* cso */				     ESO,				     Delta,				     0,	/* alpha */				     GVSEL,				     (unsigned int)0x7f,				     (unsigned int)0x3ff,				     CTRL,				     EC);	}	spin_unlock_irq(&codec->reg_lock);	return 0;}static int snd_ali_prepare(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	unsigned int LBA;	unsigned int Delta;	unsigned int ESO;	unsigned int CTRL;	unsigned int GVSEL;	unsigned int PAN;	unsigned int VOL;	unsigned int EC;	u8	 bValue;	spin_lock_irq(&codec->reg_lock);	snd_ali_printk("ali_prepare...\n");	snd_ali_enable_special_channel(codec,pvoice->number);	Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL ||		 pvoice->number == ALI_MODEM_OUT_CHANNEL) ? 		0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode);	// Prepare capture intr channel	if (pvoice->number == ALI_SPDIF_IN_CHANNEL) {		unsigned int rate;				spin_unlock_irq(&codec->reg_lock);		if (codec->revision != ALI_5451_V02)			return -1;		rate = snd_ali_get_spdif_in_rate(codec);		if (rate == 0) {			snd_printk(KERN_WARNING "ali_capture_preapre: spdif rate detect err!\n");			rate = 48000;		}		spin_lock_irq(&codec->reg_lock);		bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL));		if (bValue & 0x10) {			outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL));			printk(KERN_WARNING "clear SPDIF parity error flag.\n");		}		if (rate != 48000)			Delta = ((rate << 12)/runtime->rate)&0x00ffff;	}	// set target ESO for channel 	pvoice->eso = runtime->buffer_size; 	// set interrupt count size 	pvoice->count = runtime->period_size;	// set Loop Back Address 	LBA = runtime->dma_addr;	// set ESO to capture first MIDLP interrupt 	ESO = pvoice->eso - 1;	CTRL = snd_ali_control_mode(substream);	GVSEL = 0;	PAN = 0x00;	VOL = 0x00;	EC = 0;	snd_ali_write_voice_regs(    codec,				     pvoice->number,				     LBA,				     0,	/* cso */				     ESO,				     Delta,				     0,	/* alpha */				     GVSEL,				     PAN,				     VOL,				     CTRL,				     EC);	spin_unlock_irq(&codec->reg_lock);	return 0;}static snd_pcm_uframes_t snd_ali_playback_pointer(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	unsigned int cso;	spin_lock(&codec->reg_lock);	if (!pvoice->running) {		spin_unlock(&codec->reg_lock);		return 0;	}	outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));	cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));	spin_unlock(&codec->reg_lock);	snd_ali_printk("playback pointer returned cso=%xh.\n", cso);	return cso;}static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice = runtime->private_data;	unsigned int cso;	spin_lock(&codec->reg_lock);	if (!pvoice->running) {		spin_unlock_irq(&codec->reg_lock);		return 0;	}	outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR));	cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2));	spin_unlock(&codec->reg_lock);	return cso;}static struct snd_pcm_hardware snd_ali_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |				 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(256*1024),	.period_bytes_min =	64,	.period_bytes_max =	(256*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};/* *  Capture support device description */static struct snd_pcm_hardware snd_ali_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |				 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static void snd_ali_pcm_free_substream(struct snd_pcm_runtime *runtime){	struct snd_ali_voice *pvoice = runtime->private_data;	struct snd_ali *codec;	if (pvoice) {		codec = pvoice->codec;		snd_ali_free_voice(pvoice->codec, pvoice);	}}static int snd_ali_open(struct snd_pcm_substream *substream, int rec, int channel,		struct snd_pcm_hardware *phw){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ali_voice *pvoice;	pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel);	if (pvoice == NULL)		return -EAGAIN;	pvoice->substream = substream;	runtime->private_data = pvoice;	runtime->private_free = snd_ali_pcm_free_substream;	runtime->hw = *phw;	snd_pcm_set_sync(substream);	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);	return 0;}static int snd_ali_playback_open(struct snd_pcm_substream *substream){	return snd_ali_open(substream, 0, -1, &snd_ali_playback);}static int snd_ali_capture_open(struct snd_pcm_substream *substream){	return snd_ali_open(substream, 1, -1, &snd_ali_capture);}static int snd_ali_playback_close(struct snd_pcm_substream *substream){	return 0;}static int snd_ali_close(struct snd_pcm_substream *substream){	struct snd_ali *codec = snd_pcm_substream_chip(substream);	struct snd_ali_voice *pvoice = substream->runtime->private_data;	snd_ali_disable_special_channel(codec,pvoice->number);	return 0;}static struct snd_pcm_ops snd_ali_playback_ops = {	.open =		snd_ali_playback_open,	.close =	snd_ali_playback_close,	.ioctl =	snd_ali_ioctl,	.hw_params =	snd_ali_playback_hw_params,	.hw_free =	snd_ali_playback_hw_free,	.prepare =	snd_ali_playback_prepare,	.trigger =	snd_ali_trigger,	.pointer =	snd_ali_playback_pointer,};static struct snd_pcm_ops snd_ali_capture_ops = {	.open =		snd_ali_capture_open,	.close =	snd_ali_close,	.ioctl =	snd_ali_ioctl,	.hw_params =	snd_ali_hw_params,	.hw_free =	snd_ali_hw_free,	.prepare =	snd_ali_prepare,	.trigger =	snd_ali_trigger,	.pointer =	snd_ali_pointer,};/* * Modem PCM */static int snd_ali_modem_hw_params(struct snd_pcm_substream *substream,				 struct snd_pcm_hw_params *hw_params){	struct snd_ali *chip = snd_pcm_substream_chip(substream);	unsigned int modem_num = chip->num_of_codecs - 1;	snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params));	snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0);	return snd_ali_hw_params(substream, hw_params);}static struct snd_pcm_hardware snd_ali_modem ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_SYNC_START),	.formats =		SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000,	.rate_min =		8000,	.rate_max =		16000,	.channels_min =		1,	.channels_max =		1,	.buffer_bytes_max =	(256*1024),	.period_bytes_min =	64,	.period_bytes_max =	(256*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static int snd_ali_modem_open(struct snd_pcm_substream *substream, int rec, int channel){	static unsigned int rates [] = {8000,9600,12000,16000};	static struct snd_pcm_hw_constraint_list hw_constraint_rates = {		.count = ARRAY_SIZE(rates),		.list = rates,		.mask = 0,	};	int err = snd_ali_open(substream, rec, channel, &snd_ali_modem);	if (err)		return err;	return snd_pcm_hw_constraint_list(substream->runtime, 0,			SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);}static int snd_ali_modem_playback_open(struct snd_pcm_substream *substream){	return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL);}static int snd_ali_modem_capture_open(struct snd_pcm_substream *substream){	return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL);}static struct snd_pcm_ops snd_ali_modem_playback_ops = {	.open =		snd_ali_modem_playback_open,	.close =	snd_ali_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_ali_modem_hw_params,	.hw_free =	snd_ali_hw_free,	.prepare =	snd_ali_prepare,	.trigger =	snd_ali_trigger,	.pointer =	snd_ali_pointer,};static struct snd_pcm_ops snd_ali_modem_capture_ops = {	.open =		snd_ali_modem_capture_open,	.close =	snd_ali_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_ali_modem_hw_params,	.hw_free =	snd_ali_hw_free,	.prepare =	snd_ali_prepare,	.trigger =	snd_ali_trigger,	.pointer =	snd_ali_pointer,};struct ali_pcm_description {	char *name;	unsigned int playback_num;	unsigned int capture_num;	struct snd_pcm_ops *playback_ops;	struct snd_pcm_ops *capture_ops;	unsigned short class;};static void snd_ali_pcm_free(struct snd_pcm *pcm){	struct snd_ali *codec = pcm->private_data;	codec->pcm[pcm->device] = NULL;}static int __devinit snd_ali_pcm(struct snd_ali * codec, int device, struct ali_pcm_description *desc){	struct snd_pcm *pcm;	int err;	err = snd_pcm_new(codec->card, desc->name, device,			  desc->playback_num, desc->capture_num, &pcm);	if (err < 0) {		snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n");		return err;	}	pcm->private_data = codec;	pcm->private_free = snd_ali_pcm_free;	if (desc->playback_ops)		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops);

⌨️ 快捷键说明

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