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

📄 sa11xx-uda1341.c

📁 linux环境下ALSA驱动范例
💻 C
📖 第 1 页 / 共 2 页
字号:
			snd_assert(dma_size <= DMA_BUF_SIZE, );		}#ifdef HH_VERSION		ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);		if (ret)			return; //FIXME#else		ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);		if (ret) {			printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);			return;		}#endif		s->period++;		s->period %= runtime->periods;		s->periods++;	}}#ifdef HH_VERSIONstatic void audio_dma_callback(void *data, int size)#elsestatic void audio_dma_callback(void *data)#endif{	struct audio_stream *s = data;        	/* 	 * If we are getting a callback for an active stream then we inform	 * the PCM middle layer we've finished a period	 */ 	if (s->active)		snd_pcm_period_elapsed(s->stream);	spin_lock(&s->dma_lock);	if (!s->tx_spin && s->periods > 0)		s->periods--;	audio_process_dma(s);	spin_unlock(&s->dma_lock);}/* }}} *//* {{{ PCM setting *//* {{{ trigger & timer */static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd){	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);	int stream_id = substream->pstr->stream;	struct audio_stream *s = &chip->s[stream_id];	struct audio_stream *s1 = &chip->s[stream_id ^ 1];	int err = 0;	/* note local interrupts are already disabled in the midlevel code */	spin_lock(&s->dma_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* now we need to make sure a record only stream has a clock */		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {			/* we need to force fill the xmit DMA with zeros */			s1->tx_spin = 1;			audio_process_dma(s1);		}		/* this case is when you were recording then you turn on a		 * playback stream so we stop (also clears it) the dma first,		 * clear the sync flag and then we let it turned on		 */				else { 			s->tx_spin = 0; 		}		/* requested stream startup */		s->active = 1;		audio_process_dma(s);		break;	case SNDRV_PCM_TRIGGER_STOP:		/* requested stream shutdown */		audio_stop_dma(s);				/*		 * now we need to make sure a record only stream has a clock		 * so if we're stopping a playback with an active capture		 * we need to turn the 0 fill dma on for the xmit side		 */		if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {			/* we need to force fill the xmit DMA with zeros */			s->tx_spin = 1;			audio_process_dma(s);		}		/*		 * we killed a capture only stream, so we should also kill		 * the zero fill transmit		 */		else {			if (s1->tx_spin) {				s1->tx_spin = 0;				audio_stop_dma(s1);			}		}				break;	case SNDRV_PCM_TRIGGER_SUSPEND:		s->active = 0;#ifdef HH_VERSION				sa1100_dma_stop(s->dmach);#else		//FIXME - DMA API#endif				s->old_offset = audio_get_dma_pos(s) + 1;#ifdef HH_VERSION				sa1100_dma_flush_all(s->dmach);#else		//FIXME - DMA API#endif				s->periods = 0;		break;	case SNDRV_PCM_TRIGGER_RESUME:		s->active = 1;		s->tx_spin = 0;		audio_process_dma(s);		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {			s1->tx_spin = 1;			audio_process_dma(s1);		}		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:#ifdef HH_VERSION				sa1100_dma_stop(s->dmach);#else		//FIXME - DMA API#endif		s->active = 0;		if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {			if (s1->active) {				s->tx_spin = 1;				s->old_offset = audio_get_dma_pos(s) + 1;#ifdef HH_VERSION								sa1100_dma_flush_all(s->dmach);#else				//FIXME - DMA API#endif								audio_process_dma(s);			}		} else {			if (s1->tx_spin) {				s1->tx_spin = 0;#ifdef HH_VERSION								sa1100_dma_flush_all(s1->dmach);#else				//FIXME - DMA API#endif							}		}		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		s->active = 1;		if (s->old_offset) {			s->tx_spin = 0;			audio_process_dma(s);			break;		}		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {			s1->tx_spin = 1;			audio_process_dma(s1);		}#ifdef HH_VERSION				sa1100_dma_resume(s->dmach);#else		//FIXME - DMA API#endif		break;	default:		err = -EINVAL;		break;	}	spin_unlock(&s->dma_lock);		return err;}static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream){	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct audio_stream *s = &chip->s[substream->pstr->stream];        	/* set requested samplerate */	sa11xx_uda1341_set_samplerate(chip, runtime->rate);	/* set requestd format when available */	/* set FMT here !!! FIXME */	s->period = 0;	s->periods = 0;        	return 0;}static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream){	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);	return audio_get_dma_pos(&chip->s[substream->pstr->stream]);}/* }}} */static struct snd_pcm_hardware snd_sa11xx_uda1341_capture ={	.info			= (SNDRV_PCM_INFO_INTERLEAVED |				   SNDRV_PCM_INFO_BLOCK_TRANSFER |				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),	.formats		= SNDRV_PCM_FMTBIT_S16_LE,	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\				   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\				   SNDRV_PCM_RATE_KNOT),	.rate_min		= 8000,	.rate_max		= 48000,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 64,	.period_bytes_max	= DMA_BUF_SIZE,	.periods_min		= 2,	.periods_max		= 255,	.fifo_size		= 0,};static struct snd_pcm_hardware snd_sa11xx_uda1341_playback ={	.info			= (SNDRV_PCM_INFO_INTERLEAVED |				   SNDRV_PCM_INFO_BLOCK_TRANSFER |				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),	.formats		= SNDRV_PCM_FMTBIT_S16_LE,	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\                                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\				   SNDRV_PCM_RATE_KNOT),	.rate_min		= 8000,	.rate_max		= 48000,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 64,	.period_bytes_max	= DMA_BUF_SIZE,	.periods_min		= 2,	.periods_max		= 255,	.fifo_size		= 0,};static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream){	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int stream_id = substream->pstr->stream;	int err;	chip->s[stream_id].stream = substream;	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)		runtime->hw = snd_sa11xx_uda1341_playback;	else		runtime->hw = snd_sa11xx_uda1341_capture;	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;	if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)		return err;        	return 0;}static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream){	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);	chip->s[substream->pstr->stream].stream = NULL;	return 0;}/* {{{ HW params & free */static int snd_sa11xx_uda1341_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_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream){	return snd_pcm_lib_free_pages(substream);}/* }}} */static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {	.open			= snd_card_sa11xx_uda1341_open,	.close			= snd_card_sa11xx_uda1341_close,	.ioctl			= snd_pcm_lib_ioctl,	.hw_params	        = snd_sa11xx_uda1341_hw_params,	.hw_free	        = snd_sa11xx_uda1341_hw_free,	.prepare		= snd_sa11xx_uda1341_prepare,	.trigger		= snd_sa11xx_uda1341_trigger,	.pointer		= snd_sa11xx_uda1341_pointer,};static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {	.open			= snd_card_sa11xx_uda1341_open,	.close			= snd_card_sa11xx_uda1341_close,	.ioctl			= snd_pcm_lib_ioctl,	.hw_params	        = snd_sa11xx_uda1341_hw_params,	.hw_free	        = snd_sa11xx_uda1341_hw_free,	.prepare		= snd_sa11xx_uda1341_prepare,	.trigger		= snd_sa11xx_uda1341_trigger,	.pointer		= snd_sa11xx_uda1341_pointer,};static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device){	struct snd_pcm *pcm;	int err;	if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)		return err;	/*	 * this sets up our initial buffers and sets the dma_type to isa.	 * isa works but I'm not sure why (or if) it's the right choice	 * this may be too large, trying it for now	 */	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 					      snd_dma_isa_data(),					      64*1024, 64*1024);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);	pcm->private_data = sa11xx_uda1341;	pcm->info_flags = 0;	strcpy(pcm->name, "UDA1341 PCM");	sa11xx_uda1341_audio_init(sa11xx_uda1341);	/* setup DMA controller */	audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);	audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);	sa11xx_uda1341->pcm = pcm;	return 0;}/* }}} *//* {{{ module init & exit */#ifdef CONFIG_PMstatic int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,				      pm_message_t state){	struct snd_card *card = platform_get_drvdata(devptr);	struct sa11xx_uda1341 *chip = card->private_data;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	snd_pcm_suspend_all(chip->pcm);#ifdef HH_VERSION	sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);	sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);#else	//FIXME#endif	l3_command(chip->uda1341, CMD_SUSPEND, NULL);	sa11xx_uda1341_audio_shutdown(chip);	return 0;}static int snd_sa11xx_uda1341_resume(struct platform_device *devptr){	struct snd_card *card = platform_get_drvdata(devptr);	struct sa11xx_uda1341 *chip = card->private_data;	sa11xx_uda1341_audio_init(chip);	l3_command(chip->uda1341, CMD_RESUME, NULL);#ifdef HH_VERSION		sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);	sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);#else	//FIXME#endif	snd_power_change_state(card, SNDRV_CTL_POWER_D0);	return 0;}#endif /* COMFIG_PM */void snd_sa11xx_uda1341_free(struct snd_card *card){	struct sa11xx_uda1341 *chip = card->private_data;	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);}static int __init sa11xx_uda1341_probe(struct platform_device *devptr){	int err;	struct snd_card *card;	struct sa11xx_uda1341 *chip;	/* register the soundcard */	card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));	if (card == NULL)		return -ENOMEM;	chip = card->private_data;	spin_lock_init(&chip->s[0].dma_lock);	spin_lock_init(&chip->s[1].dma_lock);	card->private_free = snd_sa11xx_uda1341_free;	chip->card = card;	chip->samplerate = AUDIO_RATE_DEFAULT;	// mixer	if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))		goto nodev;	// PCM	if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)		goto nodev;        	strcpy(card->driver, "UDA1341");	strcpy(card->shortname, "H3600 UDA1341TS");	sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");        	snd_card_set_dev(card, &devptr->dev);	if ((err = snd_card_register(card)) == 0) {		printk( KERN_INFO "iPAQ audio support initialized\n" );		platform_set_drvdata(devptr, card);		return 0;	}         nodev:	snd_card_free(card);	return err;}static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr){	snd_card_free(platform_get_drvdata(devptr));	platform_set_drvdata(devptr, NULL);	return 0;}#define SA11XX_UDA1341_DRIVER	"sa11xx_uda1341"static struct platform_driver sa11xx_uda1341_driver = {	.probe		= sa11xx_uda1341_probe,	.remove		= __devexit_p(sa11xx_uda1341_remove),#ifdef CONFIG_PM	.suspend	= snd_sa11xx_uda1341_suspend,	.resume		= snd_sa11xx_uda1341_resume,#endif	.driver		= {		.name	= SA11XX_UDA1341_DRIVER,	},};static int __init sa11xx_uda1341_init(void){	int err;	if (!machine_is_h3xxx())		return -ENODEV;	if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)		return err;	device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);	if (IS_ERR(device)) {		platform_driver_unregister(&sa11xx_uda1341_driver);		return PTR_ERR(device);	}	return 0;}static void __exit sa11xx_uda1341_exit(void){	platform_device_unregister(device);	platform_driver_unregister(&sa11xx_uda1341_driver);}module_init(sa11xx_uda1341_init);module_exit(sa11xx_uda1341_exit);/* }}} *//* * Local variables: * indent-tabs-mode: t * End: */

⌨️ 快捷键说明

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