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

📄 audio.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sound/audio.c * * Device file manager for /dev/audio *//* * 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   : ioctl code reworked (vmalloc/vfree removed) * 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   : use more logical O_NONBLOCK semantics * Daniel Rodriksson: reworked the use of the device specific copy_user *                    still generic * Horst von Brand:  Add missing #include <linux/string.h> */#include <linux/stddef.h>#include <linux/string.h>#include <linux/kmod.h>#include "sound_config.h"#include "ulaw.h"#include "coproc.h"#define NEUTRAL8	0x80#define NEUTRAL16	0x00int             dma_ioctl(int dev, unsigned int cmd, caddr_t arg);static int set_format(int dev, int fmt){	if (fmt != AFMT_QUERY)	{		audio_devs[dev]->local_conversion = 0;		if (!(audio_devs[dev]->format_mask & fmt))	/* Not supported */		{			if (fmt == AFMT_MU_LAW)			{				fmt = AFMT_U8;				audio_devs[dev]->local_conversion = CNV_MU_LAW;			}			else				fmt = AFMT_U8;	/* This is always supported */		}		audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt);		audio_devs[dev]->local_format = fmt;	}	else		return audio_devs[dev]->local_format;	if (audio_devs[dev]->local_conversion)		return audio_devs[dev]->local_conversion;	else 		return audio_devs[dev]->local_format;}int audio_open(int dev, struct file *file){	int ret;	int bits;	int dev_type = dev & 0x0f;	int mode = translate_mode(file);	dev = dev >> 4;	if (dev_type == SND_DEV_DSP16)		bits = 16;	else		bits = 8;	if (dev < 0 || dev >= num_audiodevs)		return -ENXIO;	if (audio_devs[dev]->d->owner)		__MOD_INC_USE_COUNT (audio_devs[dev]->d->owner);	if ((ret = DMAbuf_open(dev, mode)) < 0)		return ret;	if (audio_devs[dev]->coproc) {		if ((ret = audio_devs[dev]->coproc->			open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) {			audio_release(dev, file);			printk(KERN_WARNING "Sound: Can't access coprocessor device\n");			return ret;		}	}		audio_devs[dev]->local_conversion = 0;	if (dev_type == SND_DEV_AUDIO)		set_format(dev, AFMT_MU_LAW);	else 		set_format(dev, bits);	audio_devs[dev]->audio_mode = AM_NONE;	return ret;}static void sync_output(int dev){	int             p, i;	int             l;	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;	if (dmap->fragment_size <= 0)		return;	dmap->flags |= DMA_POST;	/* Align the write pointer with fragment boundaries */		if ((l = dmap->user_counter % dmap->fragment_size) > 0)	{		int len;		unsigned long offs = dmap->user_counter % dmap->bytes_in_use;		len = dmap->fragment_size - l;		memset(dmap->raw_buf + offs, dmap->neutral_byte, len);		DMAbuf_move_wrpointer(dev, len);	}		/*	 * Clean all unused buffer fragments.	 */	p = dmap->qtail;	dmap->flags |= DMA_POST;	for (i = dmap->qlen + 1; i < dmap->nbufs; i++)	{		p = (p + 1) % dmap->nbufs;		if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) >			(dmap->raw_buf + dmap->buffsize))				printk(KERN_ERR "audio: Buffer error 2\n");		memset(dmap->raw_buf + p * dmap->fragment_size,			dmap->neutral_byte,			dmap->fragment_size);	}	dmap->flags |= DMA_DIRTY;}void audio_release(int dev, struct file *file){	int             mode = translate_mode(file);	dev = dev >> 4;	/*	 * We do this in DMAbuf_release(). Why are we doing it	 * here? Why don't we test the file mode before setting	 * both flags? DMAbuf_release() does.	 * ...pester...pester...pester...	 */	audio_devs[dev]->dmap_out->closing = 1;	audio_devs[dev]->dmap_in->closing = 1;	/*	 * We need to make sure we allocated the dmap_out buffer	 * before we go mucking around with it in sync_output().	 */	if (mode & OPEN_WRITE)		sync_output(dev);	if (audio_devs[dev]->coproc)		audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM);	DMAbuf_release(dev, mode);	if (audio_devs[dev]->d->owner)		__MOD_DEC_USE_COUNT (audio_devs[dev]->d->owner);}static void translate_bytes(const unsigned char *table, unsigned char *buff, int n){	unsigned long   i;	if (n <= 0)		return;	for (i = 0; i < n; ++i)		buff[i] = table[buff[i]];}int audio_write(int dev, struct file *file, const char *buf, int count){	int c, p, l, buf_size, used, returned;	int err;	char *dma_buf;	dev = dev >> 4;	p = 0;	c = count;		if(count < 0)		return -EINVAL;	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))		return -EPERM;	if (audio_devs[dev]->flags & DMA_DUPLEX)		audio_devs[dev]->audio_mode |= AM_WRITE;	else		audio_devs[dev]->audio_mode = AM_WRITE;	if (!count)		/* Flush output */	{		  sync_output(dev);		  return 0;	}		while (c)	{		if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, !!(file->f_flags & O_NONBLOCK))) < 0)		{			    /* Handle nonblocking mode */			if ((file->f_flags & O_NONBLOCK) && err == -EAGAIN)				return p? p : -EAGAIN;	/* No more space. Return # of accepted bytes */			return err;		}		l = c;		if (l > buf_size)			l = buf_size;		returned = l;		used = l;		if (!audio_devs[dev]->d->copy_user)		{			if ((dma_buf + l) >				(audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize))			{				printk(KERN_ERR "audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize);				return -EDOM;			}			if (dma_buf < audio_devs[dev]->dmap_out->raw_buf)			{				printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf);				return -EDOM;			}			if(copy_from_user(dma_buf, &(buf)[p], l))				return -EFAULT;		} 		else audio_devs[dev]->d->copy_user (dev,						dma_buf, 0,						buf, p,						c, buf_size,						&used, &returned,						l);		l = returned;		if (audio_devs[dev]->local_conversion & CNV_MU_LAW)		{			/*			 * This just allows interrupts while the conversion is running			 */			sti();			translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);		}		c -= used;		p += used;		DMAbuf_move_wrpointer(dev, l);	}	return count;}int audio_read(int dev, struct file *file, char *buf, int count){	int             c, p, l;	char           *dmabuf;	int             buf_no;	dev = dev >> 4;	p = 0;	c = count;	if (!(audio_devs[dev]->open_mode & OPEN_READ))		return -EPERM;	if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))		sync_output(dev);	if (audio_devs[dev]->flags & DMA_DUPLEX)		audio_devs[dev]->audio_mode |= AM_READ;	else		audio_devs[dev]->audio_mode = AM_READ;	while(c)	{		if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, !!(file->f_flags & O_NONBLOCK))) < 0)		{			/*			 *	Nonblocking mode handling. Return current # of bytes			 */			if (p > 0) 		/* Avoid throwing away data */				return p;	/* Return it instead */			if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN)				return -EAGAIN;			return buf_no;		}		if (l > c)			l = c;		/*		 * Insert any local processing here.		 */		if (audio_devs[dev]->local_conversion & CNV_MU_LAW)		{			/*			 * This just allows interrupts while the conversion is running			 */			sti();			translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l);		}				{			char           *fixit = dmabuf;			if(copy_to_user(&(buf)[p], fixit, l))				return -EFAULT;		};		DMAbuf_rmchars(dev, buf_no, l);		p += l;		c -= l;	}	return count - c;}int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg){	int val, count;	unsigned long flags;	struct dma_buffparms *dmap;	dev = dev >> 4;	if (_IOC_TYPE(cmd) == 'C')	{		if (audio_devs[dev]->coproc)	/* Coprocessor ioctl */			return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);		/* else		        printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */		return -ENXIO;	}	else switch (cmd) 	{		case SNDCTL_DSP_SYNC:			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return 0;			if (audio_devs[dev]->dmap_out->fragment_size == 0)				return 0;			sync_output(dev);			DMAbuf_sync(dev);			DMAbuf_reset(dev);			return 0;		case SNDCTL_DSP_POST:			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return 0;			if (audio_devs[dev]->dmap_out->fragment_size == 0)				return 0;			audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;			sync_output(dev);			dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);			return 0;		case SNDCTL_DSP_RESET:			audio_devs[dev]->audio_mode = AM_NONE;			DMAbuf_reset(dev);			return 0;		case SNDCTL_DSP_GETFMTS:			val = audio_devs[dev]->format_mask | AFMT_MU_LAW;			break;			case SNDCTL_DSP_SETFMT:			if (get_user(val, (int *)arg))				return -EFAULT;			val = set_format(dev, val);			break;		case SNDCTL_DSP_GETISPACE:			if (!(audio_devs[dev]->open_mode & OPEN_READ))				return 0;  			if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))  				return -EBUSY;			return dma_ioctl(dev, cmd, arg);		case SNDCTL_DSP_GETOSPACE:			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))				return -EPERM;  			if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))  				return -EBUSY;			return dma_ioctl(dev, cmd, arg);				case SNDCTL_DSP_NONBLOCK:			file->f_flags |= O_NONBLOCK;			return 0;		case SNDCTL_DSP_GETCAPS:				val = 1 | DSP_CAP_MMAP;	/* Revision level of this ioctl() */				if (audio_devs[dev]->flags & DMA_DUPLEX &&					audio_devs[dev]->open_mode == OPEN_READWRITE)					val |= DSP_CAP_DUPLEX;				if (audio_devs[dev]->coproc)					val |= DSP_CAP_COPROC;				if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */					val |= DSP_CAP_BATCH;				if (audio_devs[dev]->d->trigger)	/* Supports SETTRIGGER */					val |= DSP_CAP_TRIGGER;				break;					case SOUND_PCM_WRITE_RATE:			if (get_user(val, (int *)arg))				return -EFAULT;			val = audio_devs[dev]->d->set_speed(dev, val);			break;		case SOUND_PCM_READ_RATE:			val = audio_devs[dev]->d->set_speed(dev, 0);			break;					case SNDCTL_DSP_STEREO:			if (get_user(val, (int *)arg))				return -EFAULT;			if (val > 1 || val < 0)				return -EINVAL;			val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1;			break;		case SOUND_PCM_WRITE_CHANNELS:			if (get_user(val, (int *)arg))				return -EFAULT;			val = audio_devs[dev]->d->set_channels(dev, val);			break;		case SOUND_PCM_READ_CHANNELS:			val = audio_devs[dev]->d->set_channels(dev, 0);			break;				case SOUND_PCM_READ_BITS:			val = audio_devs[dev]->d->set_bits(dev, 0);			break;		case SNDCTL_DSP_SETDUPLEX:			if (audio_devs[dev]->open_mode != OPEN_READWRITE)				return -EPERM;			return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO;		case SNDCTL_DSP_PROFILE:			if (get_user(val, (int *)arg))				return -EFAULT;			if (audio_devs[dev]->open_mode & OPEN_WRITE)				audio_devs[dev]->dmap_out->applic_profile = val;			if (audio_devs[dev]->open_mode & OPEN_READ)				audio_devs[dev]->dmap_in->applic_profile = val;			return 0;		

⌨️ 快捷键说明

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