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

📄 dmabuf.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/dmabuf.c * * The DMA buffer manager for digitized voice applications *//* * Copyright (C) by Hannu Savolainen 1993-1996 * * USS/Lite 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. */#include <linux/config.h>#include "sound_config.h"#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)static wait_handle *in_sleeper[MAX_AUDIO_DEV] ={NULL};static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] ={  {0}};static wait_handle *out_sleeper[MAX_AUDIO_DEV] ={NULL};static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] ={  {0}};#define NEUTRAL8	0x80#define NEUTRAL16	0x00static int      ndmaps = 0;#define MAX_DMAP (MAX_AUDIO_DEV*2)static struct dma_buffparms dmaps[MAX_DMAP] ={  {0}};static int      space_in_queue (int dev);static void     dma_reset_output (int dev);static void     dma_reset_input (int dev);static int      dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact);static voidreorganize_buffers (int dev, struct dma_buffparms *dmap, int recording){  /*   * This routine breaks the physical device buffers to logical ones.   */  struct audio_operations *dsp_dev = audio_devs[dev];  unsigned        i, n;  unsigned        sr, nc, sz, bsz;  if (dmap->fragment_size == 0)    {				/* Compute the fragment size using the default algorithm */      sr = dsp_dev->d->set_speed (dev, 0);      nc = dsp_dev->d->set_channels (dev, 0);      sz = dsp_dev->d->set_bits (dev, 0);      if (sz == 8)	dmap->neutral_byte = NEUTRAL8;      else	dmap->neutral_byte = NEUTRAL16;      if (sr < 1 || nc < 1 || sz < 1)	{	  printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",		  dev, sr, nc, sz);	  sr = DSP_DEFAULT_SPEED;	  nc = 1;	  sz = 8;	}      sz = sr * nc * sz;      sz /= 8;			/* #bits -> #bytes */      /*         * Compute a buffer size for time not exceeding 1 second.         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds         * of sound (using the current speed, sample size and #channels).       */      bsz = dsp_dev->buffsize;      while (bsz > sz)	bsz /= 2;      if (bsz == dsp_dev->buffsize)	bsz /= 2;		/* Needs at least 2 buffers *//* *    Split the computed fragment to smaller parts. After 3.5a9 *      the default subdivision is 4 which should give better *      results when recording. */      if (dmap->subdivision == 0)	/* Not already set */	{	  dmap->subdivision = 1;	/* Init to the default value */#ifndef V35A9_COMPATIBLE	  if (recording)	    dmap->subdivision = 4;	/* Use shorter fragments when recording */#endif	}      bsz /= dmap->subdivision;      if (bsz < 16)	bsz = 16;		/* Just a sanity check */      dmap->fragment_size = bsz;    }  else    {      /*         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or         * the buffer size computation has already been done.       */      if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))	dmap->fragment_size = (audio_devs[dev]->buffsize / 2);      bsz = dmap->fragment_size;    }  bsz &= ~0x03;			/* Force size which is multiple of 4 bytes */#ifdef OS_DMA_ALIGN_CHECK  OS_DMA_ALIGN_CHECK (bsz);#endif  n = dsp_dev->buffsize / bsz;  if (n > MAX_SUB_BUFFERS)    n = MAX_SUB_BUFFERS;  if (n > dmap->max_fragments)    n = dmap->max_fragments;  dmap->nbufs = n;  dmap->bytes_in_use = n * bsz;  if (dmap->raw_buf)    memset (dmap->raw_buf,	    dmap->neutral_byte,	    dmap->bytes_in_use);  for (i = 0; i < dmap->nbufs; i++)    {      dmap->counts[i] = 0;    }  dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;}static voiddma_init_buffers (int dev, struct dma_buffparms *dmap){  if (dmap == audio_devs[dev]->dmap_out)    {      out_sleep_flag[dev].flags = WK_NONE;    }  else    {      in_sleep_flag[dev].flags = WK_NONE;    }  dmap->flags = DMA_BUSY;	/* Other flags off */  dmap->qlen = dmap->qhead = dmap->qtail = 0;  dmap->nbufs = 1;  dmap->bytes_in_use = audio_devs[dev]->buffsize;  dmap->dma_mode = DMODE_NONE;  dmap->mapping_flags = 0;  dmap->neutral_byte = NEUTRAL8;  dmap->cfrag = -1;  dmap->closing = 0;}static intopen_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan){  if (dmap->flags & DMA_BUSY)    return -(EBUSY);  {    int             err;    if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0)      return err;  }  if (dmap->raw_buf == NULL)    return -(ENOSPC);		/* Memory allocation failed during boot */  if (sound_open_dma (chan, audio_devs[dev]->name))    {      printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);      return -(EBUSY);    }  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;  dma_init_buffers (dev, dmap);  return 0;}static voidclose_dmap (int dev, struct dma_buffparms *dmap, int chan){  sound_close_dma (chan);  if (dmap->flags & DMA_BUSY)    dmap->dma_mode = DMODE_NONE;  dmap->flags &= ~DMA_BUSY;  disable_dma (chan);  sound_free_dmap (dev, dmap);}static unsigned intdefault_set_bits (int dev, unsigned int bits){  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) (long) bits, 1);}static intdefault_set_speed (int dev, int speed){  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) (long) speed, 1);}static shortdefault_set_channels (int dev, short channels){  int             c = channels;  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) (long) c, 1);}static voidcheck_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;}intDMAbuf_open (int dev, int mode){  int             retval;  struct dma_buffparms *dmap_in = NULL;  struct dma_buffparms *dmap_out = NULL;  if (dev >= num_audiodevs)    {      /*  printk ("PCM device %d not installed.\n", dev); */      return -(ENXIO);    }  if (!audio_devs[dev])    {      /* printk ("PCM device %d not initialized\n", dev); */      return -(ENXIO);    }  if (!(audio_devs[dev]->flags & DMA_DUPLEX))    {      audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;      audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;    }  if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)    return retval;  check_driver (audio_devs[dev]->d);  dmap_out = audio_devs[dev]->dmap_out;  dmap_in = audio_devs[dev]->dmap_in;  if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0)    {      audio_devs[dev]->d->close (dev);      return retval;    }  audio_devs[dev]->enable_bits = mode;  if (mode & OPEN_READ &&      audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)    if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)      {	audio_devs[dev]->d->close (dev);	close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1);	return retval;      }  audio_devs[dev]->open_mode = mode;  audio_devs[dev]->go = 1;  in_sleep_flag[dev].flags = WK_NONE;  out_sleep_flag[dev].flags = WK_NONE;  audio_devs[dev]->d->set_bits (dev, 8);  audio_devs[dev]->d->set_channels (dev, 1);  audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED);  return 0;}static voiddma_reset (int dev){  unsigned long   flags;  save_flags (flags);  cli ();  audio_devs[dev]->d->reset (dev);  restore_flags (flags);  dma_reset_output (dev);  if (audio_devs[dev]->flags & DMA_DUPLEX &&      audio_devs[dev]->open_mode & OPEN_READ)    dma_reset_input (dev);}static voiddma_reset_output (int dev){  unsigned long   flags;  save_flags (flags);  cli ();  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||      !audio_devs[dev]->d->halt_output)    audio_devs[dev]->d->reset (dev);  else    audio_devs[dev]->d->halt_output (dev);  restore_flags (flags);  dma_init_buffers (dev, audio_devs[dev]->dmap_out);  reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);}static voiddma_reset_input (int dev){  unsigned long   flags;  save_flags (flags);  cli ();  if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||      !audio_devs[dev]->d->halt_input)    audio_devs[dev]->d->reset (dev);  else    audio_devs[dev]->d->halt_input (dev);  restore_flags (flags);  dma_init_buffers (dev, audio_devs[dev]->dmap_in);  reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);}static intdma_sync (int dev){  unsigned long   flags;  if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))    return 0;  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)    {      save_flags (flags);      cli ();      audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;      audio_devs[dev]->dmap_out->underrun_count = 0;      while (!current_got_fatal_signal ()	     && audio_devs[dev]->dmap_out->qlen	     && audio_devs[dev]->dmap_out->underrun_count == 0)	{	  {	    unsigned long   tlimit;	    if (HZ)	      current_set_timeout (tlimit = jiffies + (HZ));	    else	      tlimit = (unsigned long) -1;	    out_sleep_flag[dev].flags = WK_SLEEP;	    module_interruptible_sleep_on (&out_sleeper[dev]);	    if (!(out_sleep_flag[dev].flags & WK_WAKEUP))	      {		if (jiffies >= tlimit)		  out_sleep_flag[dev].flags |= WK_TIMEOUT;	      }	    out_sleep_flag[dev].flags &= ~WK_SLEEP;	  };	  if ((out_sleep_flag[dev].flags & WK_TIMEOUT))	    {	      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;	      restore_flags (flags);	      return audio_devs[dev]->dmap_out->qlen;	    }	}      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;      restore_flags (flags);      /*       * Some devices such as GUS have huge amount of on board RAM for the       * audio data. We have to wait until the device has finished playing.       */      save_flags (flags);      cli ();      if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */	{	  while (!(current_got_fatal_signal ())		 && audio_devs[dev]->d->local_qlen (dev))	    {	      {		unsigned long   tlimit;		if (HZ)		  current_set_timeout (tlimit = jiffies + (HZ));		else		  tlimit = (unsigned long) -1;		out_sleep_flag[dev].flags = WK_SLEEP;		module_interruptible_sleep_on (&out_sleeper[dev]);		if (!(out_sleep_flag[dev].flags & WK_WAKEUP))		  {		    if (jiffies >= tlimit)		      out_sleep_flag[dev].flags |= WK_TIMEOUT;		  }		out_sleep_flag[dev].flags &= ~WK_SLEEP;	      };	    }	}      restore_flags (flags);    }  return audio_devs[dev]->dmap_out->qlen;}intDMAbuf_release (int dev, int mode){  unsigned long   flags;  audio_devs[dev]->dmap_out->closing = 1;  audio_devs[dev]->dmap_in->closing = 1;  if (!(current_got_fatal_signal ())      && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))    {      dma_sync (dev);    }  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)    memset (audio_devs[dev]->dmap_out->raw_buf,	    audio_devs[dev]->dmap_out->neutral_byte,	    audio_devs[dev]->dmap_out->bytes_in_use);  save_flags (flags);  cli ();  audio_devs[dev]->d->halt_xfer (dev);  audio_devs[dev]->d->close (dev);  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);  if (audio_devs[dev]->open_mode & OPEN_READ &&      audio_devs[dev]->flags & DMA_DUPLEX)    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);  audio_devs[dev]->open_mode = 0;  restore_flags (flags);  return 0;}static intactivate_recording (int dev, struct dma_buffparms *dmap){  int             prepare = 0;  if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))    return 0;  if (dmap->flags & DMA_RESTART)    {      dma_reset_input (dev);      dmap->flags &= ~DMA_RESTART;      prepare = 1;    }  if (dmap->dma_mode == DMODE_OUTPUT)	/* Direction change */    {      dma_sync (dev);      dma_reset (dev);      dmap->dma_mode = DMODE_NONE;    }  if (!(dmap->flags & DMA_ALLOC_DONE))    reorganize_buffers (dev, dmap, 1);  if (prepare || !dmap->dma_mode)    {      int             err;      if ((err = audio_devs[dev]->d->prepare_for_input (dev,				     dmap->fragment_size, dmap->nbufs)) < 0)	{	  return err;	}      dmap->dma_mode = DMODE_INPUT;    }  if (!(dmap->flags & DMA_ACTIVE))    {      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +				       dmap->qtail * dmap->fragment_size,				       dmap->fragment_size, 0,				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||				       !(dmap->flags & DMA_STARTED));      dmap->flags |= DMA_ACTIVE | DMA_STARTED;      if (audio_devs[dev]->d->trigger)	audio_devs[dev]->d->trigger (dev,			audio_devs[dev]->enable_bits * audio_devs[dev]->go);    }  return 0;}intDMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock){  unsigned long   flags;  int             err = EIO;  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;  save_flags (flags);  cli ();  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)    {      printk ("Sound: Can't read from mmapped device (1)\n");      return -(EINVAL);    }  else if (!dmap->qlen)    {      int             tmout;      if ((err = activate_recording (dev, dmap)) < 0)	{	  restore_flags (flags);	  return err;	}      /* Wait for the next block */      if (dontblock)	{	  restore_flags (flags);	  return -(EAGAIN);	}      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &	  audio_devs[dev]->go)	{	  restore_flags (flags);	  return -(EAGAIN);	}      if (!audio_devs[dev]->go)	tmout = 0;      else	tmout = 10 * HZ;      {	unsigned long   tlimit;	if (tmout)	  current_set_timeout (tlimit = jiffies + (tmout));	else	  tlimit = (unsigned long) -1;	in_sleep_flag[dev].flags = WK_SLEEP;	module_interruptible_sleep_on (&in_sleeper[dev]);	if (!(in_sleep_flag[dev].flags & WK_WAKEUP))	  {	    if (jiffies >= tlimit)	      in_sleep_flag[dev].flags |= WK_TIMEOUT;	  }	in_sleep_flag[dev].flags &= ~WK_SLEEP;      };      if ((in_sleep_flag[dev].flags & WK_TIMEOUT))	{	  printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");	  err = EIO;	  audio_devs[dev]->d->reset (dev);	  ;	}      else	err = EINTR;    }  restore_flags (flags);  if (!dmap->qlen)    return -(err);  *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];  *len = dmap->fragment_size - dmap->counts[dmap->qhead];  return dmap->qhead;}intDMAbuf_rmchars (int dev, int buff_no, int c){  struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;  int             p = dmap->counts[dmap->qhead] + c;  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)    {      printk ("Sound: Can't read from mmapped device (2)\n");      return -(EINVAL);    }  else if (p >= dmap->fragment_size)    {				/* This buffer is completely empty */      dmap->counts[dmap->qhead] = 0;      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)	printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",		dev, dmap->qlen, dmap->nbufs);

⌨️ 快捷键说明

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