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

📄 dmabuf.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * sound/dmabuf.c *  * The DMA buffer manager for digitized voice applications *  * Copyright by Hannu Savolainen 1993 *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. *  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *  */#include "sound_config.h"#ifdef CONFIGURE_SOUNDCARD#include "sound_calls.h"#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)#define MAX_SUB_BUFFERS		(32*MAX_REALTIME_FACTOR)/* * The DSP channel can be used either for input or output. Variable * 'dma_mode' will be set when the program calls read or write first time * after open. Current version doesn't support mode changes without closing * and reopening the device. Support for this feature may be implemented in a * future version of this driver. */#define DMODE_NONE		0#define DMODE_OUTPUT		1#define DMODE_INPUT		2DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);static int      dma_mode[MAX_DSP_DEV] ={0};				/* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */static volatile int dmabuf_interrupted[MAX_DSP_DEV] ={0};/* * Pointers to raw buffers */char           *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] ={  {NULL}};unsigned long   snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];int             snd_raw_count[MAX_DSP_DEV];/* * Device state tables */static int      dev_busy[MAX_DSP_DEV];static int      dev_needs_restart[MAX_DSP_DEV];static int      dev_modes[MAX_DSP_DEV];static int      dev_active[MAX_DSP_DEV];static int      dev_started[MAX_DSP_DEV];static int      dev_qlen[MAX_DSP_DEV];static int      dev_qhead[MAX_DSP_DEV];static int      dev_qtail[MAX_DSP_DEV];static int      dev_underrun[MAX_DSP_DEV];static int      bufferalloc_done[MAX_DSP_DEV] ={0};/* * Logical buffers for each devices */static int      dev_nbufs[MAX_DSP_DEV];	/* # of logical buffers ( >=					 * sound_buffcounts[dev] */static int      dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];static int      dev_subdivision[MAX_DSP_DEV];static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];static char    *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =  {{NULL}};static int      dev_buffsize[MAX_DSP_DEV];static voidreorganize_buffers (int dev){  /*   * This routine breaks the physical device buffers to logical ones.   */  unsigned i, p, n;  unsigned sr, nc, sz, bsz;  sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);  nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);  sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);  if (sr < 1 || nc < 1 || sz < 1)    {      printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);      sr = DSP_DEFAULT_SPEED;      nc = 1;      sz = 8;    }  sz /= 8;			/* Convert # of bits -> # of bytes */  sz = sr * nc * sz;  /*   * Compute a buffer size not exeeding 1 second.   */  bsz = sound_buffsizes[dev];  while (bsz > sz)    bsz >>= 1;			/* Divide by 2 */  if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])    bsz >>= 1;			/* Need at least 2 buffers */  if (dev_subdivision[dev] == 0)     dev_subdivision[dev] = 1;	/* Default value */  bsz /= dev_subdivision[dev];	/* Use smaller buffers */  if (bsz == 0) bsz = 4096;	/* Just a sanity check */  while ((sound_buffsizes[dev]*sound_buffcounts[dev])/bsz > MAX_SUB_BUFFERS)  	bsz <<= 1;	/* Too much buffers */  dev_buffsize[dev] = bsz;  n = 0;  /*   * Now computing addresses for the logical buffers   */  for (i = 0; i < snd_raw_count[dev]; i++)    {      p = 0;      while ((p + bsz) <= sound_buffsizes[dev])	{	  dev_buf[dev][n] = snd_raw_buf[dev][i] + p;	  dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p;	  p += bsz;	  n++;	}    }  dev_nbufs[dev] = n;  for (i = 0; i < dev_nbufs[dev]; i++)    {      dev_counts[dev][i] = 0;    }  bufferalloc_done[dev] = 1;}static voiddma_init_buffers(int dev){  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);  dev_underrun[dev] = 0;  dev_busy[dev] = 1;  bufferalloc_done[dev] = 0;  dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;  dev_needs_restart[dev] = dev_started[dev] = 0;  dma_mode[dev] = DMODE_NONE;}intDMAbuf_open (int dev, int mode){  int             retval;  if (dev >= num_dspdevs)    {      printk ("PCM device %d not installed.\n", dev);      return RET_ERROR (ENXIO);    }  if (dev_busy[dev])    return RET_ERROR (EBUSY);  if (!dsp_devs[dev])    {      printk ("DSP device %d not initialized\n", dev);      return RET_ERROR (ENXIO);    }#ifdef USE_RUNTIME_DMAMEM  sound_dma_malloc(dev);#endif  if (snd_raw_buf[dev][0] == NULL)    return RET_ERROR (ENOSPC);	/* Memory allocation failed during boot */  if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)    return retval;  dev_modes[dev] = mode;  dev_subdivision[dev] = 0;  dma_init_buffers(dev);  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);  return 0;}static voiddma_reset (int dev){  int retval;  unsigned long flags;  DISABLE_INTR(flags);  dsp_devs[dev]->reset (dev);  dsp_devs[dev]->close (dev);  if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)    printk("Sound: Reset failed - Can't reopen device\n");  RESTORE_INTR(flags);  dma_init_buffers(dev);  reorganize_buffers(dev);}static intdma_sync (int dev){  unsigned long   flags;  unsigned long   time;  int             timed_out;  if (dma_mode[dev] == DMODE_OUTPUT)    {      DISABLE_INTR (flags);      timed_out = 0;      time = GET_TIME ();      while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||		dmabuf_interrupted[dev]) && !timed_out)	     && dev_qlen[dev])	{	  DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);	  if ((GET_TIME () - time) > (10 * HZ))	    timed_out = 1;	}      RESTORE_INTR (flags);      /*       * Some devices such as GUS have huge amount of on board RAM for the       * audio data. We have to wait util the device has finished playing.       */      DISABLE_INTR (flags);      if (dsp_devs[dev]->has_output_drained)	/* Device has hidden buffers */	{	  while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||		   dmabuf_interrupted[dev])		 && !dsp_devs[dev]->has_output_drained (dev))	    {	      DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);	    }	}      RESTORE_INTR (flags);    }  return dev_qlen[dev];}intDMAbuf_release (int dev, int mode){  if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||	dmabuf_interrupted[dev])      && (dma_mode[dev] == DMODE_OUTPUT))    {      dma_sync (dev);    }#ifdef USE_RUNTIME_DMAMEM  sound_dma_free(dev);#endif  dsp_devs[dev]->reset (dev);  dsp_devs[dev]->close (dev);  dma_mode[dev] = DMODE_NONE;  dev_busy[dev] = 0;  return 0;}intDMAbuf_getrdbuffer (int dev, char **buf, int *len){  unsigned long   flags;  int err = EIO;  DISABLE_INTR (flags);  if (!dev_qlen[dev])    {      if (dev_needs_restart[dev])      {	dma_reset(dev);	dev_needs_restart[dev] = 0;      }  if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */  {	dma_sync(dev);	dma_reset(dev);	dma_mode[dev] = DMODE_NONE;  }  if (!bufferalloc_done[dev])    reorganize_buffers (dev);  if (!dma_mode[dev])    {      int             err;      if ((err = dsp_devs[dev]->prepare_for_input (dev,				    dev_buffsize[dev], dev_nbufs[dev])) < 0)	{          RESTORE_INTR (flags);	  return err; 	}      dma_mode[dev] = DMODE_INPUT;    }      if (!dev_active[dev])	{	  dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], 				      dev_buffsize[dev], 0,				      !sound_dma_automode[dev] || 				      !dev_started[dev]);	  dev_active[dev] = 1;	  dev_started[dev] = 1;	}      /* Wait for the next block */      DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);      if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))	{	  printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");	  err = EIO;	  SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);	}      else	err = EINTR;    }  RESTORE_INTR (flags);  if (!dev_qlen[dev])    return RET_ERROR (err);  *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];  *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];  return dev_qhead[dev];}intDMAbuf_rmchars (int dev, int buff_no, int c){  int             p = dev_counts[dev][dev_qhead[dev]] + c;  if (p >= dev_buffsize[dev])    {				/* This buffer is now empty */      dev_counts[dev][dev_qhead[dev]] = 0;      dev_qlen[dev]--;      dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];    }  else    dev_counts[dev][dev_qhead[dev]] = p;  return 0;}intDMAbuf_read (int dev, snd_rw_buf * user_buf, int count){  char           *dmabuf;  int             buff_no, c, err;  /*   * This routine returns at most 'count' bytes from the dsp input buffers.   * Returns negative value if there is an error.   */  if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0)    return buff_no;  if (c > count)    c = count;  COPY_TO_USER (user_buf, 0, dmabuf, c);  if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0)    return err;  return c;}intDMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){  switch (cmd)    {    case SNDCTL_DSP_RESET:      dma_reset (dev);      return 0;      break;    case SNDCTL_DSP_SYNC:      dma_sync (dev);      dma_reset (dev);      return 0;      break;    case SNDCTL_DSP_GETBLKSIZE:      if (!bufferalloc_done[dev])	reorganize_buffers (dev);

⌨️ 快捷键说明

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