📄 dmabuf.c
字号:
dmap->user_counter += l; dmap->flags |= DMA_DIRTY; if (dmap->byte_counter >= dmap->max_byte_counter) { /* Wrap the byte counters */ long decr = dmap->byte_counter; dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); decr -= dmap->byte_counter; dmap->user_counter -= decr; } end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; p = (dmap->user_counter - 1) % dmap->bytes_in_use; dmap->neutral_byte = dmap->raw_buf[p]; /* Update the fragment based bookkeeping too */ while (ptr < end_ptr) { dmap->counts[dmap->qtail] = dmap->fragment_size; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; dmap->qlen++; ptr += dmap->fragment_size; } dmap->counts[dmap->qtail] = dmap->user_counter - ptr; /* * Let the low level driver to perform some postprocessing to * the written data. */ if (adev->d->postprocess_write) adev->d->postprocess_write(dev); if (!(dmap->flags & DMA_ACTIVE)) if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) DMAbuf_launch_output(dev, dmap); return 0;}int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; if (dmap->raw_buf == NULL) { printk(KERN_ERR "sound: DMA buffer(1) == NULL\n"); printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in"); return 0; } if (dmap->dma < 0) return 0; sound_start_dma(dmap, physaddr, count, dma_mode); return count;}static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode){ struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; if (dmap->raw_buf == NULL) { printk(KERN_ERR "sound: DMA buffer(2) == NULL\n"); printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in"); return 0; } if (dmap->flags & DMA_NODMA) return 1; if (dmap->dma < 0) return 0; sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT); dmap->flags |= DMA_STARTED; return count;}static void finish_output_interrupt(int dev, struct dma_buffparms *dmap){ struct audio_operations *adev = audio_devs[dev]; if (dmap->audio_callback != NULL) dmap->audio_callback(dev, dmap->callback_parm); wake_up(&adev->out_sleeper); wake_up(&adev->poll_sleeper);}static void do_outputintr(int dev, int dummy){ struct audio_operations *adev = audio_devs[dev]; unsigned long flags; struct dma_buffparms *dmap = adev->dmap_out; int this_fragment; if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: Error. Audio interrupt (%d) after freeing buffers.\n", dev); return; } if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* Virtual memory mapped access */ /* mmapped access */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; if (dmap->qhead == 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); decr -= dmap->byte_counter; dmap->user_counter -= decr; } } dmap->qlen++; /* Yes increment it (don't decrement) */ if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; dmap->counts[dmap->qhead] = dmap->fragment_size; DMAbuf_launch_output(dev, dmap); finish_output_interrupt(dev, dmap); return; } save_flags(flags); cli(); dmap->qlen--; this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; if (dmap->qhead == 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); decr -= dmap->byte_counter; dmap->user_counter -= decr; } } if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; /* * This is dmap->qlen <= 0 except when closing when * dmap->qlen < 0 */ while (dmap->qlen <= -dmap->closing) { dmap->underrun_count++; dmap->qlen++; if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) { dmap->flags &= ~DMA_DIRTY; memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->buffsize); } dmap->user_counter += dmap->fragment_size; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } if (dmap->qlen > 0) DMAbuf_launch_output(dev, dmap); restore_flags(flags); finish_output_interrupt(dev, dmap);}void DMAbuf_outputintr(int dev, int notify_only){ struct audio_operations *adev = audio_devs[dev]; unsigned long flags; struct dma_buffparms *dmap = adev->dmap_out; save_flags(flags); cli(); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; unsigned long f; f=claim_dma_lock(); if(!isa_dma_bridge_buggy) disable_dma(dmap->dma); clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); if(!isa_dma_bridge_buggy) enable_dma(dmap->dma); release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) pos = 0; n = 0; while (dmap->qhead != pos && n++ < dmap->nbufs) do_outputintr(dev, notify_only); } else do_outputintr(dev, notify_only); restore_flags(flags);}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); }}void DMAbuf_inputintr(int dev){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_in; unsigned long flags; save_flags(flags); cli(); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; unsigned long f; f=claim_dma_lock(); if(!isa_dma_bridge_buggy) disable_dma(dmap->dma); clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); if(!isa_dma_bridge_buggy) enable_dma(dmap->dma); release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) pos = 0; n = 0; while (dmap->qtail != pos && ++n < dmap->nbufs) do_inputintr(dev); } else do_inputintr(dev); restore_flags(flags);}int DMAbuf_open_dma(int dev){ /* * NOTE! This routine opens only the primary DMA channel (output). */ struct audio_operations *adev = audio_devs[dev]; int err; if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0) return -EBUSY; dma_init_buffers(adev->dmap_out); adev->dmap_out->flags |= DMA_ALLOC_DONE; adev->dmap_out->fragment_size = adev->dmap_out->buffsize; if (adev->dmap_out->dma >= 0) { unsigned long flags; flags=claim_dma_lock(); clear_dma_ff(adev->dmap_out->dma); disable_dma(adev->dmap_out->dma); release_dma_lock(flags); } return 0;}void DMAbuf_close_dma(int dev){ close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);}void DMAbuf_init(int dev, int dma1, int dma2){ struct audio_operations *adev = audio_devs[dev]; /* * NOTE! This routine could be called several times. */ /* drag in audio_syms.o */ { extern char audio_syms_symbol; audio_syms_symbol = 0; } if (adev && adev->dmap_out == NULL) { if (adev->d == NULL) panic("OSS: audio_devs[%d]->d == NULL\n", dev); if (adev->parent_dev) { /* Use DMA map of the parent dev */ int parent = adev->parent_dev - 1; adev->dmap_out = audio_devs[parent]->dmap_out; adev->dmap_in = audio_devs[parent]->dmap_in; } else { adev->dmap_out = adev->dmap_in = &adev->dmaps[0]; adev->dmap_out->dma = dma1; if (adev->flags & DMA_DUPLEX) { adev->dmap_in = &adev->dmaps[1]; adev->dmap_in->dma = dma2; } } /* Persistent DMA buffers allocated here */ if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { if (adev->dmap_in->raw_buf == NULL) sound_alloc_dmap(adev->dmap_in); if (adev->dmap_out->raw_buf == NULL) sound_alloc_dmap(adev->dmap_out); } }}/* No kernel lock - DMAbuf_activate_recording protected by global cli/sti */static unsigned int poll_input(struct file * file, int dev, poll_table *wait){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_in; if (!(adev->open_mode & OPEN_READ)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { if (dmap->qlen) return POLLIN | POLLRDNORM; return 0; } if (dmap->dma_mode != DMODE_INPUT) { if (dmap->dma_mode == DMODE_NONE && adev->enable_bits & PCM_ENABLE_INPUT && !dmap->qlen && adev->go) { unsigned long flags; save_flags(flags); cli(); DMAbuf_activate_recording(dev, dmap); restore_flags(flags); } return 0; } if (!dmap->qlen) return 0; return POLLIN | POLLRDNORM;}static unsigned int poll_output(struct file * file, int dev, poll_table *wait){ struct audio_operations *adev = audio_devs[dev]; struct dma_buffparms *dmap = adev->dmap_out; if (!(adev->open_mode & OPEN_WRITE)) return 0; if (dmap->mapping_flags & DMA_MAP_MAPPED) { if (dmap->qlen) return POLLOUT | POLLWRNORM; return 0; } if (dmap->dma_mode == DMODE_INPUT) return 0; if (dmap->dma_mode == DMODE_NONE) return POLLOUT | POLLWRNORM; if (!DMAbuf_space_in_queue(dev)) return 0; return POLLOUT | POLLWRNORM;}unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait){ struct audio_operations *adev = audio_devs[dev]; poll_wait(file, &adev->poll_sleeper, wait); return poll_input(file, dev, wait) | poll_output(file, dev, wait);}void DMAbuf_deinit(int dev){ struct audio_operations *adev = audio_devs[dev]; /* This routine is called when driver is being unloaded */ if (!adev) return; /* Persistent DMA buffers deallocated here */ if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { sound_free_dmap(adev->dmap_out); if (adev->flags & DMA_DUPLEX) sound_free_dmap(adev->dmap_in); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -