/* MUST be called with holding the dmap->lock */ void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { struct audio_operations *adev = audio_devs[dev]; if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT)) return; /* Don't start DMA yet */ dmap->dma_mode = DMODE_OUTPUT; if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { if (!(dmap->flags & DMA_STARTED)) { reorganize_buffers(dev, dmap, 0); if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) return; if (!(dmap->flags & DMA_NODMA)) local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE); dmap->flags |= DMA_STARTED; } if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; dmap->dma_mode = DMODE_OUTPUT; adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, dmap->counts[dmap->qhead], 1); if (adev->d->trigger) adev->d->trigger(dev,adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; }
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; }
/* called with dmap->lock held in irq context */ static void do_inputintr(int dev) { struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_in; if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: Fatal error. Audio interrupt after freeing buffers.\n"); return; } if (dmap->mapping_flags & DMA_MAP_MAPPED) { dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; if (dmap->qtail == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; } } dmap->qlen++; if (!(adev->flags & DMA_AUTOMODE)) { 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, 1); if (adev->d->trigger) adev->d->trigger(dev, adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; } else if (dmap->qlen >= (dmap->nbufs - 1)) { printk(KERN_WARNING "Sound: Recording overrun\n"); dmap->underrun_count++; /* Just throw away the oldest fragment but keep the engine running */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) { dmap->qlen++; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; if (dmap->qtail == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; } } } if (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { 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, 1); if (adev->d->trigger) adev->d->trigger(dev,adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; if (dmap->qlen > 0) { wake_up(&adev->in_sleeper); wake_up(&adev->poll_sleeper); } }