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

📄 omap-audio.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/sound/oss/omap-audio.c * * Common audio handling for the OMAP processors * * Copyright (C) 2004 Texas Instruments, Inc. * * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org> * * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * History: * * 2004/08/12   Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 *                and 2420 platforms. * * 2004-11-01   Nishanth Menon - modified to support 16xx and 17xx  *                platform multi channel chaining. * * 2004-11-04   Nishanth Menon - Added support for power management *//***************************** INCLUDES ************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/pm.h>#include <linux/errno.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/sysrq.h>#include <linux/delay.h>#include <linux/device.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include "omap-audio-dma-intfc.h"#include "omap-audio.h"/***************************** MACROS ************************************/#undef DEBUG//#define DEBUG#ifdef DEBUG#define DPRINTK  printk#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__)#define FN_OUT(n) printk(" end\n")#else#define DPRINTK( x... )#define FN_IN#define FN_OUT(x)#endif#define OMAP_AUDIO_NAME		"omap-audio"#define AUDIO_NBFRAGS_DEFAULT	8#define AUDIO_FRAGSIZE_DEFAULT	8192/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w * Sampling Rate vs buffer size and delay we are prepared to do before giving up */#define MAX_QUEUE_FULL_RETRIES 1000000#define QUEUE_WAIT_TIME        10#if !(defined( CONFIG_ARCH_OMAP16XX))#define OMAP_AUDIO_DMA_RETRY 1#endif#define AUDIO_ACTIVE(state)	((state)->rd_ref || (state)->wr_ref)#define SPIN_ADDR		(dma_addr_t)0#define SPIN_SIZE		2048/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/static int audio_write(struct file *file, const char *buffer,		       size_t count, loff_t * ppos);static int audio_read(struct file *file, char *buffer, size_t count,		      loff_t * ppos);static int audio_mmap(struct file *file, struct vm_area_struct *vma);static unsigned int audio_poll(struct file *file,			       struct poll_table_struct *wait);static loff_t audio_llseek(struct file *file, loff_t offset, int origin);static int audio_ioctl(struct inode *inode, struct file *file, uint cmd,		       ulong arg);static int audio_open(struct inode *inode, struct file *file);static int audio_release(struct inode *inode, struct file *file);static int audio_probe(struct device *dev);static int audio_remove(struct device *dev);static void audio_shutdown(struct device *dev);static int audio_suspend(struct device *dev, u32 state, u32 level);static int audio_resume(struct device *dev, u32 level);static void audio_free(struct device *dev);/***************************** Data Structures **********************************//* * The function pointer set to be registered by the codec. */static audio_state_t audio_state = { 0 };/* DMA Call back function */static dma_callback_t audio_dma_callback = 0;/* File Ops structure */static struct file_operations omap_audio_fops = {	.open     = audio_open,	.release  = audio_release,	.write    = audio_write,	.read     = audio_read,	.mmap     = audio_mmap,	.poll     = audio_poll,	.ioctl    = audio_ioctl,	.llseek   = audio_llseek,	.owner    = THIS_MODULE};/* Driver information */static struct device_driver omap_audio_driver = {	.name     = OMAP_AUDIO_NAME,	.bus      = &platform_bus_type,	.probe    = audio_probe,	.remove   = audio_remove,	.suspend  = audio_suspend,	.resume   = audio_resume,	.shutdown = audio_shutdown,};/* Device Information */static struct platform_device omap_audio_device = {	.name = OMAP_AUDIO_NAME,	.dev  = {		.driver_data = &audio_state,		.release = audio_free,		},	.id   = 0,};/***************************** GLOBAL FUNCTIONs **********************************//* Power Management Functions for Linux Device Model  *//* DEBUG PUPOSES ONLY! */#ifdef CONFIG_PM//#undef CONFIG_PM#endif#ifdef CONFIG_PM/********************************************************************************* * * audio_ldm_suspend(): Suspend operation * *********************************************************************************/static int audio_ldm_suspend(void *data){	audio_state_t *state = data;	FN_IN;	if (AUDIO_ACTIVE(state) && state->hw_init) {		printk(KERN_ERR "Audio device Active, Cannot Suspend");		return -EPERM;#if 0		/* NOTE:		 * This Piece of code is commented out in hope		 * That one day we would need to suspend the device while 		 * audio operations are in progress and resume the operations		 * once the resume is done.		 * This is just a sample implementation of how it could be done.		 * Currently NOT SUPPORTED		 */		audio_stream_t *is = state->input_stream;		audio_stream_t *os = state->output_stream;		int stopstate;		if (is && is->buffers) {			printk("IS Suspend\n");			stopstate = is->stopped;			audio_stop_dma(is);			DMA_CLEAR(is);			is->dma_spinref = 0;			is->stopped = stopstate;		}		if (os && os->buffers) {			printk("OS Suspend\n");			stopstate = os->stopped;			audio_stop_dma(os);			DMA_CLEAR(os);			os->dma_spinref = 0;			os->stopped = stopstate;		}#endif	}	FN_OUT(0);	return 0;}/********************************************************************************* * * audio_ldm_resume(): Resume Operations * *********************************************************************************/static int audio_ldm_resume(void *data){	audio_state_t *state = data;	FN_IN;	if (AUDIO_ACTIVE(state) && state->hw_init) {		/* Should never occur - since we never suspend with active state */		BUG();		return -EPERM;#if 0		/* NOTE:		 * This Piece of code is commented out in hope		 * That one day we would need to suspend the device while 		 * audio operations are in progress and resume the operations		 * once the resume is done.		 * This is just a sample implementation of how it could be done.		 * Currently NOT SUPPORTED		 */		audio_stream_t *is = state->input_stream;		audio_stream_t *os = state->output_stream;		if (os && os->buffers) {			printk("OS Resume\n");			audio_reset(os);			audio_process_dma(os);		}		if (is && is->buffers) {			printk("IS Resume\n");			audio_reset(is);			audio_process_dma(is);		}#endif	}	FN_OUT(0);	return 0;}#endif				/* End of #ifdef CONFIG_PM *//********************************************************************************* * * audio_free(): The Audio driver release function * This is a dummy function required by the platform driver * *********************************************************************************/static void audio_free(struct device *dev){	/* Nothing to Release! */}/********************************************************************************* * * audio_probe(): The Audio driver probe function * WARNING!!!!  : It is expected that the codec would have registered with us by now * *********************************************************************************/static int audio_probe(struct device *dev){	int ret;	FN_IN;	if (!audio_state.hw_probe) {		printk(KERN_ERR "Probe Function Not Registered\n");		return -ENODEV;	}	ret = audio_state.hw_probe();	FN_OUT(ret);	return ret;}/********************************************************************************* * * audio_remove() Function to handle removal operations * *********************************************************************************/static int audio_remove(struct device *dev){	FN_IN;	if (audio_state.hw_remove) {		DPRINTK("Calling Hadware remove \n");		audio_state.hw_remove();	}	FN_OUT(0);	return 0;}/********************************************************************************* * * audio_shutdown(): Function to handle shutdown operations * *********************************************************************************/static void audio_shutdown(struct device *dev){	FN_IN;	if (audio_state.hw_cleanup) {		DPRINTK("Calling Hadware Cleanup \n");		audio_state.hw_cleanup();	}	FN_OUT(0);	return;}/********************************************************************************* * * audio_suspend(): Function to handle suspend operations  * *********************************************************************************/static int audio_suspend(struct device *dev, u32 state, u32 level){	int ret = 0;#ifdef CONFIG_PM	void *data = dev->driver_data;	FN_IN;	if (level != 3) {		return 0;	}	if (audio_state.hw_suspend) {		DPRINTK("Calling Hadware suspend(level=%d) \n", level);		ret = audio_ldm_suspend(data);		if (ret == 0)			ret = audio_state.hw_suspend();	}	if (ret) {		printk(KERN_INFO "Audio Suspend Failed \n");	} else {		printk(KERN_INFO "Audio Suspend Success \n");	}#endif				/* CONFIG_PM */	FN_OUT(ret);	return ret;}/********************************************************************************* * * audio_resume(): Function to handle resume operations * *********************************************************************************/static int audio_resume(struct device *dev, u32 level){	int ret = 0;#ifdef	CONFIG_PM	void *data = dev->driver_data;	FN_IN;	if (level != 0) {		return 0;	}	if (audio_state.hw_resume) {		DPRINTK("Calling Hadware resume(level=%d) \n", level);		ret = audio_ldm_resume(data);		if (ret == 0)			ret = audio_state.hw_resume();	}	if (ret) {		printk(KERN_INFO " Audio Resume Failed \n");	} else {		printk(KERN_INFO " Audio Resume Success \n");	}#endif				/* CONFIG_PM */	FN_OUT(ret);	return ret;}/********************************************************************************* * * audio_get_fops(): Return the fops required to get the function pointers of  *                   OMAP Audio Driver * *********************************************************************************/struct file_operations *audio_get_fops(void){	FN_IN;	FN_OUT(0);	return &omap_audio_fops;}/********************************************************************************* * * audio_register_codec(): Register a Codec fn points using this function * WARNING!!!!!          : Codecs should ensure that they do so! no sanity checks *                         during runtime is done due to obvious performance  *                         penalties. * *********************************************************************************/int audio_register_codec(audio_state_t * codec_state){	int ret;	FN_IN;	/* We dont handle multiple codecs now */	if (audio_state.hw_init) {		printk(KERN_ERR " Codec Already registered\n");		return -EPERM;	}	/* Grab the dma Callback */	audio_dma_callback = audio_get_dma_callback();	if (!audio_dma_callback) {		printk(KERN_ERR "Unable to get call back function\n");		return -EPERM;	}	/* Sanity checks */	if (!codec_state) {		printk(KERN_ERR "NULL ARGUMENT!\n");		return -EPERM;	}	if (!codec_state->hw_probe || !codec_state->hw_init	    || !codec_state->hw_shutdown || !codec_state->client_ioctl) {		printk(KERN_ERR		       "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n",		       codec_state->hw_probe, codec_state->hw_init,		       codec_state->hw_shutdown, codec_state->client_ioctl);		return -EPERM;	}	memcpy(&audio_state, codec_state, sizeof(audio_state_t));	ret = platform_device_register(&omap_audio_device);	if (ret != 0) {		printk(KERN_ERR "Platform dev_register failed =%d\n", ret);		ret = -ENODEV;		goto register_out;	}	ret = driver_register(&omap_audio_driver);	if (ret != 0) {		printk(KERN_ERR "Device Register failed =%d\n", ret);		ret = -ENODEV;		platform_device_unregister(&omap_audio_device);		goto register_out;	}      register_out:	FN_OUT(ret);	return ret;}/********************************************************************************* * * audio_unregister_codec(): Un-Register a Codec using this function * *********************************************************************************/int audio_unregister_codec(audio_state_t * codec_state){	FN_IN;	/* We dont handle multiple codecs now */	if (!audio_state.hw_init) {		printk(KERN_ERR " No Codec registered\n");		return -EPERM;	}	/* Security check */	if (audio_state.hw_init != codec_state->hw_init) {		printk(KERN_ERR		       " Attempt to unregister codec which was not registered with us\n");		return -EPERM;	}	driver_unregister(&omap_audio_driver);	platform_device_unregister(&omap_audio_device);	memset(&audio_state, 0, sizeof(audio_state_t));	FN_OUT(0);	return 0;}/***************************** MODULES SPECIFIC FUNCTION *************************//********************************************************************************* * * audio_write(): Exposed to write() call * *********************************************************************************/static intaudio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){	const char *buffer0 = buffer;	audio_state_t *state = file->private_data;	audio_stream_t *s = state->output_stream;	int chunksize, ret = 0;#ifdef OMAP_AUDIO_DMA_RETRY	int ret1 = 0, try_count = 0;#endif	DPRINTK("audio_write: count=%d\n", count);	if (*ppos != file->f_pos) {		printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos,		       (u32) file->f_pos);		return -ESPIPE;	}	if (s->mapped) {		printk("s already mapped\n");		return -ENXIO;	}	if (!s->buffers && audio_setup_buf(s)) {		printk("NO MEMORY\n");		return -ENOMEM;	}	while (count > 0) {		audio_buf_t *b = &s->buffers[s->usr_head];		/* Wait for a buffer to become free */		if (file->f_flags & O_NONBLOCK) {			ret = -EAGAIN;			if (down_trylock(&s->sem))				break;		} else {			ret = -ERESTARTSYS;			if (down_interruptible(&s->sem))				break;		}		/* Feed the current buffer */		chunksize = s->fragsize - b->offset;		if (chunksize > count)			chunksize = count;		DPRINTK("write %d to %d\n", chunksize, s->usr_head);		if (copy_from_user(b->data + b->offset, buffer, chunksize)) {			printk(KERN_ERR "Audio: CopyFrom User failed \n");			up(&s->sem);			return -EFAULT;		}		buffer += chunksize;		count -= chunksize;		b->offset += chunksize;		DPRINTK("count: %d, chunksize: %d, offset: %d\n", count,			chunksize, b->offset);		if (b->offset < s->fragsize) {			up(&s->sem);			break;		}		/* Update pointers and send current fragment to DMA */		b->offset = 0;		if (++s->usr_head >= s->nbfrags)			s->usr_head = 0;		/* Add the num of frags pending */		s->pending_frags++;		s->active = 1;#ifdef OMAP_AUDIO_DMA_RETRY		try_count = 0;		ret1 = 0;		do {			ret1 = audio_process_dma(s);			if (ret1 == -2) {	/* Queue full? */				udelay(QUEUE_WAIT_TIME);	/* give a chance to empty queue */			}			try_count++;		}		while ((try_count < MAX_QUEUE_FULL_RETRIES) && (ret1 == -2));#else		audio_process_dma(s);#endif#ifdef OMAP_AUDIO_DMA_RETRY		if (ret1) {			printk(KERN_ERR			       "audio_write: Queue is Full or dma processing error (%d)!\n",			       ret1);			break;		}#endif	}

⌨️ 快捷键说明

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