📄 pcm.c
字号:
static void snd_pcm_tick_timer_func(unsigned long data){ snd_pcm_substream_t *substream = (snd_pcm_substream_t*) data; snd_pcm_tick_elapsed(substream);}int snd_pcm_open_substream(snd_pcm_t *pcm, int stream, snd_pcm_substream_t **rsubstream){ snd_pcm_str_t * pstr; snd_pcm_substream_t * substream; snd_pcm_runtime_t * runtime; snd_ctl_file_t *kctl; snd_card_t *card; struct list_head *list; int prefer_subdevice = -1; size_t size; snd_assert(rsubstream != NULL, return -EINVAL); *rsubstream = NULL; snd_assert(pcm != NULL, return -ENXIO); pstr = &pcm->streams[stream]; if (pstr->substream == NULL) return -ENODEV; card = pcm->card; down_read(&card->controls_rwsem); list_for_each(list, &card->ctl_files) { kctl = snd_ctl_file(list); if (kctl->pid == current->pid) { prefer_subdevice = kctl->prefer_pcm_subdevice; break; } } up_read(&card->controls_rwsem); if (pstr->substream_count == 0) return -ENODEV; switch (stream) { case SNDRV_PCM_STREAM_PLAYBACK: if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { if (SUBSTREAM_BUSY(substream)) return -EAGAIN; } } break; case SNDRV_PCM_STREAM_CAPTURE: if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { if (SUBSTREAM_BUSY(substream)) return -EAGAIN; } } break; default: return -EINVAL; } if (prefer_subdevice >= 0) { for (substream = pstr->substream; substream; substream = substream->next) if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) goto __ok; } for (substream = pstr->substream; substream; substream = substream->next) if (!SUBSTREAM_BUSY(substream)) break; __ok: if (substream == NULL) return -EAGAIN; runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL); if (runtime == NULL) return -ENOMEM; size = PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)); runtime->status = snd_malloc_pages(size, GFP_KERNEL); if (runtime->status == NULL) { kfree(runtime); return -ENOMEM; } memset((void*)runtime->status, 0, size); size = PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)); runtime->control = snd_malloc_pages(size, GFP_KERNEL); if (runtime->control == NULL) { snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))); kfree(runtime); return -ENOMEM; } memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); atomic_set(&runtime->mmap_count, 0); init_timer(&runtime->tick_timer); runtime->tick_timer.function = snd_pcm_tick_timer_func; runtime->tick_timer.data = (unsigned long) substream; runtime->status->state = SNDRV_PCM_STATE_OPEN; substream->runtime = runtime; substream->private_data = pcm->private_data; pstr->substream_opened++; *rsubstream = substream; return 0;}void snd_pcm_release_substream(snd_pcm_substream_t *substream){ snd_pcm_runtime_t * runtime; substream->file = NULL; runtime = substream->runtime; snd_assert(runtime != NULL, return); if (runtime->private_free != NULL) runtime->private_free(runtime); snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))); snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t))); if (runtime->hw_constraints.rules) kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; substream->pstr->substream_opened--;}static int snd_pcm_dev_register(snd_device_t *device){ int idx, cidx, err; unsigned short minor; snd_pcm_substream_t *substream; struct list_head *list; char str[16]; snd_pcm_t *pcm = device->device_data; snd_assert(pcm != NULL && device != NULL, return -ENXIO); down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; if (snd_pcm_devices[idx]) { up(®ister_mutex); return -EBUSY; } snd_pcm_devices[idx] = pcm; for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; if (pcm->streams[cidx].substream == NULL) continue; switch (cidx) { case SNDRV_PCM_STREAM_PLAYBACK: sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device); minor = SNDRV_MINOR_PCM_PLAYBACK + idx; devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; break; case SNDRV_PCM_STREAM_CAPTURE: sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device); minor = SNDRV_MINOR_PCM_CAPTURE + idx; devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } if ((err = snd_register_device(devtype, pcm->card, pcm->device, pcm->streams[cidx].reg, str)) < 0) { snd_pcm_devices[idx] = NULL; up(®ister_mutex); return err; } for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_init(substream); } list_for_each(list, &snd_pcm_notify_list) { snd_pcm_notify_t *notify; notify = list_entry(list, snd_pcm_notify_t, list); notify->n_register(pcm); } up(®ister_mutex); return 0;}static int snd_pcm_dev_disconnect(snd_device_t *device){ snd_pcm_t *pcm = device->device_data; struct list_head *list; snd_pcm_substream_t *substream; int idx, cidx; down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; for (cidx = 0; cidx < 2; cidx++) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) if (substream->runtime) substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; list_for_each(list, &snd_pcm_notify_list) { snd_pcm_notify_t *notify; notify = list_entry(list, snd_pcm_notify_t, list); notify->n_disconnect(pcm); } up(®ister_mutex); return 0;}static int snd_pcm_dev_unregister(snd_device_t *device){ int idx, cidx, devtype; snd_pcm_substream_t *substream; struct list_head *list; snd_pcm_t *pcm = device->device_data; snd_assert(pcm != NULL, return -ENXIO); down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; for (cidx = 0; cidx < 2; cidx++) { devtype = -1; switch (cidx) { case SNDRV_PCM_STREAM_PLAYBACK: devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK; break; case SNDRV_PCM_STREAM_CAPTURE: devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE; break; } snd_unregister_device(devtype, pcm->card, pcm->device); for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_done(substream); } list_for_each(list, &snd_pcm_notify_list) { snd_pcm_notify_t *notify; notify = list_entry(list, snd_pcm_notify_t, list); notify->n_unregister(pcm); } up(®ister_mutex); return snd_pcm_free(pcm);}int snd_pcm_notify(snd_pcm_notify_t *notify, int nfree){ int idx; snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); down(®ister_mutex); if (nfree) { list_del(¬ify->list); for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { if (snd_pcm_devices[idx] == NULL) continue; notify->n_unregister(snd_pcm_devices[idx]); } } else { list_add_tail(¬ify->list, &snd_pcm_notify_list); for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { if (snd_pcm_devices[idx] == NULL) continue; notify->n_register(snd_pcm_devices[idx]); } } up(®ister_mutex); return 0;}/* * Info interface */static void snd_pcm_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ int idx; snd_pcm_t *pcm; down(®ister_mutex); for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { pcm = snd_pcm_devices[idx]; if (pcm == NULL) continue; snd_iprintf(buffer, "%02i-%02i: %s : %s", idx / SNDRV_PCM_DEVICES, idx % SNDRV_PCM_DEVICES, pcm->id, pcm->name); if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) snd_iprintf(buffer, " : playback %i", pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count); if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) snd_iprintf(buffer, " : capture %i", pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count); snd_iprintf(buffer, "\n"); } up(®ister_mutex);}/* * ENTRY functions */static snd_info_entry_t *snd_pcm_proc_entry = NULL;static int __init alsa_pcm_init(void){ snd_info_entry_t *entry; snd_ctl_register_ioctl(snd_pcm_control_ioctl); if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } snd_pcm_proc_entry = entry; return 0;}static void __exit alsa_pcm_exit(void){ snd_ctl_unregister_ioctl(snd_pcm_control_ioctl); if (snd_pcm_proc_entry) { snd_info_unregister(snd_pcm_proc_entry); snd_pcm_proc_entry = NULL; }}module_init(alsa_pcm_init)module_exit(alsa_pcm_exit)EXPORT_SYMBOL(snd_pcm_devices);EXPORT_SYMBOL(snd_pcm_new);EXPORT_SYMBOL(snd_pcm_new_stream);EXPORT_SYMBOL(snd_pcm_notify);EXPORT_SYMBOL(snd_pcm_open_substream);EXPORT_SYMBOL(snd_pcm_release_substream);EXPORT_SYMBOL(snd_pcm_format_name);EXPORT_SYMBOL(snd_pcm_subformat_name); /* pcm_native.c */EXPORT_SYMBOL(snd_pcm_link_rwlock);EXPORT_SYMBOL(snd_pcm_start);#ifdef CONFIG_PMEXPORT_SYMBOL(snd_pcm_suspend);EXPORT_SYMBOL(snd_pcm_suspend_all);#endifEXPORT_SYMBOL(snd_pcm_kernel_playback_ioctl);EXPORT_SYMBOL(snd_pcm_kernel_capture_ioctl);EXPORT_SYMBOL(snd_pcm_kernel_ioctl);EXPORT_SYMBOL(snd_pcm_open);EXPORT_SYMBOL(snd_pcm_release);EXPORT_SYMBOL(snd_pcm_playback_poll);EXPORT_SYMBOL(snd_pcm_capture_poll);EXPORT_SYMBOL(snd_pcm_mmap_data);#if SNDRV_PCM_INFO_MMAP_IOMEMEXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);#endif /* pcm_misc.c */EXPORT_SYMBOL(snd_pcm_format_signed);EXPORT_SYMBOL(snd_pcm_format_unsigned);EXPORT_SYMBOL(snd_pcm_format_linear);EXPORT_SYMBOL(snd_pcm_format_little_endian);EXPORT_SYMBOL(snd_pcm_format_big_endian);EXPORT_SYMBOL(snd_pcm_format_width);EXPORT_SYMBOL(snd_pcm_format_physical_width);EXPORT_SYMBOL(snd_pcm_format_size);EXPORT_SYMBOL(snd_pcm_format_silence_64);EXPORT_SYMBOL(snd_pcm_format_set_silence);EXPORT_SYMBOL(snd_pcm_build_linear_format);EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -