📄 dmabuf.c
字号:
dmap = adev->dmap_out; save_flags(flags); cli(); 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); t = interruptible_sleep_on_timeout(&adev->out_sleeper, t); if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; restore_flags(flags); return adev->dmap_out->qlen; } } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); 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 (adev->d->local_qlen) { /* Device has hidden buffers */ while (!signal_pending(current) && adev->d->local_qlen(dev)) interruptible_sleep_on_timeout(&adev->out_sleeper, dmabuf_timeout(dmap)); } restore_flags(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]; unsigned long flags; if (adev->open_mode & OPEN_WRITE) adev->dmap_out->closing = 1; if (adev->open_mode & OPEN_READ) adev->dmap_in->closing = 1; 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); save_flags(flags); cli(); DMAbuf_reset(dev); 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; restore_flags(flags); return 0;}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 */ DMAbuf_sync(dev); DMAbuf_reset(dev); 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;}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; if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); save_flags(flags); cli(); if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) {/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ restore_flags(flags); return -EINVAL; } else while (dmap->qlen <= 0 && n++ < 10) { long timeout = MAX_SCHEDULE_TIMEOUT; if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { restore_flags(flags); return -EAGAIN; } if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { restore_flags(flags); return err; } /* Wait for the next block */ if (dontblock) { restore_flags(flags); return -EAGAIN; } if ((go = adev->go)) timeout = dmabuf_timeout(dmap); 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; } restore_flags(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;}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 flags; unsigned long f; save_flags(flags); cli(); 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); } restore_flags(flags); /* 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); }}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;}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;}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 flags; 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; save_flags(flags); cli();#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) { restore_flags(flags); 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) { restore_flags(flags); return 0; } if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) len = (maxfrags * dmap->fragment_size) - occupied_bytes; *size = len & ~SAMPLE_ROUNDUP; restore_flags(flags); return (*size > 0);}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->needs_reorg) reorganize_buffers(dev, dmap, 0); if (dmap->mapping_flags & DMA_MAP_MAPPED) {/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ return -EINVAL; } if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ DMAbuf_reset(dev); dmap->dma_mode = DMODE_NONE; } dmap->dma_mode = DMODE_OUTPUT; save_flags(flags); cli(); while (find_output_space(dev, buf, size) <= 0) { if ((err = output_sleep(dev, dontblock)) < 0) { restore_flags(flags); return err; } } restore_flags(flags); return 0;}int DMAbuf_move_wrpointer(int dev, int l){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_out; unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; unsigned long end_ptr, p; int post = (dmap->flags & DMA_POST); dmap->flags &= ~DMA_POST; dmap->cfrag = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -