📄 dmabuf.c
字号:
dmap->qlen--; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; } else dmap->counts[dmap->qhead] = p; return 0;}static intdma_subdivide (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact){ if (fact == 0) { fact = dmap->subdivision; if (fact == 0) fact = 1; return snd_ioctl_return ((int *) arg, fact); } if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ return -(EINVAL); if (fact > MAX_REALTIME_FACTOR) return -(EINVAL); if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) return -(EINVAL); dmap->subdivision = fact; return snd_ioctl_return ((int *) arg, fact);}static intdma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact){ int bytes, count; if (fact == 0) return -(EIO); if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ return -(EINVAL); bytes = fact & 0xffff; count = (fact >> 16) & 0x7fff; if (count == 0) count = MAX_SUB_BUFFERS; if (bytes < 4 || bytes > 17) /* <16 || > 512k */ return -(EINVAL); if (count < 2) return -(EINVAL); if (audio_devs[dev]->min_fragment > 0) if (bytes < audio_devs[dev]->min_fragment) bytes = audio_devs[dev]->min_fragment;#ifdef OS_DMA_MINBITS if (bytes < OS_DMA_MINBITS) bytes = OS_DMA_MINBITS;#endif dmap->fragment_size = (1 << bytes); dmap->max_fragments = count; if (dmap->fragment_size > audio_devs[dev]->buffsize) dmap->fragment_size = audio_devs[dev]->buffsize; if (dmap->fragment_size == audio_devs[dev]->buffsize && audio_devs[dev]->flags & DMA_AUTOMODE) dmap->fragment_size /= 2; /* Needs at least 2 buffers */ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ if (arg) return snd_ioctl_return ((int *) arg, bytes | (count << 16)); else return 0;}static intget_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap){ int pos; unsigned long flags; save_flags (flags); cli (); if (!(dmap->flags & DMA_ACTIVE)) pos = 0; else { clear_dma_ff (chan); disable_dma (chan); pos = get_dma_residue (chan); enable_dma (chan); } restore_flags (flags); /* printk ("%04x ", pos); */ if (audio_devs[dev]->flags & DMA_AUTOMODE) return dmap->bytes_in_use - pos; else { pos = dmap->fragment_size - pos; if (pos < 0) return 0; return pos; }}intDMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local){ struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; long larg = (long) arg; switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return audio_devs[dev]->d->set_speed (dev, larg); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg))); case SOUND_PCM_READ_RATE: if (local) return audio_devs[dev]->d->set_speed (dev, 0); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0)); case SNDCTL_DSP_STEREO: if (local) return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1; return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1); case SOUND_PCM_WRITE_CHANNELS: if (local) return audio_devs[dev]->d->set_channels (dev, (short) larg); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg))); case SOUND_PCM_READ_CHANNELS: if (local) return audio_devs[dev]->d->set_channels (dev, 0); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0)); case SNDCTL_DSP_SAMPLESIZE: if (local) return audio_devs[dev]->d->set_bits (dev, larg); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg))); case SOUND_PCM_READ_BITS: if (local) return audio_devs[dev]->d->set_bits (dev, 0); return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0)); case SNDCTL_DSP_RESET: dma_reset (dev); return 0; break; case SNDCTL_DSP_SYNC: dma_sync (dev); dma_reset (dev); return 0; break; case SNDCTL_DSP_GETBLKSIZE: if (!(dmap_out->flags & DMA_ALLOC_DONE)) { reorganize_buffers (dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); if (audio_devs[dev]->flags & DMA_DUPLEX && audio_devs[dev]->open_mode & OPEN_READ) reorganize_buffers (dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); } return snd_ioctl_return ((int *) arg, dmap_out->fragment_size); break; case SNDCTL_DSP_SUBDIVIDE: { int fact = get_user ((int *) arg); int ret; ret = dma_subdivide (dev, dmap_out, arg, fact); if (ret < 0) return ret; if (audio_devs[dev]->flags & DMA_DUPLEX && audio_devs[dev]->open_mode & OPEN_READ) ret = dma_subdivide (dev, dmap_in, arg, fact); return ret; } break; case SNDCTL_DSP_SETDUPLEX: if (audio_devs[dev]->flags & DMA_DUPLEX) return 0; else return -(EIO); break; case SNDCTL_DSP_SETFRAGMENT: { int fact = get_user ((int *) arg); int ret; ret = dma_set_fragment (dev, dmap_out, arg, fact); if (ret < 0) return ret; if (audio_devs[dev]->flags & DMA_DUPLEX && audio_devs[dev]->open_mode & OPEN_READ) ret = dma_set_fragment (dev, dmap_in, arg, fact); return ret; } break; case SNDCTL_DSP_GETISPACE: case SNDCTL_DSP_GETOSPACE: if (!local) return -(EINVAL); else { struct dma_buffparms *dmap = dmap_out; audio_buf_info *info = (audio_buf_info *) arg; if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) return -(EINVAL); if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) dmap = dmap_in; if (dmap->mapping_flags & DMA_MAP_MAPPED) return -(EINVAL); if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); info->fragstotal = dmap->nbufs; if (cmd == SNDCTL_DSP_GETISPACE) info->fragments = dmap->qlen; else { if (!space_in_queue (dev)) info->fragments = 0; else { info->fragments = dmap->nbufs - dmap->qlen; if (audio_devs[dev]->d->local_qlen) { int tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && info->fragments) tmp--; /* * This buffer has been counted twice */ info->fragments -= tmp; } } } if (info->fragments < 0) info->fragments = 0; else if (info->fragments > dmap->nbufs) info->fragments = dmap->nbufs; info->fragsize = dmap->fragment_size; info->bytes = info->fragments * dmap->fragment_size; if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) info->bytes -= dmap->counts[dmap->qhead]; } return 0; case SNDCTL_DSP_SETTRIGGER: { unsigned long flags; int bits = get_user ((int *) arg) & audio_devs[dev]->open_mode; int changed; if (audio_devs[dev]->d->trigger == NULL) return -(EINVAL); if (!(audio_devs[dev]->flags & DMA_DUPLEX)) if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) { printk ("Sound: Device doesn't have full duplex capability\n"); return -(EINVAL); } save_flags (flags); cli (); changed = audio_devs[dev]->enable_bits ^ bits; if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) { int err; if (!(dmap_in->flags & DMA_ALLOC_DONE)) { reorganize_buffers (dev, dmap_in, 1); } if ((err = audio_devs[dev]->d->prepare_for_input (dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) return -(err); audio_devs[dev]->enable_bits = bits; activate_recording (dev, dmap_in); } if ((changed & bits) & PCM_ENABLE_OUTPUT && dmap_out->mapping_flags & DMA_MAP_MAPPED && audio_devs[dev]->go) { int err; if (!(dmap_out->flags & DMA_ALLOC_DONE)) { reorganize_buffers (dev, dmap_out, 0); } if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap_out->fragment_size, dmap_out->nbufs)) < 0) return -(err); dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; DMAbuf_start_output (dev, 0, dmap_out->fragment_size); } audio_devs[dev]->enable_bits = bits; if (changed && audio_devs[dev]->d->trigger) { audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); } restore_flags (flags); } case SNDCTL_DSP_GETTRIGGER: return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits); break; case SNDCTL_DSP_SETSYNCRO: if (!audio_devs[dev]->d->trigger) return -(EINVAL); audio_devs[dev]->d->trigger (dev, 0); audio_devs[dev]->go = 0; return 0; break; case SNDCTL_DSP_GETIPTR: { count_info info; unsigned long flags; if (!(audio_devs[dev]->open_mode & OPEN_READ)) return -(EINVAL); save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_in->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in); info.blocks = audio_devs[dev]->dmap_in->qlen; info.bytes += info.ptr; memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */ restore_flags (flags); return 0; } break; case SNDCTL_DSP_GETOPTR: { count_info info; unsigned long flags; if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -(EINVAL); save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_out->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out); info.blocks = audio_devs[dev]->dmap_out->qlen; info.bytes += info.ptr; memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */ restore_flags (flags); return 0; } break; default: return audio_devs[dev]->d->ioctl (dev, cmd, arg, local); }}/* * DMAbuf_start_devices() is called by the /dev/music driver to start * one or more audio devices at desired moment. */voidDMAbuf_start_devices (unsigned int devmask){ int dev; for (dev = 0; dev < num_audiodevs; dev++) if (devmask & (1 << dev)) if (audio_devs[dev]->open_mode != 0) if (!audio_devs[dev]->go) { /* OK to start the device */ audio_devs[dev]->go = 1; if (audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); }}static intspace_in_queue (int dev){ int len, max, tmp; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; if (dmap->qlen >= dmap->nbufs) /* 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; len = dmap->qlen; if (audio_devs[dev]->d->local_qlen) { tmp = audio_devs[dev]->d->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_out; dmap->flags &= ~DMA_CLEAN; if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't write to mmapped device (3)\n"); return -(EINVAL); } 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_output (dev); } dmap->flags &= ~(DMA_RESTART | DMA_EMPTY); if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, 0); if (!dmap->dma_mode) { int err; dmap->dma_mode = DMODE_OUTPUT; if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; } save_flags (flags); cli (); abort = 0; while (!space_in_queue (dev) && !abort) { int tmout; if (dontblock) { restore_flags (flags); return -(EAGAIN); } if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) && audio_devs[dev]->go) { restore_flags (flags); return -(EAGAIN); } /* * Wait for free space */ if (!audio_devs[dev]->go) tmout = 0; else tmout = 10 * HZ; { unsigned long tlimit; if (tmout) current_set_timeout (tlimit = jiffies + (tmout)); else tlimit = (unsigned long) -1; out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { if (jiffies >= tlimit) out_sleep_flag[dev].flags |= WK_TIMEOUT; } out_sleep_flag[dev].flags &= ~WK_SLEEP; }; if ((out_sleep_flag[dev].flags & WK_TIMEOUT)) { printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); err = EIO; abort = 1; ; if (audio_devs[dev]->flags & DMA_AUTOMODE) dmap->flags |= DMA_RESTART; else dmap->flags &= ~DMA_RESTART; audio_devs[dev]->d->reset (dev); } else if (current_got_fatal_signal ()) { err = EINTR; abort = 1; } } restore_flags (flags); if (!space_in_queue (dev)) { return -(err); /* Caught a signal ? */ } *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; *size = dmap->fragment_size; dmap->counts[dmap->qtail] = 0; return dmap->qtail;}intDMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size){ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; if (dmap->cfrag < 0) return -1; *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; *buf_ptr = dmap->counts[dmap->qtail]; *buf_size = dmap->fragment_size; return *buf_no = dmap->cfrag;}intDMAbuf_set_count (int dev, int buff_no, int l){ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; if (buff_no == dmap->qtail) { dmap->cfrag = buff_no; dmap->counts[buff_no] = l; } else dmap->cfrag = -1; return 0;}intDMAbuf_start_output (int dev, int buff_no, int l){ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; int restart = 0; dmap->cfrag = -1; if (dmap->flags & DMA_RESTART) restart = 1;/* * Bypass buffering if using mmapped access */ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { l = dmap->fragment_size; dmap->counts[dmap->qtail] = l; dmap->flags &= ~DMA_RESTART;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -