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

📄 dmabuf.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
      dmap->qlen--;      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;    }  else    dmap->counts[dmap->qhead] = p;  return 0;}static intdma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact){  if (fact == 0)    {      fact = dmap->subdivision;      if (fact == 0)	fact = 1;      return snd_ioctl_return ((int *) arg, fact);    }  if (dmap->subdivision != 0 ||      dmap->fragment_size)	/* Too late to change */    return -(EINVAL);  if (fact > MAX_REALTIME_FACTOR)    return -(EINVAL);  if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)    return -(EINVAL);  dmap->subdivision = fact;  return snd_ioctl_return ((int *) arg, fact);}static intdma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact){  int             bytes, count;  if (fact == 0)    return -(EIO);  if (dmap->subdivision != 0 ||      dmap->fragment_size)	/* Too late to change */    return -(EINVAL);  bytes = fact & 0xffff;  count = (fact >> 16) & 0x7fff;  if (count == 0)    count = MAX_SUB_BUFFERS;  if (bytes < 4 || bytes > 17)	/* <16 || > 512k */    return -(EINVAL);  if (count < 2)    return -(EINVAL);  if (audio_devs[dev]->min_fragment > 0)    if (bytes < audio_devs[dev]->min_fragment)      bytes = audio_devs[dev]->min_fragment;#ifdef OS_DMA_MINBITS  if (bytes < OS_DMA_MINBITS)    bytes = OS_DMA_MINBITS;#endif  dmap->fragment_size = (1 << bytes);  dmap->max_fragments = count;  if (dmap->fragment_size > audio_devs[dev]->buffsize)    dmap->fragment_size = audio_devs[dev]->buffsize;  if (dmap->fragment_size == audio_devs[dev]->buffsize &&      audio_devs[dev]->flags & DMA_AUTOMODE)    dmap->fragment_size /= 2;	/* Needs at least 2 buffers */  dmap->subdivision = 1;	/* Disable SNDCTL_DSP_SUBDIVIDE */  if (arg)    return snd_ioctl_return ((int *) arg, bytes | (count << 16));  else    return 0;}static intget_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap){  int             pos;  unsigned long   flags;  save_flags (flags);  cli ();  if (!(dmap->flags & DMA_ACTIVE))    pos = 0;  else    {      clear_dma_ff (chan);      disable_dma (chan);      pos = get_dma_residue (chan);      enable_dma (chan);    }  restore_flags (flags);  /* printk ("%04x ", pos); */  if (audio_devs[dev]->flags & DMA_AUTOMODE)    return dmap->bytes_in_use - pos;  else    {      pos = dmap->fragment_size - pos;      if (pos < 0)	return 0;      return pos;    }}intDMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local){  struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;  struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;  long            larg = (long) arg;  switch (cmd)    {    case SOUND_PCM_WRITE_RATE:      if (local)	return audio_devs[dev]->d->set_speed (dev, larg);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg)));    case SOUND_PCM_READ_RATE:      if (local)	return audio_devs[dev]->d->set_speed (dev, 0);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0));    case SNDCTL_DSP_STEREO:      if (local)	return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1;      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1);    case SOUND_PCM_WRITE_CHANNELS:      if (local)	return audio_devs[dev]->d->set_channels (dev, (short) larg);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg)));    case SOUND_PCM_READ_CHANNELS:      if (local)	return audio_devs[dev]->d->set_channels (dev, 0);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0));    case SNDCTL_DSP_SAMPLESIZE:      if (local)	return audio_devs[dev]->d->set_bits (dev, larg);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg)));    case SOUND_PCM_READ_BITS:      if (local)	return audio_devs[dev]->d->set_bits (dev, 0);      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0));    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 (!(dmap_out->flags & DMA_ALLOC_DONE))	{	  reorganize_buffers (dev, dmap_out,			      (audio_devs[dev]->open_mode == OPEN_READ));	  if (audio_devs[dev]->flags & DMA_DUPLEX &&	      audio_devs[dev]->open_mode & OPEN_READ)	    reorganize_buffers (dev, dmap_in,				(audio_devs[dev]->open_mode == OPEN_READ));	}      return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);      break;    case SNDCTL_DSP_SUBDIVIDE:      {	int             fact = get_user ((int *) arg);	int             ret;	ret = dma_subdivide (dev, dmap_out, arg, fact);	if (ret < 0)	  return ret;	if (audio_devs[dev]->flags & DMA_DUPLEX &&	    audio_devs[dev]->open_mode & OPEN_READ)	  ret = dma_subdivide (dev, dmap_in, arg, fact);	return ret;      }      break;    case SNDCTL_DSP_SETDUPLEX:      if (audio_devs[dev]->flags & DMA_DUPLEX)	return 0;      else	return -(EIO);      break;    case SNDCTL_DSP_SETFRAGMENT:      {	int             fact = get_user ((int *) arg);	int             ret;	ret = dma_set_fragment (dev, dmap_out, arg, fact);	if (ret < 0)	  return ret;	if (audio_devs[dev]->flags & DMA_DUPLEX &&	    audio_devs[dev]->open_mode & OPEN_READ)	  ret = dma_set_fragment (dev, dmap_in, arg, fact);	return ret;      }      break;    case SNDCTL_DSP_GETISPACE:    case SNDCTL_DSP_GETOSPACE:      if (!local)	return -(EINVAL);      else	{	  struct dma_buffparms *dmap = dmap_out;	  audio_buf_info *info = (audio_buf_info *) arg;	  if (cmd == SNDCTL_DSP_GETISPACE &&	      !(audio_devs[dev]->open_mode & OPEN_READ))	    return -(EINVAL);	  if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)	    dmap = dmap_in;	  if (dmap->mapping_flags & DMA_MAP_MAPPED)	    return -(EINVAL);	  if (!(dmap->flags & DMA_ALLOC_DONE))	    reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));	  info->fragstotal = dmap->nbufs;	  if (cmd == SNDCTL_DSP_GETISPACE)	    info->fragments = dmap->qlen;	  else	    {	      if (!space_in_queue (dev))		info->fragments = 0;	      else		{		  info->fragments = dmap->nbufs - dmap->qlen;		  if (audio_devs[dev]->d->local_qlen)		    {		      int             tmp = audio_devs[dev]->d->local_qlen (dev);		      if (tmp && info->fragments)			tmp--;	/*				   * This buffer has been counted twice				 */		      info->fragments -= tmp;		    }		}	    }	  if (info->fragments < 0)	    info->fragments = 0;	  else if (info->fragments > dmap->nbufs)	    info->fragments = dmap->nbufs;	  info->fragsize = dmap->fragment_size;	  info->bytes = info->fragments * dmap->fragment_size;	  if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)	    info->bytes -= dmap->counts[dmap->qhead];	}      return 0;    case SNDCTL_DSP_SETTRIGGER:      {	unsigned long   flags;	int             bits = get_user ((int *) arg) & audio_devs[dev]->open_mode;	int             changed;	if (audio_devs[dev]->d->trigger == NULL)	  return -(EINVAL);	if (!(audio_devs[dev]->flags & DMA_DUPLEX))	  if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))	    {	      printk ("Sound: Device doesn't have full duplex capability\n");	      return -(EINVAL);	    }	save_flags (flags);	cli ();	changed = audio_devs[dev]->enable_bits ^ bits;	if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)	  {	    int             err;	    if (!(dmap_in->flags & DMA_ALLOC_DONE))	      {		reorganize_buffers (dev, dmap_in, 1);	      }	    if ((err = audio_devs[dev]->d->prepare_for_input (dev,			       dmap_in->fragment_size, dmap_in->nbufs)) < 0)	      return -(err);	    audio_devs[dev]->enable_bits = bits;	    activate_recording (dev, dmap_in);	  }	if ((changed & bits) & PCM_ENABLE_OUTPUT &&	    dmap_out->mapping_flags & DMA_MAP_MAPPED &&	    audio_devs[dev]->go)	  {	    int             err;	    if (!(dmap_out->flags & DMA_ALLOC_DONE))	      {		reorganize_buffers (dev, dmap_out, 0);	      }	    if ((err = audio_devs[dev]->d->prepare_for_output (dev,			     dmap_out->fragment_size, dmap_out->nbufs)) < 0)	      return -(err);	    dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;	    DMAbuf_start_output (dev, 0, dmap_out->fragment_size);	  }	audio_devs[dev]->enable_bits = bits;	if (changed && audio_devs[dev]->d->trigger)	  {	    audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);	  }	restore_flags (flags);      }    case SNDCTL_DSP_GETTRIGGER:      return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);      break;    case SNDCTL_DSP_SETSYNCRO:      if (!audio_devs[dev]->d->trigger)	return -(EINVAL);      audio_devs[dev]->d->trigger (dev, 0);      audio_devs[dev]->go = 0;      return 0;      break;    case SNDCTL_DSP_GETIPTR:      {	count_info      info;	unsigned long   flags;	if (!(audio_devs[dev]->open_mode & OPEN_READ))	  return -(EINVAL);	save_flags (flags);	cli ();	info.bytes = audio_devs[dev]->dmap_in->byte_counter;	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);	info.blocks = audio_devs[dev]->dmap_in->qlen;	info.bytes += info.ptr;	memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));	if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)	  audio_devs[dev]->dmap_in->qlen = 0;	/* Acknowledge interrupts */	restore_flags (flags);	return 0;      }      break;    case SNDCTL_DSP_GETOPTR:      {	count_info      info;	unsigned long   flags;	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))	  return -(EINVAL);	save_flags (flags);	cli ();	info.bytes = audio_devs[dev]->dmap_out->byte_counter;	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);	info.blocks = audio_devs[dev]->dmap_out->qlen;	info.bytes += info.ptr;	memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));	if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)	  audio_devs[dev]->dmap_out->qlen = 0;	/* Acknowledge interrupts */	restore_flags (flags);	return 0;      }      break;    default:      return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);    }}/* * DMAbuf_start_devices() is called by the /dev/music driver to start * one or more audio devices at desired moment. */voidDMAbuf_start_devices (unsigned int devmask){  int             dev;  for (dev = 0; dev < num_audiodevs; dev++)    if (devmask & (1 << dev))      if (audio_devs[dev]->open_mode != 0)	if (!audio_devs[dev]->go)	  {	    /* OK to start the device */	    audio_devs[dev]->go = 1;	    if (audio_devs[dev]->d->trigger)	      audio_devs[dev]->d->trigger (dev,			audio_devs[dev]->enable_bits * audio_devs[dev]->go);	  }}static intspace_in_queue (int dev){  int             len, max, tmp;  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;  if (dmap->qlen >= dmap->nbufs)	/* No space at all */    return 0;  /*     * Verify that there are no more pending buffers than the limit     * defined by the process.   */  max = dmap->max_fragments;  len = dmap->qlen;  if (audio_devs[dev]->d->local_qlen)    {      tmp = audio_devs[dev]->d->local_qlen (dev);      if (tmp && len)	tmp--;			/*				   * This buffer has been counted twice				 */      len += tmp;    }  if (len >= max)    return 0;  return 1;}intDMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock){  unsigned long   flags;  int             abort, err = EIO;  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;  dmap->flags &= ~DMA_CLEAN;  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)    {      printk ("Sound: Can't write to mmapped device (3)\n");      return -(EINVAL);    }  if (dmap->dma_mode == DMODE_INPUT)	/* Direction change */    {      dma_reset (dev);      dmap->dma_mode = DMODE_NONE;    }  else if (dmap->flags & DMA_RESTART)	/* Restart buffering */    {      dma_sync (dev);      dma_reset_output (dev);    }  dmap->flags &= ~(DMA_RESTART | DMA_EMPTY);  if (!(dmap->flags & DMA_ALLOC_DONE))    reorganize_buffers (dev, dmap, 0);  if (!dmap->dma_mode)    {      int             err;      dmap->dma_mode = DMODE_OUTPUT;      if ((err = audio_devs[dev]->d->prepare_for_output (dev,				     dmap->fragment_size, dmap->nbufs)) < 0)	return err;    }  save_flags (flags);  cli ();  abort = 0;  while (!space_in_queue (dev) &&	 !abort)    {      int             tmout;      if (dontblock)	{	  restore_flags (flags);	  return -(EAGAIN);	}      if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&	  audio_devs[dev]->go)	{	  restore_flags (flags);	  return -(EAGAIN);	}      /*       * Wait for free space       */      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;	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))	{	  printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");	  err = EIO;	  abort = 1;	  ;	  if (audio_devs[dev]->flags & DMA_AUTOMODE)	    dmap->flags |= DMA_RESTART;	  else	    dmap->flags &= ~DMA_RESTART;	  audio_devs[dev]->d->reset (dev);	}      else if (current_got_fatal_signal ())	{	  err = EINTR;	  abort = 1;	}    }  restore_flags (flags);  if (!space_in_queue (dev))    {      return -(err);		/* Caught a signal ? */    }  *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;  *size = dmap->fragment_size;  dmap->counts[dmap->qtail] = 0;  return dmap->qtail;}intDMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size){  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;  if (dmap->cfrag < 0)    return -1;  *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;  *buf_ptr = dmap->counts[dmap->qtail];  *buf_size = dmap->fragment_size;  return *buf_no = dmap->cfrag;}intDMAbuf_set_count (int dev, int buff_no, int l){  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;  if (buff_no == dmap->qtail)    {      dmap->cfrag = buff_no;      dmap->counts[buff_no] = l;    }  else    dmap->cfrag = -1;  return 0;}intDMAbuf_start_output (int dev, int buff_no, int l){  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;  int             restart = 0;  dmap->cfrag = -1;  if (dmap->flags & DMA_RESTART)    restart = 1;/* * Bypass buffering if using mmapped access */  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)    {      l = dmap->fragment_size;      dmap->counts[dmap->qtail] = l;      dmap->flags &= ~DMA_RESTART;

⌨️ 快捷键说明

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