pcm_native.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,359 行 · 第 1/5 页
C
2,359 行
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_pcm_hw_rule_rate, hw, SNDRV_PCM_HW_PARAM_RATE, -1); if (err < 0) return err; } /* FIXME: this belong to lowlevel */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, 1000000 / HZ, 1000000 / HZ); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return 0;}static void snd_pcm_add_file(snd_pcm_str_t *str, snd_pcm_file_t *pcm_file){ pcm_file->next = str->files; str->files = pcm_file;}static void snd_pcm_remove_file(snd_pcm_str_t *str, snd_pcm_file_t *pcm_file){ snd_pcm_file_t * pcm_file1; if (str->files == pcm_file) { str->files = pcm_file->next; } else { pcm_file1 = str->files; while (pcm_file1 && pcm_file1->next != pcm_file) pcm_file1 = pcm_file1->next; if (pcm_file1 != NULL) pcm_file1->next = pcm_file->next; }}static int snd_pcm_release_file(snd_pcm_file_t * pcm_file){ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_str_t * str; snd_assert(pcm_file != NULL, return -ENXIO); substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); runtime = substream->runtime; str = substream->pstr; snd_pcm_unlink(substream); if (substream->open_flag) { if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); substream->ops->close(substream); substream->open_flag = 0; } substream->ffile = NULL; snd_pcm_remove_file(str, pcm_file); snd_pcm_release_substream(substream); kfree(pcm_file); return 0;}static int snd_pcm_open_file(struct file *file, snd_pcm_t *pcm, int stream, snd_pcm_file_t **rpcm_file){ int err = 0; snd_pcm_file_t *pcm_file; snd_pcm_substream_t *substream; snd_pcm_str_t *str; snd_assert(rpcm_file != NULL, return -EINVAL); *rpcm_file = NULL; pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL); if (pcm_file == NULL) { return -ENOMEM; } if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) { kfree(pcm_file); return err; } str = substream->pstr; substream->file = pcm_file; pcm_file->substream = substream; snd_pcm_add_file(str, pcm_file); err = snd_pcm_hw_constraints_init(substream); if (err < 0) { snd_printd("snd_pcm_hw_constraints_init failed\n"); snd_pcm_release_file(pcm_file); return err; } if ((err = substream->ops->open(substream)) < 0) { snd_pcm_release_file(pcm_file); return err; } substream->open_flag = 1; err = snd_pcm_hw_constraints_complete(substream); if (err < 0) { snd_printd("snd_pcm_hw_constraints_complete failed\n"); substream->ops->close(substream); snd_pcm_release_file(pcm_file); return err; } substream->ffile = file; file->private_data = pcm_file; *rpcm_file = pcm_file; return 0;}int snd_pcm_open(struct inode *inode, struct file *file){ int cardnum = SNDRV_MINOR_CARD(iminor(inode)); int device = SNDRV_MINOR_DEVICE(iminor(inode)); int err; snd_pcm_t *pcm; snd_pcm_file_t *pcm_file; wait_queue_t wait; snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO); pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)]; if (pcm == NULL) { err = -ENODEV; goto __error1; } err = snd_card_file_add(pcm->card, file); if (err < 0) goto __error1; if (!try_module_get(pcm->card->module)) { err = -EFAULT; goto __error2; } init_waitqueue_entry(&wait, current); add_wait_queue(&pcm->open_wait, &wait); down(&pcm->open_mutex); while (1) { err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file); if (err >= 0) break; if (err == -EAGAIN) { if (file->f_flags & O_NONBLOCK) { err = -EBUSY; break; } } else break; set_current_state(TASK_INTERRUPTIBLE); up(&pcm->open_mutex); schedule(); down(&pcm->open_mutex); if (signal_pending(current)) { err = -ERESTARTSYS; break; } } remove_wait_queue(&pcm->open_wait, &wait); up(&pcm->open_mutex); if (err < 0) goto __error; return err; __error: module_put(pcm->card->module); __error2: snd_card_file_remove(pcm->card, file); __error1: return err;}int snd_pcm_release(struct inode *inode, struct file *file){ snd_pcm_t *pcm; snd_pcm_substream_t *substream; snd_pcm_file_t *pcm_file; pcm_file = file->private_data; substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); snd_assert(!atomic_read(&substream->runtime->mmap_count), ); pcm = substream->pcm; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_playback_drop(substream); else snd_pcm_capture_drop(substream); fasync_helper(-1, file, 0, &substream->runtime->fasync); down(&pcm->open_mutex); snd_pcm_release_file(pcm_file); up(&pcm->open_mutex); wake_up(&pcm->open_wait); module_put(pcm->card->module); snd_card_file_remove(pcm->card, file); return 0;}snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; snd_pcm_sframes_t hw_avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: break; case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: if (snd_pcm_update_hw_ptr(substream) >= 0) break; /* Fall through */ case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; default: ret = -EBADFD; goto __end; } hw_avail = snd_pcm_playback_hw_avail(runtime); if (hw_avail <= 0) { ret = 0; goto __end; } if (frames > (snd_pcm_uframes_t)hw_avail) frames = hw_avail; else frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; runtime->control->appl_ptr = appl_ptr; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && runtime->sleep_min) snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); return ret;}snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; snd_pcm_sframes_t hw_avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_DRAINING: break; case SNDRV_PCM_STATE_RUNNING: if (snd_pcm_update_hw_ptr(substream) >= 0) break; /* Fall through */ case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; default: ret = -EBADFD; goto __end; } hw_avail = snd_pcm_capture_hw_avail(runtime); if (hw_avail <= 0) { ret = 0; goto __end; } if (frames > (snd_pcm_uframes_t)hw_avail) frames = hw_avail; else frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; runtime->control->appl_ptr = appl_ptr; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && runtime->sleep_min) snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); return ret;}snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; snd_pcm_sframes_t avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: break; case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: if (snd_pcm_update_hw_ptr(substream) >= 0) break; /* Fall through */ case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; default: ret = -EBADFD; goto __end; } avail = snd_pcm_playback_avail(runtime); if (avail <= 0) { ret = 0; goto __end; } if (frames > (snd_pcm_uframes_t)avail) frames = avail; else frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; runtime->control->appl_ptr = appl_ptr; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && runtime->sleep_min) snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); return ret;}snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t appl_ptr; snd_pcm_sframes_t ret; snd_pcm_sframes_t avail; if (frames == 0) return 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_PAUSED: break; case SNDRV_PCM_STATE_RUNNING: if (snd_pcm_update_hw_ptr(substream) >= 0) break; /* Fall through */ case SNDRV_PCM_STATE_XRUN: ret = -EPIPE; goto __end; default: ret = -EBADFD; goto __end; } avail = snd_pcm_capture_avail(runtime); if (avail <= 0) { ret = 0; goto __end; } if (frames > (snd_pcm_uframes_t)avail) frames = avail; else frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; runtime->control->appl_ptr = appl_ptr; if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && runtime->sleep_min) snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); return ret;}static int snd_pcm_hwsync(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; int err; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_DRAINING: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) goto __badfd; case SNDRV_PCM_STATE_RUNNING: if ((err = snd_pcm_update_hw_ptr(substream)) < 0) break; /* Fall through */ case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: err = 0; break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; break; default: __badfd: err = -EBADFD; break; } snd_pcm_stream_unlock_irq(substream); return err;} static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res){ snd_pcm_runtime_t *runtime = substream->runtime; int err; snd_pcm_sframes_t n = 0; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_DRAINING: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) goto __badfd; case SNDRV_PCM_STATE_RUNNING: if ((err = snd_pcm_update_hw_ptr(substream)) < 0) break; /* Fall through */ case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: err = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) n = snd_pcm_playback_hw_avail(runtime); else n = snd_pcm_capture_avail(runtime); break; case SNDRV_PCM_STATE_XRUN: err = -EPIPE; break; default: __badfd: err = -EBADFD; break; } snd_pcm_stream_unlock_irq(substream); if (!err) if (put_user(n, res)) err = -EFAULT; return err;} static int snd_pcm_sync_ptr(snd_
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?