📄 pcm_oss.c
字号:
frames = bytes_to_frames(runtime, bytes); frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel); if (frames1 <= 0) return frames1; bytes = frames_to_bytes(runtime, frames1); } return bytes;}static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, 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) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; runtime->oss.period_ptr = tmp; runtime->oss.buffer_used = tmp; } tmp = bytes; if ((size_t) tmp > runtime->oss.buffer_used) tmp = runtime->oss.buffer_used; if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; buf += tmp; bytes -= tmp; xfer += tmp; runtime->oss.buffer_used -= tmp; } else { tmp = snd_pcm_oss_read2(substream, (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; } } return xfer;}static int snd_pcm_oss_reset(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); substream->runtime->oss.prepare = 1; } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); substream->runtime->oss.prepare = 1; } return 0;}static int snd_pcm_oss_post(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL); } /* note: all errors from the start action are ignored */ /* OSS apps do not know, how to handle them */ return 0;}static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size){ snd_pcm_runtime_t *runtime; ssize_t result = 0; long res; wait_queue_t wait; runtime = substream->runtime; init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait);#ifdef OSS_DEBUG printk("sync1: size = %li\n", size);#endif while (1) { result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); if (result > 0) { runtime->oss.buffer_used = 0; result = 0; break; } if (result != 0 && result != -EAGAIN) break; result = 0; set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_lock_irq(substream); res = runtime->status->state; snd_pcm_stream_unlock_irq(substream); if (res != SNDRV_PCM_STATE_RUNNING) { set_current_state(TASK_RUNNING); break; } res = schedule_timeout(10 * HZ); if (signal_pending(current)) { result = -ERESTARTSYS; break; } if (res == 0) { snd_printk(KERN_ERR "OSS sync error - DMA timeout\n"); result = -EIO; break; } } remove_wait_queue(&runtime->sleep, &wait); return result;}static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file){ int err = 0; unsigned int saved_f_flags; snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_format_t format; unsigned long width; size_t size; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); if (runtime->oss.buffer_used > 0) {#ifdef OSS_DEBUG printk("sync: buffer_used\n");#endif size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width; snd_pcm_format_set_silence(format, runtime->oss.buffer + runtime->oss.buffer_used, size); err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); if (err < 0) return err; } else if (runtime->oss.period_ptr > 0) {#ifdef OSS_DEBUG printk("sync: period_ptr\n");#endif size = runtime->oss.period_bytes - runtime->oss.period_ptr; snd_pcm_format_set_silence(format, runtime->oss.buffer, size * 8 / width); err = snd_pcm_oss_sync1(substream, size); if (err < 0) return err; } /* * The ALSA's period might be a bit large than OSS one. * Fill the remain portion of ALSA period with zeros. */ size = runtime->control->appl_ptr % runtime->period_size; if (size > 0) { size = runtime->period_size - size; if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { size = (runtime->frame_bits * size) / 8; while (size > 0) { mm_segment_t fs; size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; size -= size1; size1 *= 8; size1 /= runtime->sample_bits; snd_pcm_format_set_silence(runtime->format, runtime->oss.buffer, size1); fs = snd_enter_user(); snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1); snd_leave_user(fs); } } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { void __user *buffers[runtime->channels]; memset(buffers, 0, runtime->channels * sizeof(void *)); snd_pcm_lib_writev(substream, buffers, size); } } /* * finish sync: drain the buffer */ __direct: saved_f_flags = substream->ffile->f_flags; substream->ffile->f_flags &= ~O_NONBLOCK; err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); substream->ffile->f_flags = saved_f_flags; if (err < 0) return err; runtime->oss.prepare = 1; } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; runtime = substream->runtime; err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (err < 0) return err; runtime->oss.buffer_used = 0; runtime->oss.prepare = 1; } return 0;}static int snd_pcm_oss_set_rate(snd_pcm_oss_file_t *pcm_oss_file, int rate){ int idx; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; if (rate < 1000) rate = 1000; else if (rate > 192000) rate = 192000; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } } return snd_pcm_oss_get_rate(pcm_oss_file);}static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; return substream->runtime->oss.rate;}static int snd_pcm_oss_set_channels(snd_pcm_oss_file_t *pcm_oss_file, unsigned int channels){ int idx; if (channels < 1) channels = 1; if (channels > 128) return -EINVAL; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; } } return snd_pcm_oss_get_channels(pcm_oss_file);}static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; return substream->runtime->oss.channels;}static int snd_pcm_oss_get_block_size(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; return substream->runtime->oss.period_bytes;}static int snd_pcm_oss_get_formats(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; int direct; snd_pcm_hw_params_t *params; unsigned int formats = 0; snd_mask_t format_mask; int fmt; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; if (atomic_read(&substream->runtime->mmap_count)) { direct = 1; } else { snd_pcm_oss_setup_t *setup = substream->oss.setup; direct = (setup != NULL && setup->direct); } if (!direct) return AFMT_MU_LAW | AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE; params = kmalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; _snd_pcm_hw_params_any(params); err = snd_pcm_hw_refine(substream, params); format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); kfree(params); snd_assert(err >= 0, return err); for (fmt = 0; fmt < 32; ++fmt) { if (snd_mask_test(&format_mask, fmt)) { int f = snd_pcm_oss_format_to(fmt); if (f >= 0) formats |= f; } } return formats;}static int snd_pcm_oss_set_format(snd_pcm_oss_file_t *pcm_oss_file, int format){ int formats, idx; if (format != AFMT_QUERY) { formats = snd_pcm_oss_get_formats(pcm_oss_file); if (!(formats & format)) format = AFMT_U8; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; if (runtime->oss.format != format) { runtime->oss.params = 1; runtime->oss.format = format; } } } return snd_pcm_oss_get_format(pcm_oss_file);}static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; int err; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) return err; return substream->runtime->oss.format;}static int snd_pcm_oss_set_subdivide1(snd_pcm_substream_t *substream, int subdivide){ snd_pcm_runtime_t *runtime; if (substream == NULL) return 0; runtime = substream->runtime; if (subdivide == 0) { subdivide = runtime->oss.subdivision; if (subdivide == 0) subdivide = 1; return subdivide; } if (runtime->oss.subdivision || runtime->oss.fragshift) return -EINVAL; if (subdivide != 1 && subdivide != 2 && subdivide != 4 && subdivide != 8 && subdivide != 16) return -EINVAL; runtime->oss.subdivision = subdivide; runtime->oss.params = 1; return subdivide;}static int snd_pcm_oss_set_subdivide(snd_pcm_oss_file_t *pcm_oss_file, int subdivide){ int err = -EINVAL, idx; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; if (substream == NULL) continue; if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0) return err; } return err;}static int snd_pcm_oss_set_fragment1(snd_pcm_substream_t *substream, unsigned int val){ snd_pcm_runtime_t *runtime; if (substream == NULL) return 0; runtime = substream->runtime; if (runtime->oss.subdivision || runtime->oss.fragshift) return -EINVAL; runtime->oss.fragshift = val & 0xffff; runtime->oss.maxfrags = (val >> 16) & 0xffff; if (runtime->oss.fragshift < 4) /* < 16 */ runtime->oss.fragshift = 4; if (runtime->oss.maxfrags < 2) runtime->oss.maxfrags = 2; runtime->oss.params = 1; return 0;}static int snd_pcm_oss_set_fragment(snd_pcm_oss_file_t *pcm_oss_file, unsigned int val){ int err = -EINVAL, idx; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; if (substream == NULL) continue; if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0) return err; } return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -