📄 dmabuf.c
字号:
* defined by the process. */ max = dmap->max_fragments; len = dmap->qlen; if (audio_devs[dev]->local_qlen) { tmp = audio_devs[dev]->local_qlen (dev); if (tmp & len) tmp--; /* * This buffer has been counted twice */ len += tmp; } if (len >= max) return 0; return 1;}intDMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock){ unsigned long flags; int abort, err = EIO; struct dma_buffparms *dmap = audio_devs[dev]->dmap; if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ { dma_reset (dev); dmap->dma_mode = DMODE_NONE; } else if (dmap->flags & DMA_RESTART) /* Restart buffering */ { dma_sync (dev); dma_reset (dev); } dmap->flags &= ~DMA_RESTART; if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); if (!dmap->dma_mode) { int err; dmap->dma_mode = DMODE_OUTPUT; if ((err = audio_devs[dev]->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; } DISABLE_INTR (flags); abort = 0; while (!space_in_queue (dev) && !abort) { if (dontblock) { RESTORE_INTR (flags); return RET_ERROR (EAGAIN); } /* * Wait for free space */ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) { printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); dma_reset (dev); err = EIO; abort = 1; SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); } else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) { err = EINTR; abort = 1; } } RESTORE_INTR (flags); if (!space_in_queue (dev)) { return RET_ERROR (err); /* Caught a signal ? */ } *buf = dmap->buf[dmap->qtail]; *size = dmap->fragment_size; dmap->counts[dmap->qtail] = 0; return dmap->qtail;}intDMAbuf_start_output (int dev, int buff_no, int l){ struct dma_buffparms *dmap = audio_devs[dev]->dmap; if (buff_no != dmap->qtail) printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail); 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) && ((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; audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], dmap->counts[dmap->qhead], 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_STARTED; } return 0;}intDMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode){ int chan = audio_devs[dev]->dmachan; struct dma_buffparms *dmap = audio_devs[dev]->dmap;#ifdef linux unsigned long flags;#endif /* * This function is not as portable as it should be. */ /* * 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 */#ifdef linux DISABLE_INTR (flags); disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode | DMA_AUTOINIT); set_dma_addr (chan, dmap->raw_buf_phys[0]); set_dma_count (chan, dmap->bytes_in_use); enable_dma (chan); RESTORE_INTR (flags);#else#if defined(__FreeBSD__) isa_dmastart (B_RAW | ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE), (caddr_t)dmap->raw_buf_phys[0], dmap->bytes_in_use, chan);#else /* else __FreeBSD__ */#if defined(GENERIC_SYSV)#ifndef DMAMODE_AUTO printk ("sound: Invalid DMA mode for device %d\n", dev);#endif#if defined(SVR42) /* ** send full count to snd_dma_prog, it will take care of subtracting ** one if it is required. */ snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use, dma_mode, TRUE);#else /* !SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)#ifdef DMAMODE_AUTO | DMAMODE_AUTO#endif , dmap->raw_buf_phys[0], dmap->bytes_in_use - 1); dma_enable (chan);#endif /* ! SVR42 */#else#error This routine is not valid for this OS.#endif#endif#endif } else {#ifdef linux DISABLE_INTR (flags); 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_INTR (flags);#else#if defined(__FreeBSD__) isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, (caddr_t)physaddr, count, chan);#else /* FreeBSD */#if defined(GENERIC_SYSV)#if defined(SVR42) snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);#else /* ! SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), physaddr, count); dma_enable (chan);#endif /* SVR42 */#else#error This routine is not valid for this OS.#endif /* GENERIC_SYSV */#endif#endif } return count;}longDMAbuf_init (long mem_start){ int dev;#if defined(SVR42) snd_dma_init ();#endif /* SVR42 */ /* * NOTE! This routine could be called several times. */ for (dev = 0; dev < num_audiodevs; dev++) audio_devs[dev]->dmap = &dmaps[dev]; return mem_start;}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;#if defined(SVR42) snd_dma_intr (audio_devs[dev]->dmachan);#endif /* SVR42 */ 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--; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->flags &= ~DMA_ACTIVE;#ifdef __FreeBSD__ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan);#endif if (dmap->qlen) { audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); dmap->flags |= DMA_ACTIVE; } else if (event_type == 1) { dmap->underrun_count++; audio_devs[dev]->halt_xfer (dev); if ((audio_devs[dev]->flags & DMA_AUTOMODE) && audio_devs[dev]->flags & NEEDS_RESTART) dmap->flags |= DMA_RESTART; else dmap->flags &= ~DMA_RESTART; } } /* event_type != 2 */ DISABLE_INTR (flags); if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) { WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags);#if defined(__FreeBSD__) if(selinfo[dev].si_pid) selwakeup(&selinfo[dev]);#endif}voidDMAbuf_inputintr (int dev){ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap;#if defined(SVR42) snd_dma_intr (audio_devs[dev]->dmachan);#endif /* SVR42 */ #ifdef __FreeBSD__ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan);#endif if (dmap->qlen == (dmap->nbufs - 1)) {#if !defined(__FreeBSD__) /* ignore console message. */ printk ("Sound: Recording overrun\n");#endif dmap->underrun_count++; audio_devs[dev]->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; audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail], dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); dmap->flags |= DMA_ACTIVE; } DISABLE_INTR (flags); if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) { WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags);#if defined(__FreeBSD__) if(selinfo[dev].si_pid) selwakeup(&selinfo[dev]);#endif}intDMAbuf_open_dma (int dev){ unsigned long flags; int chan = audio_devs[dev]->dmachan; if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name)) {#if 0 /* Enough already! This error is reported twice elsewhere */ printk ("Unable to grab DMA%d for the audio driver\n", chan);#endif return RET_ERROR (EBUSY); } DISABLE_INTR (flags);#ifdef linux disable_dma (chan); clear_dma_ff (chan);#endif RESTORE_INTR (flags); return 0;}voidDMAbuf_close_dma (int dev){ int chan = audio_devs[dev]->dmachan; DMAbuf_reset_dma (dev); RELEASE_DMA_CHN (chan);}voidDMAbuf_reset_dma (int dev){}#ifdef ALLOW_SELECTintDMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait){ struct dma_buffparms *dmap = audio_devs[dev]->dmap; unsigned long flags; switch (sel_type) { case SEL_IN: if (dmap->dma_mode != DMODE_INPUT) return 0; DISABLE_INTR (flags); if (!dmap->qlen) {#if defined(__FreeBSD__) selrecord(wait, &selinfo[dev]);#else dev_sleep_flag[dev].mode = WK_SLEEP; select_wait (&dev_sleeper[dev], wait);#endif RESTORE_INTR (flags); return 0; } RESTORE_INTR (flags); return 1; break; case SEL_OUT: if (dmap->dma_mode == DMODE_INPUT) return 0; if (dmap->dma_mode == DMODE_NONE) return 1; DISABLE_INTR (flags); if (!space_in_queue (dev)) {#if defined(__FreeBSD__) selrecord(wait, &selinfo[dev]);#else dev_sleep_flag[dev].mode = WK_SLEEP; select_wait (&dev_sleeper[dev], wait);#endif RESTORE_INTR (flags); return 0; } RESTORE_INTR (flags); return 1; break; case SEL_EX: return 0; } return 0;}#endif /* ALLOW_SELECT */#else /* EXCLUDE_AUDIO *//* * Stub versions if audio services not included */intDMAbuf_open (int dev, int mode){ return RET_ERROR (ENXIO);}intDMAbuf_release (int dev, int mode){ return 0;}intDMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock){ return RET_ERROR (EIO);}intDMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock){ return RET_ERROR (EIO);}intDMAbuf_rmchars (int dev, int buff_no, int c){ return RET_ERROR (EIO);}intDMAbuf_start_output (int dev, int buff_no, int l){ return RET_ERROR (EIO);}intDMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local){ return RET_ERROR (EIO);}longDMAbuf_init (long mem_start){ return mem_start;}intDMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode){ return RET_ERROR (EIO);}intDMAbuf_open_dma (int dev){ return RET_ERROR (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#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -