📄 pcm_oss.c
字号:
static int snd_pcm_oss_nonblock(struct file * file){ file->f_flags |= O_NONBLOCK; return 0;}static int snd_pcm_oss_get_caps1(snd_pcm_substream_t *substream, int res){ if (substream == NULL) { res &= ~DSP_CAP_DUPLEX; return res; }#ifdef DSP_CAP_MULTI if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->pstr->substream_count > 1) res |= DSP_CAP_MULTI;#endif /* DSP_CAP_REALTIME is set all times: */ /* all ALSA drivers can return actual pointer in ring buffer */#if defined(DSP_CAP_REALTIME) && 0 { snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH)) res &= ~DSP_CAP_REALTIME; }#endif return res;}static int snd_pcm_oss_get_caps(snd_pcm_oss_file_t *pcm_oss_file){ int result, idx; result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME; for (idx = 0; idx < 2; idx++) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; result = snd_pcm_oss_get_caps1(substream, result); } result |= 0x0001; /* revision - same as SB AWE 64 */ return result;}static void snd_pcm_oss_simulate_fill(snd_pcm_substream_t *substream, snd_pcm_uframes_t hw_ptr){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr; appl_ptr = hw_ptr + runtime->buffer_size; appl_ptr %= runtime->boundary; runtime->control->appl_ptr = appl_ptr;}static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger){ snd_pcm_runtime_t *runtime; snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; int err, cmd;#ifdef OSS_DEBUG printk("pcm_oss: trigger = 0x%x\n", trigger);#endif psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (psubstream) { if ((err = snd_pcm_oss_make_ready(psubstream)) < 0) return err; } if (csubstream) { if ((err = snd_pcm_oss_make_ready(csubstream)) < 0) return err; } if (psubstream) { runtime = psubstream->runtime; if (trigger & PCM_ENABLE_OUTPUT) { if (runtime->oss.trigger) goto _skip1; if (atomic_read(&psubstream->runtime->mmap_count)) snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); runtime->oss.trigger = 1; runtime->start_threshold = 1; cmd = SNDRV_PCM_IOCTL_START; } else { if (!runtime->oss.trigger) goto _skip1; runtime->oss.trigger = 0; runtime->start_threshold = runtime->boundary; cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL); if (err < 0) return err; } _skip1: if (csubstream) { runtime = csubstream->runtime; if (trigger & PCM_ENABLE_INPUT) { if (runtime->oss.trigger) goto _skip2; runtime->oss.trigger = 1; runtime->start_threshold = 1; cmd = SNDRV_PCM_IOCTL_START; } else { if (!runtime->oss.trigger) goto _skip2; runtime->oss.trigger = 0; runtime->start_threshold = runtime->boundary; cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL); if (err < 0) return err; } _skip2: return 0;}static int snd_pcm_oss_get_trigger(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; int result = 0; psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger) result |= PCM_ENABLE_OUTPUT; if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger) result |= PCM_ENABLE_INPUT; return result;}static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t delay; int err; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream == NULL) return -EINVAL; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) return 0; err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay); if (err == -EPIPE) delay = 0; /* hack for broken OSS applications */ else if (err < 0) return err; return snd_pcm_oss_bytes(substream, delay);}static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct count_info __user * _info){ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t delay; int fixup; struct count_info info; int err; if (_info == NULL) return -EFAULT; substream = pcm_oss_file->streams[stream]; if (substream == NULL) return -EINVAL; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; runtime = substream->runtime; if (runtime->oss.params || runtime->oss.prepare) { memset(&info, 0, sizeof(info)); if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return 0; } if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay); if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) { err = 0; delay = 0; fixup = 0; } else { fixup = runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &delay); fixup = -runtime->oss.buffer_used; } if (err < 0) return err; info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); if (atomic_read(&runtime->mmap_count)) { snd_pcm_sframes_t n; n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; if (n < 0) n += runtime->boundary; info.blocks = n / runtime->period_size; runtime->oss.prev_hw_ptr_interrupt = delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_oss_simulate_fill(substream, delay); info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; } else { delay = snd_pcm_oss_bytes(substream, delay); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { snd_pcm_oss_setup_t *setup = substream->oss.setup; if (setup && setup->buggyptr) info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; else info.blocks = (delay + fixup) / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; } else { delay += fixup; info.blocks = delay / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes + delay) & INT_MAX; } } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return 0;}static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct audio_buf_info __user *_info){ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t avail; int fixup; struct audio_buf_info info; int err; if (_info == NULL) return -EFAULT; substream = pcm_oss_file->streams[stream]; if (substream == NULL) return -EINVAL; runtime = substream->runtime; if (runtime->oss.params && (err = snd_pcm_oss_change_params(substream)) < 0) return err; info.fragsize = runtime->oss.period_bytes; info.fragstotal = runtime->periods; if (runtime->oss.prepare) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { info.bytes = runtime->oss.period_bytes * runtime->oss.periods; info.fragments = runtime->oss.periods; } else { info.bytes = 0; info.fragments = 0; } } else { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail); if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) { avail = runtime->buffer_size; err = 0; fixup = 0; } else { avail = runtime->buffer_size - avail; fixup = -runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &avail); fixup = runtime->oss.buffer_used; } if (err < 0) return err; info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup; info.fragments = info.bytes / runtime->oss.period_bytes; }#ifdef OSS_DEBUG printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);#endif if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return 0;}static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc __user * _info){ // it won't be probably implemented // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n"); return -EINVAL;}static snd_pcm_oss_setup_t *snd_pcm_oss_look_for_setup(snd_pcm_t *pcm, int stream, const char *task_name){ const char *ptr, *ptrl; snd_pcm_oss_setup_t *setup; down(&pcm->streams[stream].oss.setup_mutex); for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { if (!strcmp(setup->task_name, task_name)) { up(&pcm->streams[stream].oss.setup_mutex); return setup; } } ptr = ptrl = task_name; while (*ptr) { if (*ptr == '/') ptrl = ptr + 1; ptr++; } if (ptrl == task_name) { goto __not_found; return NULL; } for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { if (!strcmp(setup->task_name, ptrl)) { up(&pcm->streams[stream].oss.setup_mutex); return setup; } } __not_found: up(&pcm->streams[stream].oss.setup_mutex); return NULL;}static void snd_pcm_oss_init_substream(snd_pcm_substream_t *substream, snd_pcm_oss_setup_t *setup, int minor){ snd_pcm_runtime_t *runtime; substream->oss.oss = 1; substream->oss.setup = setup; runtime = substream->runtime; runtime->oss.params = 1; runtime->oss.trigger = 1; runtime->oss.rate = 8000; switch (SNDRV_MINOR_OSS_DEVICE(minor)) { case SNDRV_MINOR_OSS_PCM_8: runtime->oss.format = AFMT_U8; break; case SNDRV_MINOR_OSS_PCM_16: runtime->oss.format = AFMT_S16_LE; break; default: runtime->oss.format = AFMT_MU_LAW; } runtime->oss.channels = 1; runtime->oss.fragshift = 0; runtime->oss.maxfrags = 0; runtime->oss.subdivision = 0;}static void snd_pcm_oss_release_substream(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime; runtime = substream->runtime; vfree(runtime->oss.buffer); snd_pcm_oss_plugin_clear(substream); substream->oss.file = NULL; substream->oss.oss = 0;}static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file){ int cidx; snd_assert(pcm_oss_file != NULL, return -ENXIO); for (cidx = 0; cidx < 2; ++cidx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[cidx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); if (snd_pcm_running(substream)) snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); snd_pcm_stream_unlock_irq(substream); if (substream->ffile != NULL) { if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); substream->ops->close(substream); substream->ffile = NULL; } snd_pcm_oss_release_substream(substream); snd_pcm_release_substream(substream); } kfree(pcm_oss_file); return 0;}static int snd_pcm_oss_open_file(struct file *file, snd_pcm_t *pcm, snd_pcm_oss_file_t **rpcm_oss_file, int minor, snd_pcm_oss_setup_t *psetup, snd_pcm_oss_setup_t *csetup){ int err = 0; snd_pcm_oss_file_t *pcm_oss_file; snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL; unsigned int f_mode = file->f_mode; snd_assert(rpcm_oss_file != NULL, return -EINVAL); *rpcm_oss_file = NULL; pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL); if (pcm_oss_file == NULL) return -ENOMEM; if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) && (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) f_mode = FMODE_WRITE; if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) { if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK, &psubstream)) < 0) { snd_pcm_oss_release_file(pcm_oss_file); return err; } pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream; } if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) { if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, &csubstream)) < 0) { if (!(f_mode & FMODE_WRITE) || err != -ENODEV) { snd_pcm_oss_release_file(pcm_oss_file); return err; } else { csubstream = NULL; } } pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream; } if (psubstream == NULL && csubstream == NULL) { snd_pcm_oss_release_file(pcm_oss_file); return -EINVAL; } if (psubstream != NULL) { psubstream->oss.file = pcm_oss_file; err = snd_pcm_hw_constraints_init(psubstream); if (err < 0) { snd_printd("snd_pcm_hw_constraint_init failed\n"); snd_pcm_oss_release_file(pcm_oss_file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -