omap_pcm.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 338 行

C
338
字号
/* *  linux/sound/arm/omap_pcm.c * *  Copyright (C) 2003-2004 Russell King. *  Copyright (C) 2004  Texas Instruments Inc * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * *  This is essentially responsible for looking after the SA11x0 DMA. * History: * * 04-23-2004 	Kshitij		Changes for omap24xx/tsc2101 * * * *//****** linux/sound/arm/omap_pcm.c *********/#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/device.h>#include <linux/err.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <asm/dma.h>#include "omap_pcm.h"#undef TEST//#define TEST#ifdef TEST#define DPRINTK(fmt, args...) printk(KERN_INFO "\n %s: %s: " fmt,__FILE__,__FUNCTION__ , ## args)#else#define DPRINTK(fmt, args...)#endifstatic int ret;struct omap_pcm_runtime {	dma_device_t		device;	int			state;#define ST_RUNNING	(1 << 0)	int			use;	spinlock_t		lock;	int 			*dma;	/* Note: DMA Regs replaced with lch implementation */		/*dma_regs_t		*dma;*/	unsigned int		dma_period;	dma_addr_t		dma_start;	dma_addr_t		dma_pos;	dma_addr_t		dma_end;	snd_pcm_substream_t	*stream;};struct omap_pcm_data {	snd_card_t			*card;	struct omap_pcm_ops		*ops;	struct semaphore		sem;	struct omap_pcm_runtime		playback;	struct omap_pcm_runtime		capture;};static snd_pcm_hardware_t omap_pcm_hardware = {	.info			= SNDRV_PCM_INFO_INTERLEAVED |				  SNDRV_PCM_INFO_MMAP |				  SNDRV_PCM_INFO_MMAP_VALID |				  SNDRV_PCM_INFO_SYNC_START,	.formats		= SNDRV_PCM_FMTBIT_S16_LE,	.rates			= SNDRV_PCM_RATE_CONTINUOUS,	.rate_min		= 0,	.rate_max		= 0,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 64,	.period_bytes_max	= PAGE_SIZE, /* MAX_DMA_SIZE doesn't work here */	.periods_min		= 4,	.periods_max		= 1024,};static void omap_pcm_queue_buffers(struct omap_pcm_runtime *ssr){ /* This function starts DMA & manages the buffer.  * This is called from omap_pcm_dma_callback() &   * omap_pcm_trigger() in case SNDRV_PCM_TRIGGER_START */DPRINTK("dma_queue");}static void omap_pcm_dma_callback(void *data){DPRINTK("dma_callback");}static int omap_pcm_dma_request(const char *name, struct omap_pcm_runtime *ssr){  /* called by omap_pcm_open() , request for DMA */DPRINTK("dma_request");return ret;}int omap_pcm_open(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	struct omap_pcm_data *ssd = substream->private_data;	struct omap_pcm_runtime *ssr;	int ret;	runtime->hw = omap_pcm_hardware;	ret = ssd->ops->setruntime(ssd->card, runtime);	if (ret)		goto err_out;	DPRINTK("called setruntime");	down(&ssd->sem);	ret = omap_pcm_dma_request(ssd->card->shortname, &ssd->playback);	if (ret)		goto err_play;	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {		ret = omap_pcm_dma_request(ssd->card->shortname, &ssd->capture);		if (ret)			goto err_cap;		ssr = &ssd->capture;	} else {		ssr = &ssd->playback;	}	runtime->private_data = ssr;	ssr->stream = substream;		DPRINTK("calling McBSP-Init");	ssd->playback.use = 1; /*test -- remove later*/	if ((ssd->capture.use + ssd->playback.use) == 1) {		ret = ssd->ops->startup(ssd->card);		if (ret)			goto err_cap;	}	up(&ssd->sem);	return 0; err_cap:	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&	    ssd->capture.dma && --ssd->capture.use == 0) {		omap_free_dma((int)ssd->capture.dma);		ssd->capture.dma = NULL;	} err_play:	if (ssd->playback.dma && --ssd->playback.use == 0) {		omap_free_dma((int)ssd->playback.dma);		ssd->playback.dma = NULL;	}	up(&ssd->sem); err_out:	return ret;}static int omap_pcm_close(snd_pcm_substream_t *substream){	struct omap_pcm_data *ssd = substream->private_data;	down(&ssd->sem);	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&	    ssd->capture.dma && --ssd->capture.use == 0) {		ssd->capture.stream = NULL;		omap_free_dma((int)ssd->capture.dma);		ssd->capture.dma = NULL;	}	if (ssd->playback.dma && --ssd->playback.use == 0) {		ssd->playback.stream = NULL;		omap_free_dma((int)ssd->playback.dma);		ssd->playback.dma = NULL;	}	if ((ssd->playback.use + ssd->capture.use) == 0)		ssd->ops->shutdown(ssd->card);	up(&ssd->sem);	DPRINTK("omap_pcm_close");	return 0;}static int omap_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw));	DPRINTK("omap_pcm_hw_params");}static int omap_pcm_prepare(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	struct omap_pcm_data *ssd = substream->private_data;	struct omap_pcm_runtime *ssr = substream->runtime->private_data;	unsigned long flags;	spin_lock_irqsave(&ssr->lock, flags);	ssr->dma_period = snd_pcm_lib_period_bytes(substream);	ssr->dma_start = runtime->dma_addr;	ssr->dma_pos = ssr->dma_start;	ssr->dma_end = ssr->dma_start + snd_pcm_lib_buffer_bytes(substream);	spin_unlock_irqrestore(&ssr->lock, flags);		DPRINTK("omap_pcm_prepare called, calling samplerate");	ssd->ops->samplerate(ssd->card, runtime->rate);	return 0;}static int omap_pcm_trigger(snd_pcm_substream_t *substream, int cmd){	struct omap_pcm_runtime *ssr = substream->runtime->private_data;	unsigned long flags;	int ret = -EINVAL;	DPRINTK("omap_pcm_trigger called with cmd =%d",cmd);	spin_lock_irqsave(&ssr->lock, flags);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		/* omap_clear_dma(ssr->dma); */		omap_pcm_queue_buffers(ssr);		ssr->state |= ST_RUNNING;		ret = 0;		DPRINTK("In trigger start");		break;	case SNDRV_PCM_TRIGGER_RESUME:		/* omap_resume_dma(ssr->dma); */		ssr->state |= ST_RUNNING;		ret = 0;		DPRINTK("In trigger resume");		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		ssr->state &= ~ST_RUNNING;		omap_stop_dma((int)ssr->dma);		ret = 0;		DPRINTK("In trigger stop/suspend");		break;	}	spin_unlock_irqrestore(&ssr->lock, flags);	return ret;}static snd_pcm_uframes_t omap_pcm_pointer(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	struct omap_pcm_runtime *ssr = runtime->private_data;	unsigned long flags;	dma_addr_t off;	spin_lock_irqsave(&ssr->lock, flags);	//TO : DO	//off = omap_get_dma_pos((int)ssr->dma) - ssr->dma_start;	spin_unlock_irqrestore(&ssr->lock, flags);	DPRINTK("In omap_pcm_pointer");	return bytes_to_frames(runtime, off);}static snd_pcm_ops_t omap_pcm_ops = {	.open		= omap_pcm_open,	.close		= omap_pcm_close,	.ioctl		= snd_pcm_lib_ioctl,	.hw_params	= omap_pcm_hw_params,	.hw_free	= snd_pcm_lib_free_pages,	.prepare	= omap_pcm_prepare,	.trigger	= omap_pcm_trigger,	.pointer	= omap_pcm_pointer,};static void omap_pcm_free(snd_pcm_t *pcm){	kfree(pcm->private_data);	DPRINTK("Freeing pcm private data,");}snd_pcm_t *omap_pcm_create(snd_card_t *card, struct omap_pcm_ops *ops,			     dma_device_t play_dev, dma_device_t capt_dev){	struct omap_pcm_data *ssd;	snd_pcm_t *pcm;	int err;	DPRINTK("");/*	err = dma_set_mask(card->dev, 0xffffffff);	if (err) {		dev_warn(card->dev, "no suitable DMA available\n");		pcm = ERR_PTR(err);		goto out;	}*/	err = snd_pcm_new(card, "TSC2101-PCM", 0, 1, 1, &pcm);	if (err) {		pcm = ERR_PTR(err);		goto out;	}	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &omap_pcm_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &omap_pcm_ops);	DPRINTK("created new substream, done pcm_set_ops");	ssd = kmalloc(sizeof(struct omap_pcm_data), GFP_KERNEL);	if (!ssd) {		pcm = ERR_PTR(-ENOMEM);		goto out;	}	memset(ssd, 0, sizeof(struct omap_pcm_data));	ssd->card = card;	ssd->ops = ops;	init_MUTEX(&ssd->sem);	spin_lock_init(&ssd->playback.lock);	spin_lock_init(&ssd->capture.lock);	ssd->playback.device = play_dev;	ssd->capture.device = capt_dev;	DPRINTK("play_dev =%d; capture_dev =%d",play_dev,capt_dev);	pcm->private_data = ssd;	pcm->private_free = omap_pcm_free;//	err = snd_pcm_lib_preallocate_dev_pages_for_all(card->dev, pcm,64*1024, 128*1024);	err = snd_pcm_lib_preallocate_pages_for_all(pcm, 64*1024, 128*1024,GFP_KERNEL);	if (err)		pcm = ERR_PTR(err); out:	return pcm;}EXPORT_SYMBOL(omap_pcm_create);

⌨️ 快捷键说明

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