dmabuf.c
来自「linux 内核源代码」· C语言 代码 · 共 1,268 行 · 第 1/3 页
C
1,268 行
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) { dmap = adev->dmap_out; spin_lock_irqsave(&dmap->lock,flags); if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) DMAbuf_launch_output(dev, dmap); adev->dmap_out->flags |= DMA_SYNCING; adev->dmap_out->underrun_count = 0; while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { long t = dmabuf_timeout(dmap); spin_unlock_irqrestore(&dmap->lock,flags); /* FIXME: not safe may miss events */ t = interruptible_sleep_on_timeout(&adev->out_sleeper, t); spin_lock_irqsave(&dmap->lock,flags); if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; spin_unlock_irqrestore(&dmap->lock,flags); return adev->dmap_out->qlen; } } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* * 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. */ /* still holding the lock */ if (adev->d->local_qlen) { /* Device has hidden buffers */ while (!signal_pending(current) && adev->d->local_qlen(dev)){ spin_unlock_irqrestore(&dmap->lock,flags); interruptible_sleep_on_timeout(&adev->out_sleeper, dmabuf_timeout(dmap)); spin_lock_irqsave(&dmap->lock,flags); } } spin_unlock_irqrestore(&dmap->lock,flags); } adev->dmap_out->dma_mode = DMODE_NONE; return adev->dmap_out->qlen;}int DMAbuf_release(int dev, int mode){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap; unsigned long flags; dmap = adev->dmap_out; if (adev->open_mode & OPEN_WRITE) adev->dmap_out->closing = 1; if (adev->open_mode & OPEN_READ){ adev->dmap_in->closing = 1; dmap = adev->dmap_in; } if (adev->open_mode & OPEN_WRITE) if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) DMAbuf_sync(dev); 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); DMAbuf_reset(dev); spin_lock_irqsave(&dmap->lock,flags); adev->d->close(dev); if (adev->open_mode & OPEN_WRITE) close_dmap(adev, adev->dmap_out); if (adev->open_mode == OPEN_READ || (adev->open_mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) close_dmap(adev, adev->dmap_in); adev->open_mode = 0; spin_unlock_irqrestore(&dmap->lock,flags); return 0;}/* called with dmap->lock dold */int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap){ struct audio_operations *adev = audio_devs[dev]; int err; if (!(adev->open_mode & OPEN_READ)) return 0; if (!(adev->enable_bits & PCM_ENABLE_INPUT)) return 0; if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ /* release lock - it's not recursive */ spin_unlock_irq(&dmap->lock); DMAbuf_sync(dev); DMAbuf_reset(dev); spin_lock_irq(&dmap->lock); dmap->dma_mode = DMODE_NONE; } if (!dmap->dma_mode) { reorganize_buffers(dev, dmap, 1); if ((err = adev->d->prepare_for_input(dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; dmap->dma_mode = DMODE_INPUT; } if (!(dmap->flags & DMA_ACTIVE)) { if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 0); dmap->flags |= DMA_ACTIVE; if (adev->d->trigger) adev->d->trigger(dev, adev->enable_bits * adev->go); } return 0;}/* acquires lock */int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock){ struct audio_operations *adev = audio_devs[dev]; unsigned long flags; int err = 0, n = 0; struct dma_buffparms *dmap = adev->dmap_in; int go; if (!(adev->open_mode & OPEN_READ)) return -EIO; spin_lock_irqsave(&dmap->lock,flags); if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) {/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ spin_unlock_irqrestore(&dmap->lock,flags); return -EINVAL; } else while (dmap->qlen <= 0 && n++ < 10) { long timeout = MAX_SCHEDULE_TIMEOUT; if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { spin_unlock_irqrestore(&dmap->lock,flags); return -EAGAIN; } if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { spin_unlock_irqrestore(&dmap->lock,flags); return err; } /* Wait for the next block */ if (dontblock) { spin_unlock_irqrestore(&dmap->lock,flags); return -EAGAIN; } if ((go = adev->go)) timeout = dmabuf_timeout(dmap); spin_unlock_irqrestore(&dmap->lock,flags); timeout = interruptible_sleep_on_timeout(&adev->in_sleeper, timeout); if (!timeout) { /* FIXME: include device name */ err = -EIO; printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); dma_reset_input(dev); } else err = -EINTR; spin_lock_irqsave(&dmap->lock,flags); } spin_unlock_irqrestore(&dmap->lock,flags); if (dmap->qlen <= 0) return err ? err : -EINTR; *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; return dmap->qhead;}int DMAbuf_rmchars(int dev, int buff_no, int c){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_in; int p = dmap->counts[dmap->qhead] + c; if (dmap->mapping_flags & DMA_MAP_MAPPED) {/* printk("Sound: Can't read from mmapped device (2)\n");*/ return -EINVAL; } else if (dmap->qlen <= 0) return -EIO; else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ dmap->counts[dmap->qhead] = 0; dmap->qlen--; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; } else dmap->counts[dmap->qhead] = p; return 0;}/* MUST be called with dmap->lock hold */int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction){ /* * Try to approximate the active byte position of the DMA pointer within the * buffer area as well as possible. */ int pos; unsigned long f; if (!(dmap->flags & DMA_ACTIVE)) pos = 0; else { int chan = dmap->dma; f=claim_dma_lock(); clear_dma_ff(chan); if(!isa_dma_bridge_buggy) disable_dma(dmap->dma); pos = get_dma_residue(chan); pos = dmap->bytes_in_use - pos; if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) { if (direction == DMODE_OUTPUT) { if (dmap->qhead == 0) if (pos > dmap->fragment_size) pos = 0; } else { if (dmap->qtail == 0) if (pos > dmap->fragment_size) pos = 0; } } if (pos < 0) pos = 0; if (pos >= dmap->bytes_in_use) pos = 0; if(!isa_dma_bridge_buggy) enable_dma(dmap->dma); release_dma_lock(f); } /* printk( "%04x ", pos); */ return pos;}/* * DMAbuf_start_devices() is called by the /dev/music driver to start * one or more audio devices at desired moment. */void DMAbuf_start_devices(unsigned int devmask){ struct audio_operations *adev; int dev; for (dev = 0; dev < num_audiodevs; dev++) { if (!(devmask & (1 << dev))) continue; if (!(adev = audio_devs[dev])) continue; if (adev->open_mode == 0) continue; if (adev->go) continue; /* OK to start the device */ adev->go = 1; if (adev->d->trigger) adev->d->trigger(dev,adev->enable_bits * adev->go); }}/* via poll called without a lock ?*/int DMAbuf_space_in_queue(int dev){ struct audio_operations *adev = audio_devs[dev]; int len, max, tmp; struct dma_buffparms *dmap = adev->dmap_out; int lim = dmap->nbufs; if (lim < 2) lim = 2; if (dmap->qlen >= lim) /* 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; if (max > lim) max = lim; len = dmap->qlen; if (adev->d->local_qlen) { tmp = adev->d->local_qlen(dev); if (tmp && len) tmp--; /* This buffer has been counted twice */ len += tmp; } if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ len = len + 1; if (len >= max) return 0; return max - len;}/* MUST not hold the spinlock - this function may sleep */static int output_sleep(int dev, int dontblock){ struct audio_operations *adev = audio_devs[dev]; int err = 0; struct dma_buffparms *dmap = adev->dmap_out; long timeout; long timeout_value; if (dontblock) return -EAGAIN; if (!(adev->enable_bits & PCM_ENABLE_OUTPUT)) return -EAGAIN; /* * Wait for free space */ if (signal_pending(current)) return -EINTR; timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); if (timeout) timeout_value = dmabuf_timeout(dmap); else timeout_value = MAX_SCHEDULE_TIMEOUT; timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper, timeout_value); if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); dma_reset_output(dev); } else { if (signal_pending(current)) err = -EINTR; } return err;}/* called with the lock held */static int find_output_space(int dev, char **buf, int *size){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_out; unsigned long active_offs; long len, offs; int maxfrags; int occupied_bytes = (dmap->user_counter % dmap->fragment_size); *buf = dmap->raw_buf; if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) return 0;#ifdef BE_CONSERVATIVE active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;#else active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT); /* Check for pointer wrapping situation */ if (active_offs < 0 || active_offs >= dmap->bytes_in_use) active_offs = 0; active_offs += dmap->byte_counter;#endif offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; if (offs < 0 || offs >= dmap->bytes_in_use) { printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs); printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); return 0; } *buf = dmap->raw_buf + offs; len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ if ((offs + len) > dmap->bytes_in_use) len = dmap->bytes_in_use - offs; if (len < 0) { return 0; } if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) len = (maxfrags * dmap->fragment_size) - occupied_bytes; *size = len & ~SAMPLE_ROUNDUP; return (*size > 0);}/* acquires lock */int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock){ struct audio_operations *adev = audio_devs[dev]; unsigned long flags; int err = -EIO; struct dma_buffparms *dmap = adev->dmap_out; if (dmap->mapping_flags & DMA_MAP_MAPPED) {/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ return -EINVAL; } spin_lock_irqsave(&dmap->lock,flags); if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ spin_unlock_irqrestore(&dmap->lock,flags); DMAbuf_reset(dev); spin_lock_irqsave(&dmap->lock,flags); } dmap->dma_mode = DMODE_OUTPUT;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?