📄 pcm_oss.c
字号:
if (err < 0) goto failure; n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size); err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL); snd_assert(err >= 0, goto failure); err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS, runtime->oss.periods, NULL); snd_assert(err >= 0, goto failure); snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) { snd_printd("HW_PARAMS failed: %i\n", err); goto failure; } memset(sw_params, 0, sizeof(*sw_params)); if (runtime->oss.trigger) { sw_params->start_threshold = 1; } else { sw_params->start_threshold = runtime->boundary; } if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE) sw_params->stop_threshold = runtime->boundary; else sw_params->stop_threshold = runtime->buffer_size; sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; sw_params->period_step = 1; sw_params->sleep_min = 0; sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : runtime->period_size; sw_params->xfer_align = 1; if (atomic_read(&runtime->mmap_count) || (substream->oss.setup && substream->oss.setup->nosilence)) { sw_params->silence_threshold = 0; sw_params->silence_size = 0; } else { snd_pcm_uframes_t frames; frames = runtime->period_size + 16; if (frames > runtime->buffer_size) frames = runtime->buffer_size; sw_params->silence_threshold = frames; sw_params->silence_size = frames; } if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { snd_printd("SW_PARAMS failed: %i\n", err); goto failure; } runtime->oss.periods = params_periods(sparams); oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams)); snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure); if (runtime->oss.plugin_first) { err = snd_pcm_plug_alloc(substream, oss_period_size); if (err < 0) goto failure; } oss_period_size *= oss_frame_size; oss_buffer_size = oss_period_size * runtime->oss.periods; snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure); runtime->oss.period_bytes = oss_period_size; runtime->oss.buffer_bytes = oss_buffer_size; pdprintf("oss: period bytes = %i, buffer bytes = %i\n", runtime->oss.period_bytes, runtime->oss.buffer_bytes); pdprintf("slave: period_size = %i, buffer_size = %i\n", params_period_size(sparams), params_buffer_size(sparams)); runtime->oss.format = snd_pcm_oss_format_to(params_format(params)); runtime->oss.channels = params_channels(params); runtime->oss.rate = params_rate(params); runtime->oss.params = 0; runtime->oss.prepare = 1; vfree(runtime->oss.buffer); runtime->oss.buffer = vmalloc(runtime->oss.period_bytes); runtime->oss.buffer_used = 0; if (runtime->dma_area) snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); err = 0;failure: kfree(sw_params); kfree(params); kfree(sparams); return err;}static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream){ int idx, err; snd_pcm_substream_t *asubstream = NULL, *substream; for (idx = 0; idx < 2; idx++) { substream = pcm_oss_file->streams[idx]; if (substream == NULL) continue; if (asubstream == NULL) asubstream = substream; if (substream->runtime->oss.params) { err = snd_pcm_oss_change_params(substream); if (err < 0) return err; } } snd_assert(asubstream != NULL, return -EIO); if (r_substream) *r_substream = asubstream; return 0;}static int snd_pcm_oss_prepare(snd_pcm_substream_t *substream){ int err; snd_pcm_runtime_t *runtime = substream->runtime; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n"); return err; } runtime->oss.prepare = 0; runtime->oss.prev_hw_ptr_interrupt = 0; runtime->oss.period_ptr = 0; runtime->oss.buffer_used = 0; return 0;}static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime; int err; if (substream == NULL) return 0; runtime = substream->runtime; if (runtime->oss.params) { err = snd_pcm_oss_change_params(substream); if (err < 0) return err; } if (runtime->oss.prepare) { err = snd_pcm_oss_prepare(substream); if (err < 0) return err; } return 0;}static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay){ snd_pcm_runtime_t *runtime; snd_pcm_uframes_t frames; int err = 0; while (1) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay); if (err < 0) break; runtime = substream->runtime; if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size) break; /* in case of overrun, skip whole periods like OSS/Linux driver does */ /* until avail(delay) <= buffer_size */ frames = (*delay - runtime->buffer_size) + runtime->period_size - 1; frames /= runtime->period_size; frames *= runtime->period_size; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames); if (err < 0) break; } return err;}snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG if (runtime->status->state == SNDRV_PCM_STATE_XRUN) printk("pcm_oss: write: recovering from XRUN\n"); else printk("pcm_oss: write: recovering from SUSPEND\n");#endif ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret;}snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t delay; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG if (runtime->status->state == SNDRV_PCM_STATE_XRUN) printk("pcm_oss: read: recovering from XRUN\n"); else printk("pcm_oss: read: recovering from SUSPEND\n");#endif ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break; } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } ret = snd_pcm_oss_capture_position_fixup(substream, &delay); if (ret < 0) break; if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames); } if (ret == -EPIPE) { if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (ret < 0) break; } continue; } if (ret != -ESTRPIPE) break; } return ret;}snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG if (runtime->status->state == SNDRV_PCM_STATE_XRUN) printk("pcm_oss: writev: recovering from XRUN\n"); else printk("pcm_oss: writev: recovering from SUSPEND\n");#endif ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret;} snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG if (runtime->status->state == SNDRV_PCM_STATE_XRUN) printk("pcm_oss: readv: recovering from XRUN\n"); else printk("pcm_oss: readv: recovering from SUSPEND\n");#endif ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); if (ret < 0) break; } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; } return ret;}static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *buf, size_t bytes, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t frames, frames1; if (runtime->oss.plugin_first) { snd_pcm_plugin_channel_t *channels; size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8; if (!in_kernel) { if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes)) return -EFAULT; buf = runtime->oss.buffer; } frames = bytes / oss_frame_bytes; frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels); if (frames1 < 0) return frames1; frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1); if (frames1 <= 0) return frames1; bytes = frames1 * oss_frame_bytes; } else { frames = bytes_to_frames(runtime, bytes); frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel); if (frames1 <= 0) return frames1; bytes = frames_to_bytes(runtime, frames1); } return bytes;}static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __user *buf, size_t bytes){ size_t xfer = 0; ssize_t tmp; snd_pcm_runtime_t *runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) return -ENXIO; if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; while (bytes > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) tmp = runtime->oss.period_bytes - runtime->oss.buffer_used; if (tmp > 0) { if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; } runtime->oss.buffer_used += tmp; buf += tmp; bytes -= tmp; xfer += tmp; if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) || runtime->oss.buffer_used == runtime->oss.period_bytes) { tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, runtime->oss.buffer_used - runtime->oss.period_ptr, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; runtime->oss.period_ptr += tmp; runtime->oss.period_ptr %= runtime->oss.period_bytes; if (runtime->oss.period_ptr == 0 || runtime->oss.period_ptr == runtime->oss.buffer_used) runtime->oss.buffer_used = 0; else if ((substream->ffile->f_flags & O_NONBLOCK) != 0) return xfer > 0 ? xfer : -EAGAIN; } } else { tmp = snd_pcm_oss_write2(substream, (const char __force *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; if ((substream->ffile->f_flags & O_NONBLOCK) != 0 && tmp != runtime->oss.period_bytes) break; } } return xfer;}static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size_t bytes, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t frames, frames1; char __user *final_dst = (char __user *)buf; if (runtime->oss.plugin_first) { snd_pcm_plugin_channel_t *channels; size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8; if (!in_kernel) buf = runtime->oss.buffer; frames = bytes / oss_frame_bytes; frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels); if (frames1 < 0) return frames1; frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1); if (frames1 <= 0) return frames1; bytes = frames1 * oss_frame_bytes; if (!in_kernel && copy_to_user(final_dst, buf, bytes)) return -EFAULT; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -