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

📄 s3c24xx-uda1341.c

📁 扬创2440平台上的ALSA音频驱动程序( for Linux-2.6.26.5 )。驱动使用说明和ALSA Lib的编译过程都在压缩包内
💻 C
📖 第 1 页 / 共 5 页
字号:
	if ( stream_id == SNDRV_PCM_STREAM_PLAYBACK )
	{
		// FIXME it must be located here?
		init_s3c2410_iis_bus_tx();
	}
	else
	{
		// FIXME it must be located here?
		init_s3c2410_iis_bus_rx();
	}
		
	/* Set requested samplerate */
	s3c24xx_uda1341_set_samplerate( chip, runtime -> rate );

	s -> period = 0;
	s -> periods = 0;
	
	return 0;
}

static snd_pcm_uframes_t snd_s3c24xx_uda1341_pointer( struct snd_pcm_substream *substream )
{
	struct s3c24xx_uda1341 *chip = snd_pcm_substream_chip( substream );
	struct audio_stream *s = &chip -> s[ substream -> pstr -> stream ];
	
	dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_pointer() start...\n" );

	return audio_get_dma_pos( s );
}

static int snd_s3c24xx_uda1341_trigger( struct snd_pcm_substream *substream, int cmd )
{
	struct s3c24xx_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;

	spin_lock( &s -> dma_lock );

	switch ( cmd )
	{
		case SNDRV_PCM_TRIGGER_START:

			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_START...\n" );

			if ( stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1 -> active )
			{
				s1 -> tx_spin = 1;
				audio_process_dma( s1 );
			}
			else
			{
				s -> tx_spin = 0;
			}

			s -> active = 1;
			audio_process_dma( s );
			
			break;

		case SNDRV_PCM_TRIGGER_STOP:
			
			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_STOP...\n" );

			s -> active = 0;
			
			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );
			
			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );

			if ( stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1 -> active )
			{
				s -> tx_spin = 1;
				audio_process_dma( s );
			}
			else
			{
				if ( s1 -> tx_spin )
				{
					s1 -> tx_spin = 0;
					s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_STOP );
					s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_FLUSH );
				}
			}
			
			break;

		case SNDRV_PCM_TRIGGER_SUSPEND:
			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_SUSPEND...\n" );

			s -> active = 0;

			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );

			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );

			s -> periods = 0;

			break;

		case SNDRV_PCM_TRIGGER_RESUME:
			
			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_RESUME...\n" );

			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:

			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_PAUSE_PUSH...\n" );

			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_STOP );

			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;

					s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_FLUSH );

					audio_process_dma( s );
				}
			}
			else
			{
				if ( s1 -> tx_spin )
				{
					s1 -> tx_spin = 0;

					s3c2410_dma_ctrl( s1 -> dma_ch, S3C2410_DMAOP_FLUSH );

				}
			}

			break;

		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			
			//dbg( dbg_debug, PFX "snd_s3c24xx_uda1341_trigger cmd = SNDRV_PCM_TRIGGER_PAUSE_RELEASE...\n" );

			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 );
			}
			
			s3c2410_dma_ctrl( s -> dma_ch, S3C2410_DMAOP_START );

			break;

		default:
			err = -EINVAL;
			break;
	}

	spin_unlock( &s -> dma_lock );

	return err;
}

static int snd_s3c24xx_uda1341_mmap( struct snd_pcm_substream *substream, struct vm_area_struct *vma )
{
	struct snd_pcm_runtime *runtime = substream -> runtime;

	return dma_mmap_coherent( substream -> pcm -> card -> dev, vma, runtime -> dma_area, runtime -> dma_addr, runtime -> dma_bytes );
}

/*
 * PCM operations
 */
static struct snd_pcm_ops snd_card_s3c24xx_uda1341_playback_ops = {
	.open			= snd_card_s3c24xx_uda1341_open,
	.close			= snd_card_s3c24xx_uda1341_close,
	.ioctl			= snd_pcm_lib_ioctl,
	.hw_params	        = snd_s3c24xx_uda1341_hw_params,
	.hw_free	        = snd_s3c24xx_uda1341_hw_free,
	.prepare		= snd_s3c24xx_uda1341_prepare,
	.trigger		= snd_s3c24xx_uda1341_trigger,
	.pointer		= snd_s3c24xx_uda1341_pointer,
	.mmap			= snd_s3c24xx_uda1341_mmap,
};

static struct snd_pcm_ops snd_card_s3c24xx_uda1341_capture_ops = {
	.open			= snd_card_s3c24xx_uda1341_open,
	.close			= snd_card_s3c24xx_uda1341_close,
	.ioctl			= snd_pcm_lib_ioctl,
	.hw_params	        = snd_s3c24xx_uda1341_hw_params,
	.hw_free	        = snd_s3c24xx_uda1341_hw_free,
	.prepare		= snd_s3c24xx_uda1341_prepare,
	.trigger		= snd_s3c24xx_uda1341_trigger,
	.pointer		= snd_s3c24xx_uda1341_pointer,
	.mmap			= snd_s3c24xx_uda1341_mmap,
};

static int __devinit snd_card_s3c24xx_uda1341_pcm( struct snd_card *card, struct s3c24xx_uda1341 *chip, int device )
{
	struct snd_pcm *pcm;
	int err;

	audio_stream_t *input_stream, *output_stream;

	if ( ( err = snd_pcm_new( card, "UDA1341 PCM", device, 1, 1, &pcm ) ) < 0 )
	{
		return err;
	}

	/*
	 * I'm not sure whether it's the right choice to set the dma_type to isa.
	 * but is actually works
	 */
	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_s3c24xx_uda1341_playback_ops );
	snd_pcm_set_ops( pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_s3c24xx_uda1341_capture_ops );

	pcm -> private_data = chip;
	pcm -> info_flags = 0;

	strcpy( pcm -> name, "UDA1341 PCM" );

	
	
	/*
	 * Setup DMA controller
	 */

	output_stream = &chip -> s[ SNDRV_PCM_STREAM_PLAYBACK ];
	output_stream -> id = "UDA1341 OUT";
	output_stream -> stream_id = SNDRV_PCM_STREAM_PLAYBACK;
	output_stream -> dma_ch = DMA_CH2;
	
	if ( !audio_init_dma ( output_stream, "UDA1341 out" ) )
	{
		audio_clear_dma ( output_stream, &s3c24xxiis_dma_client_out );
		dbg ( dbg_err, AUDIO_NAME_VERBOSE
		         ": unable to get DMA channels\n" );
		return -EBUSY;
	}

	input_stream = &chip -> s[ SNDRV_PCM_STREAM_CAPTURE ];
	input_stream -> id = "UDA1341 IN";
	input_stream -> stream_id = SNDRV_PCM_STREAM_CAPTURE;
	input_stream -> dma_ch = DMA_CH1;

	if ( !audio_init_dma ( input_stream, "UDA1341 in" ) )
	{
		audio_clear_dma ( input_stream, &s3c24xxiis_dma_client_in );
		dbg ( dbg_err, AUDIO_NAME_VERBOSE
		         ": unable to get DMA channels\n" );
		return -EBUSY;
	}

	chip -> pcm = pcm;

	return 0;

}

void snd_s3c24xx_uda1341_free( struct snd_card *card )
{
	struct s3c24xx_uda1341 *chip = card -> private_data;

	audio_clear_dma( &chip -> s[ SNDRV_PCM_STREAM_PLAYBACK ], &s3c24xxiis_dma_client_out );
	audio_clear_dma( &chip -> s[ SNDRV_PCM_STREAM_CAPTURE ], &s3c24xxiis_dma_client_in );
}

