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 + -
显示快捷键?