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

📄 dmabuf.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/dmabuf.c * * The DMA buffer manager for digitized voice applications *//* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * Thomas Sailer   : moved several static variables into struct audio_operations *                   (which is grossly misnamed btw.) because they have the same *                   lifetime as the rest in there and dynamic allocation saves *                   12k or so * Thomas Sailer   : remove {in,out}_sleep_flag. It was used for the sleeper to *                   determine if it was woken up by the expiring timeout or by *                   an explicit wake_up. The return value from schedule_timeout *		     can be used instead; if 0, the wakeup was due to the timeout. * * Rob Riggs		Added persistent DMA buffers (1998/10/17) */#define BE_CONSERVATIVE#define SAMPLE_ROUNDUP 0#include "sound_config.h"#include <linux/wrapper.h>#define DMAP_FREE_ON_CLOSE      0#define DMAP_KEEP_ON_CLOSE      1extern int sound_dmap_flag;static void dma_reset_output(int dev);static void dma_reset_input(int dev);static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode);static int debugmem = 0;	/* switched off by default */static int dma_buffsize = DSP_BUFFSIZE;static long dmabuf_timeout(struct dma_buffparms *dmap){	long tmout;	tmout = (dmap->fragment_size * HZ) / dmap->data_rate;	tmout += HZ / 5;	/* Some safety distance */	if (tmout < (HZ / 2))		tmout = HZ / 2;	if (tmout > 20 * HZ)		tmout = 20 * HZ;	return tmout;}static int sound_alloc_dmap(struct dma_buffparms *dmap){	char *start_addr, *end_addr;	int dma_pagesize;	int sz, size;	struct page *page;	dmap->mapping_flags &= ~DMA_MAP_MAPPED;	if (dmap->raw_buf != NULL)		return 0;	/* Already done */	if (dma_buffsize < 4096)		dma_buffsize = 4096;	dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024);		/*	 *	Now check for the Cyrix problem.	 */	 	if(isa_dma_bridge_buggy==2)		dma_pagesize=32768;	 	dmap->raw_buf = NULL;	dmap->buffsize = dma_buffsize;	if (dmap->buffsize > dma_pagesize)		dmap->buffsize = dma_pagesize;	start_addr = NULL;	/*	 * Now loop until we get a free buffer. Try to get smaller buffer if	 * it fails. Don't accept smaller than 8k buffer for performance	 * reasons.	 */	while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) {		for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);		dmap->buffsize = PAGE_SIZE * (1 << sz);		start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz);		if (start_addr == NULL)			dmap->buffsize /= 2;	}	if (start_addr == NULL) {		printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n");		return -ENOMEM;	} else {		/* make some checks */		end_addr = start_addr + dmap->buffsize - 1;		if (debugmem)			printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr);				/* now check if it fits into the same dma-pagesize */		if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1))		    || end_addr >= (char *) (MAX_DMA_ADDRESS)) {			printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize);			return -EFAULT;		}	}	dmap->raw_buf = start_addr;	dmap->raw_buf_phys = virt_to_bus(start_addr);	for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)		mem_map_reserve(page);	return 0;}static void sound_free_dmap(struct dma_buffparms *dmap){	int sz, size;	struct page *page;	unsigned long start_addr, end_addr;	if (dmap->raw_buf == NULL)		return;	if (dmap->mapping_flags & DMA_MAP_MAPPED)		return;		/* Don't free mmapped buffer. Will use it next time */	for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1);	start_addr = (unsigned long) dmap->raw_buf;	end_addr = start_addr + dmap->buffsize;	for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++)		mem_map_unreserve(page);	free_pages((unsigned long) dmap->raw_buf, sz);	dmap->raw_buf = NULL;}/* Intel version !!!!!!!!! */static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode){	unsigned long flags;	int chan = dmap->dma;	/* printk( "Start DMA%d %d, %d\n",  chan,  (int)(physaddr-dmap->raw_buf_phys),  count); */	flags = claim_dma_lock();	disable_dma(chan);	clear_dma_ff(chan);	set_dma_mode(chan, dma_mode);	set_dma_addr(chan, physaddr);	set_dma_count(chan, count);	enable_dma(chan);	release_dma_lock(flags);	return 0;}static void dma_init_buffers(struct dma_buffparms *dmap){	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;	dmap->byte_counter = 0;	dmap->max_byte_counter = 8000 * 60 * 60;	dmap->bytes_in_use = dmap->buffsize;	dmap->dma_mode = DMODE_NONE;	dmap->mapping_flags = 0;	dmap->neutral_byte = 0x80;	dmap->data_rate = 8000;	dmap->cfrag = -1;	dmap->closing = 0;	dmap->nbufs = 1;	dmap->flags = DMA_BUSY;	/* Other flags off */}static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap){	int err;		if (dmap->flags & DMA_BUSY)		return -EBUSY;	if ((err = sound_alloc_dmap(dmap)) < 0)		return err;	if (dmap->raw_buf == NULL) {		printk(KERN_WARNING "Sound: DMA buffers not available\n");		return -ENOSPC;	/* Memory allocation failed during boot */	}	if (dmap->dma >= 0 && sound_open_dma(dmap->dma, adev->name)) {		printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma);		return -EBUSY;	}	dma_init_buffers(dmap);	dmap->open_mode = mode;	dmap->subdivision = dmap->underrun_count = 0;	dmap->fragment_size = 0;	dmap->max_fragments = 65536;	/* Just a large value */	dmap->byte_counter = 0;	dmap->max_byte_counter = 8000 * 60 * 60;	dmap->applic_profile = APF_NORMAL;	dmap->needs_reorg = 1;	dmap->audio_callback = NULL;	dmap->callback_parm = 0;	return 0;}static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap){	unsigned long flags;		if (dmap->dma >= 0) {		sound_close_dma(dmap->dma);		flags=claim_dma_lock();		disable_dma(dmap->dma);		release_dma_lock(flags);	}	if (dmap->flags & DMA_BUSY)		dmap->dma_mode = DMODE_NONE;	dmap->flags &= ~DMA_BUSY;		if (sound_dmap_flag == DMAP_FREE_ON_CLOSE)		sound_free_dmap(dmap);}static unsigned int default_set_bits(int dev, unsigned int bits){	mm_segment_t fs = get_fs();	set_fs(get_ds());	audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t)&bits);	set_fs(fs);	return bits;}static int default_set_speed(int dev, int speed){	mm_segment_t fs = get_fs();	set_fs(get_ds());	audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t)&speed);	set_fs(fs);	return speed;}static short default_set_channels(int dev, short channels){	int c = channels;	mm_segment_t fs = get_fs();	set_fs(get_ds());	audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t)&c);	set_fs(fs);	return c;}static void check_driver(struct audio_driver *d){	if (d->set_speed == NULL)		d->set_speed = default_set_speed;	if (d->set_bits == NULL)		d->set_bits = default_set_bits;	if (d->set_channels == NULL)		d->set_channels = default_set_channels;}int DMAbuf_open(int dev, int mode){	struct audio_operations *adev = audio_devs[dev];	int retval;	struct dma_buffparms *dmap_in = NULL;	struct dma_buffparms *dmap_out = NULL;	if (!adev)		  return -ENXIO;	if (!(adev->flags & DMA_DUPLEX))		adev->dmap_in = adev->dmap_out;	check_driver(adev->d);	if ((retval = adev->d->open(dev, mode)) < 0)		return retval;	dmap_out = adev->dmap_out;	dmap_in = adev->dmap_in;	if (dmap_in == dmap_out)		adev->flags &= ~DMA_DUPLEX;	if (mode & OPEN_WRITE) {		if ((retval = open_dmap(adev, mode, dmap_out)) < 0) {			adev->d->close(dev);			return retval;		}	}	adev->enable_bits = mode;	if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) {		if ((retval = open_dmap(adev, mode, dmap_in)) < 0) {			adev->d->close(dev);			if (mode & OPEN_WRITE)				close_dmap(adev, dmap_out);			return retval;		}	}	adev->open_mode = mode;	adev->go = 1;	adev->d->set_bits(dev, 8);	adev->d->set_channels(dev, 1);	adev->d->set_speed(dev, DSP_DEFAULT_SPEED);	if (adev->dmap_out->dma_mode == DMODE_OUTPUT) 		memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte,		       adev->dmap_out->bytes_in_use);	return 0;}void DMAbuf_reset(int dev){	if (audio_devs[dev]->open_mode & OPEN_WRITE)		dma_reset_output(dev);	if (audio_devs[dev]->open_mode & OPEN_READ)		dma_reset_input(dev);}static void dma_reset_output(int dev){	struct audio_operations *adev = audio_devs[dev];	unsigned long flags,f ;	struct dma_buffparms *dmap = adev->dmap_out;	if (!(dmap->flags & DMA_STARTED))	/* DMA is not active */		return;	/*	 *	First wait until the current fragment has been played completely	 */	save_flags(flags);	cli();	adev->dmap_out->flags |= DMA_SYNCING;	adev->dmap_out->underrun_count = 0;	if (!signal_pending(current) && adev->dmap_out->qlen && 	    adev->dmap_out->underrun_count == 0)		interruptible_sleep_on_timeout(&adev->out_sleeper,					       dmabuf_timeout(dmap));	adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);	/*	 *	Finally shut the device off	 */	if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output)		adev->d->halt_io(dev);	else		adev->d->halt_output(dev);	adev->dmap_out->flags &= ~DMA_STARTED;		f=claim_dma_lock();	clear_dma_ff(dmap->dma);	disable_dma(dmap->dma);	release_dma_lock(f);		restore_flags(flags);	dmap->byte_counter = 0;	reorganize_buffers(dev, adev->dmap_out, 0);	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;}static void dma_reset_input(int dev){        struct audio_operations *adev = audio_devs[dev];	unsigned long flags;	struct dma_buffparms *dmap = adev->dmap_in;	save_flags(flags);	cli();	if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input)		adev->d->halt_io(dev);	else		adev->d->halt_input(dev);	adev->dmap_in->flags &= ~DMA_STARTED;	restore_flags(flags);	dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0;	dmap->byte_counter = 0;	reorganize_buffers(dev, adev->dmap_in, 1);}void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap){	struct audio_operations *adev = audio_devs[dev];	if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT))		return;		/* Don't start DMA yet */	dmap->dma_mode = DMODE_OUTPUT;	if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) {		if (!(dmap->flags & DMA_STARTED)) {			reorganize_buffers(dev, dmap, 0);			if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs))				return;			if (!(dmap->flags & DMA_NODMA))				local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE);			dmap->flags |= DMA_STARTED;		}		if (dmap->counts[dmap->qhead] == 0)			dmap->counts[dmap->qhead] = dmap->fragment_size;		dmap->dma_mode = DMODE_OUTPUT;		adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size,				      dmap->counts[dmap->qhead], 1);		if (adev->d->trigger)			adev->d->trigger(dev,adev->enable_bits * adev->go);	}	dmap->flags |= DMA_ACTIVE;}int DMAbuf_sync(int dev){	struct audio_operations *adev = audio_devs[dev];	unsigned long flags;	int n = 0;	struct dma_buffparms *dmap;	if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT))		return 0;	if (adev->dmap_out->dma_mode == DMODE_OUTPUT) {

⌨️ 快捷键说明

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