static int __devinit s3c24xxiis_probe ( struct platform_device *pdev )
{

	struct snd_card *card;
	struct s3c24xx_uda1341 *chip;
	int ret;
	
	dbg ( dbg_debug, "s3c24xxiis_probe...\n" );
	
	res = platform_get_resource ( pdev, IORESOURCE_MEM, 0 );

	if ( res == NULL )
	{
		dbg ( dbg_err, PFX "failed to get memory region resouce\n" );
		ret = -ENOENT;
		goto probe_out;
	}

	res = request_mem_region( res->start, RESSIZE( res ), pdev->name );

	if ( res == 0 )
	{
		dbg ( dbg_err, PFX "failed to request io memory region resouce\n" );
		ret = -ENOENT;
		goto probe_out;

	}

	iis_base = ioremap( res->start, RESSIZE( res ) );

	if ( iis_base == 0 )
	{
		dbg ( dbg_err, PFX "failed to ioremap() io memory region\n" );
		ret = -ENOENT;
		goto probe_free_mem_region;
	}


	iis_clock = clk_get ( &pdev->dev, "iis" );

	if ( iis_clock == NULL )
	{
		dbg ( dbg_err, PFX "failed to find clock source\n" );
		ret = -EINVAL;
		goto probe_iounmap;
	}


	clk_enable ( iis_clock );
	
	/*
	 * The Initialization of resouce and clock has been ended
	 * Now it is the snd's turn
	 */
	/*
	 * Register the soundcard
	 */
	card = snd_card_new( -1, id, THIS_MODULE, sizeof( struct s3c24xx_uda1341 ) );
	if ( card == NULL )
	{
		dbg( dbg_err, PFX "failed to allocate sound card\n" );
		ret = -ENOMEM;
		goto probe_clk_free;
	}

	chip = card -> private_data;
	spin_lock_init( &chip -> s[ 0 ].dma_lock );
	spin_lock_init( &chip -> s[ 1 ].dma_lock );

	card -> private_free = snd_s3c24xx_uda1341_free;
	chip -> card = card;
	chip -> samplerate = AUDIO_RATE_DEFAULT;

	/*
	 * Initialize soundcard hardware information
	 */
	if ( ( ret = snd_card_s3c24xx_uda1341_init( card, pdev, chip ) ) < 0 )
	{
		dbg( dbg_err, PFX "failed to initialize hardware\n" );
		goto probe_snd_free;
	}

	// mixer
	if ( ( ret = snd_chip_uda1341_mixer_new( card, chip ) ) < 0 )
	{
		dbg( dbg_err, PFX "failed to register mixer device\n" );
		goto probe_snd_free;
	}

	// PCM
	if ( ( ret = snd_card_s3c24xx_uda1341_pcm( card, chip, 0 ) ) < 0 )
	{
		dbg( dbg_err, PFX "failed to register PCM device\n" );
		goto probe_snd_free;
	}
	
	// todo sigh! complicated!
#ifdef CONFIG_PROC_FS
	snd_chip_uda1341_proc_init( card, chip );
#endif /*CONFIG_PROC_FS*/
	
	strcpy( card -> driver, "UDA1341" );
	strcpy( card -> shortname, "S3C24XX UDA1341" );
	strcpy( card -> longname, "SAMSUNG S3C24XX with Philips UDA1341TS" );


	/*
	 * Register sound card
	 */
	if ( ( ret = snd_card_register( card ) ) != 0 )
	{
		dbg( dbg_err, PFX "faled to register sound card\n" );
		goto probe_snd_free;
	}

	platform_set_drvdata( pdev, card );

	dbg ( dbg_info, AUDIO_NAME_VERBOSE " initialized\n" );

	return 0;

probe_snd_free:
	snd_card_free( card );

probe_clk_free:
	clk_disable( iis_clock );
	clk_put( iis_clock );

probe_iounmap:
	iounmap( iis_base );

probe_free_mem_region:
	release_mem_region( res->start, RESSIZE( res ) );

probe_out:

	return ret;
}

static int __devexit s3c24xxiis_remove ( struct platform_device *pdev )
{
	//free snd_card
	snd_card_free( platform_get_drvdata( pdev ) );
	platform_set_drvdata( pdev, NULL );
	
	clk_disable ( iis_clock);
	clk_put ( iis_clock );
	iounmap ( iis_base );
	release_mem_region( res->start, RESSIZE( res ) );
	kfree( res );
	dbg ( dbg_info, AUDIO_NAME_VERBOSE " unloaded\n" );
	return 0;
}

static struct platform_driver s3c24xxiis_driver =
{
	.probe		= s3c24xxiis_probe,
	.remove		= s3c24xxiis_remove,
	.driver		=
	{
		.name	= "s3c2410-iis",	/* match the resource name in arch/arm/plat-s3c24xx/devs.c */
		.owner	= THIS_MODULE,	
	},
};

static int __init s3c24xx_uda1341_init( void )
{
	return platform_driver_register( &s3c24xxiis_driver );
}

static void __exit s3c24xx_uda1341_exit( void )
{
	return platform_driver_unregister( &s3c24xxiis_driver );
}

module_init ( s3c24xx_uda1341_init );
module_exit ( s3c24xx_uda1341_exit );

⌨️ 快捷键说明

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