📄 dmabuf.c
字号:
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } else { dmap->qlen++; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); dmap->counts[dmap->qtail] = l; if (l < dmap->fragment_size) { int p = dmap->fragment_size * dmap->qtail; dmap->neutral_byte = dmap->raw_buf[p + l - 1]; memset (dmap->raw_buf + p + l, dmap->neutral_byte, dmap->fragment_size - l); } else dmap->neutral_byte = dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1]; if ((l != dmap->fragment_size) && ((audio_devs[dev]->flags & DMA_AUTOMODE) && audio_devs[dev]->flags & NEEDS_RESTART)) dmap->flags |= DMA_RESTART; else dmap->flags &= ~DMA_RESTART; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } if (!(dmap->flags & DMA_ACTIVE)) { dmap->flags |= DMA_ACTIVE; if (restart) audio_devs[dev]->d->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs); audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, dmap->counts[dmap->qhead], 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_STARTED; if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } return 0;}intDMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode){ int chan; struct dma_buffparms *dmap; unsigned long flags; if (dma_mode == DMA_MODE_WRITE) { chan = audio_devs[dev]->dmachan1; dmap = audio_devs[dev]->dmap_out; } else { chan = audio_devs[dev]->dmachan2; dmap = audio_devs[dev]->dmap_in; } if (dmap->raw_buf_phys == 0) { printk ("sound: DMA buffer == NULL\n"); return 0; } /* * The count must be one less than the actual size. This is handled by * set_dma_addr() */ if (audio_devs[dev]->flags & DMA_AUTOMODE) { /* * Auto restart mode. Transfer the whole * * buffer */ save_flags (flags); cli (); disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode | DMA_AUTOINIT); set_dma_addr (chan, dmap->raw_buf_phys); set_dma_count (chan, dmap->bytes_in_use); enable_dma (chan); restore_flags (flags); } else { save_flags (flags); cli (); disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode); set_dma_addr (chan, physaddr); set_dma_count (chan, count); enable_dma (chan); restore_flags (flags); } return count;}voidDMAbuf_init (void){ int dev; /* * NOTE! This routine could be called several times. */ for (dev = 0; dev < num_audiodevs; dev++) if (audio_devs[dev]->dmap_out == NULL) { audio_devs[dev]->dmap_out = audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; if (audio_devs[dev]->flags & DMA_DUPLEX) audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; }}static voidpolish_buffers (struct dma_buffparms *dmap){ int i; int p, l; i = dmap->qhead; p = dmap->fragment_size * i; if (i == dmap->cfrag) { l = dmap->fragment_size - dmap->counts[i]; } else l = dmap->fragment_size; if (l) { memset (dmap->raw_buf + p, dmap->neutral_byte, l); }}static voidforce_restart (int dev, struct dma_buffparms *dmap){ if ((audio_devs[dev]->flags & DMA_DUPLEX) && audio_devs[dev]->d->halt_output) audio_devs[dev]->d->halt_output (dev); else audio_devs[dev]->d->halt_xfer (dev); dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED); if (audio_devs[dev]->flags & DMA_AUTOMODE) dmap->flags |= DMA_RESTART; else dmap->flags &= ~DMA_RESTART;}voidDMAbuf_outputintr (int dev, int event_type){ /* * Event types: * 0 = DMA transfer done. Device still has more data in the local * buffer. * 1 = DMA transfer done. Device doesn't have local buffer or it's * empty now. * 2 = No DMA transfer but the device has now more space in it's local * buffer. */ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; int this_fragment; dmap->byte_counter += dmap->counts[dmap->qhead];#ifdef OS_DMA_INTR sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);#endif if (dmap->raw_buf == NULL) { printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); return; } if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* mmapped access */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->qlen++; /* Yes increment it (don't decrement) */ dmap->flags &= ~DMA_ACTIVE; dmap->counts[dmap->qhead] = dmap->fragment_size; if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; } else if (event_type != 2) { if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) { printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); return; } dmap->qlen--; this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->flags &= ~DMA_ACTIVE; if (event_type == 1 && dmap->qlen < 1) { dmap->underrun_count++; if ((!(dmap->flags & DMA_CLEAN) && (audio_devs[dev]->dmap_out->flags & DMA_SYNCING || dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) || audio_devs[dev]->flags & DMA_HARDSTOP) { dmap->qlen = 0; force_restart (dev, dmap); } else /* Ignore underrun. Just move the tail pointer forward and go */ if (dmap->closing) { polish_buffers (dmap); audio_devs[dev]->d->halt_xfer (dev); } else { dmap->qlen++; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; if (!(dmap->flags & DMA_EMPTY)) polish_buffers (dmap); dmap->cfrag = -1; dmap->flags |= DMA_EMPTY; dmap->counts[dmap->qtail] = dmap->fragment_size; } } if (dmap->qlen) { if (dmap->flags & DMA_CLEAN) { int p = dmap->fragment_size * this_fragment; memset (dmap->raw_buf + p, dmap->neutral_byte, dmap->fragment_size); } if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; } } /* event_type != 2 */ save_flags (flags); cli (); if ((out_sleep_flag[dev].flags & WK_SLEEP)) { { out_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&out_sleeper[dev]); }; } restore_flags (flags);}voidDMAbuf_inputintr (int dev){ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; dmap->byte_counter += dmap->fragment_size;#ifdef OS_DMA_INTR sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);#endif if (dmap->raw_buf == NULL) { printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); return; } if (dmap->mapping_flags & DMA_MAP_MAPPED) { dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; dmap->qlen++; if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; } else if (dmap->qlen == (dmap->nbufs - 1)) { printk ("Sound: Recording overrun\n"); dmap->underrun_count++; if (audio_devs[dev]->flags & DMA_AUTOMODE) { /* Force restart on next read */ if ((audio_devs[dev]->flags & DMA_DUPLEX) && audio_devs[dev]->d->halt_input) audio_devs[dev]->d->halt_input (dev); else audio_devs[dev]->d->halt_xfer (dev); dmap->flags &= ~DMA_ACTIVE; if (audio_devs[dev]->flags & DMA_AUTOMODE) dmap->flags |= DMA_RESTART; else dmap->flags &= ~DMA_RESTART; } } else { dmap->qlen++; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", dev, dmap->qlen, dmap->nbufs); dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; save_flags (flags); cli (); if ((in_sleep_flag[dev].flags & WK_SLEEP)) { { in_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&in_sleeper[dev]); }; } restore_flags (flags);}intDMAbuf_open_dma (int dev){/* * NOTE! This routine opens only the primary DMA channel (output). */ int chan = audio_devs[dev]->dmachan1; int err; unsigned long flags; if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0) { return -(EBUSY); } dma_init_buffers (dev, audio_devs[dev]->dmap_out); audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize; save_flags (flags); cli (); disable_dma (chan); clear_dma_ff (chan); restore_flags (flags); return 0;}voidDMAbuf_close_dma (int dev){ DMAbuf_reset_dma (dev); close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);}voidDMAbuf_reset_dma (int dev){}intDMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait){ struct dma_buffparms *dmap; unsigned long flags; switch (sel_type) { case SEL_IN: dmap = audio_devs[dev]->dmap_in; if (dmap->mapping_flags & DMA_MAP_MAPPED) { if (dmap->qlen) return 1; save_flags (flags); cli (); in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; } if (dmap->dma_mode != DMODE_INPUT) { if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen && audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && audio_devs[dev]->go) { unsigned long flags; save_flags (flags); cli (); activate_recording (dev, dmap); restore_flags (flags); } return 0; } if (!dmap->qlen) { save_flags (flags); cli (); in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; } return 1; break; case SEL_OUT: dmap = audio_devs[dev]->dmap_out; if (dmap->mapping_flags & DMA_MAP_MAPPED) { if (dmap->qlen) return 1; save_flags (flags); cli (); out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; } if (dmap->dma_mode == DMODE_INPUT) { return 0; } if (dmap->dma_mode == DMODE_NONE) { return 1; } if (!space_in_queue (dev)) { save_flags (flags); cli (); out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; } return 1; break; case SEL_EX: return 0; } return 0;}#else /* CONFIG_AUDIO *//* * Stub versions if audio services not included */intDMAbuf_open (int dev, int mode){ return -(ENXIO);}intDMAbuf_release (int dev, int mode){ return 0;}intDMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock){ return -(EIO);}intDMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock){ return -(EIO);}intDMAbuf_rmchars (int dev, int buff_no, int c){ return -(EIO);}intDMAbuf_start_output (int dev, int buff_no, int l){ return -(EIO);}intDMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local){ return -(EIO);}voidDMAbuf_init (void){}intDMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode){ return -(EIO);}intDMAbuf_open_dma (int dev){ return -(ENXIO);}voidDMAbuf_close_dma (int dev){ return;}voidDMAbuf_reset_dma (int dev){ return;}voidDMAbuf_inputintr (int dev){ return;}voidDMAbuf_outputintr (int dev, int underrun_flag){ return;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -