dummy.c
来自「linux 内核源代码」· C语言 代码 · 共 703 行 · 第 1/2 页
C
703 行
runtime->private_free = snd_card_dummy_runtime_free; runtime->hw = snd_card_dummy_playback; if (substream->pcm->device & 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; } if (substream->pcm->device & 2) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); if ((err = add_playback_constraints(runtime)) < 0) { kfree(dpcm); return err; } return 0;}static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream){ struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dummy_pcm *dpcm; int err; if ((dpcm = new_pcm_stream(substream)) == NULL) return -ENOMEM; runtime->private_data = dpcm; runtime->private_free = snd_card_dummy_runtime_free; runtime->hw = snd_card_dummy_capture; if (substream->pcm->device == 1) { runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; } if (substream->pcm->device & 2) runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); if ((err = add_capture_constraints(runtime)) < 0) { kfree(dpcm); return err; } return 0;}static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream){ return 0;}static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream){ return 0;}static struct snd_pcm_ops snd_card_dummy_playback_ops = { .open = snd_card_dummy_playback_open, .close = snd_card_dummy_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_card_dummy_hw_params, .hw_free = snd_card_dummy_hw_free, .prepare = snd_card_dummy_pcm_prepare, .trigger = snd_card_dummy_pcm_trigger, .pointer = snd_card_dummy_pcm_pointer,};static struct snd_pcm_ops snd_card_dummy_capture_ops = { .open = snd_card_dummy_capture_open, .close = snd_card_dummy_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_card_dummy_hw_params, .hw_free = snd_card_dummy_hw_free, .prepare = snd_card_dummy_pcm_prepare, .trigger = snd_card_dummy_pcm_trigger, .pointer = snd_card_dummy_pcm_pointer,};static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int substreams){ struct snd_pcm *pcm; int err; if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, substreams, substreams, &pcm)) < 0) return err; dummy->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); pcm->private_data = dummy; pcm->info_flags = 0; strcpy(pcm->name, "Dummy PCM"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, 64*1024); return 0;}#define DUMMY_VOLUME(xname, xindex, addr) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .name = xname, .index = xindex, \ .info = snd_dummy_volume_info, \ .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ .private_value = addr, \ .tlv = { .p = db_scale_dummy } }static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = -50; uinfo->value.integer.max = 100; return 0;} static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int addr = kcontrol->private_value; spin_lock_irq(&dummy->mixer_lock); ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0]; ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1]; spin_unlock_irq(&dummy->mixer_lock); return 0;}static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int change, addr = kcontrol->private_value; int left, right; left = ucontrol->value.integer.value[0]; if (left < -50) left = -50; if (left > 100) left = 100; right = ucontrol->value.integer.value[1]; if (right < -50) right = -50; if (right > 100) right = 100; spin_lock_irq(&dummy->mixer_lock); change = dummy->mixer_volume[addr][0] != left || dummy->mixer_volume[addr][1] != right; dummy->mixer_volume[addr][0] = left; dummy->mixer_volume[addr][1] = right; spin_unlock_irq(&dummy->mixer_lock); return change;}static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);#define DUMMY_CAPSRC(xname, xindex, addr) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_dummy_capsrc_info, \ .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \ .private_value = addr }#define snd_dummy_capsrc_info snd_ctl_boolean_stereo_info static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int addr = kcontrol->private_value; spin_lock_irq(&dummy->mixer_lock); ucontrol->value.integer.value[0] = dummy->capture_source[addr][0]; ucontrol->value.integer.value[1] = dummy->capture_source[addr][1]; spin_unlock_irq(&dummy->mixer_lock); return 0;}static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); int change, addr = kcontrol->private_value; int left, right; left = ucontrol->value.integer.value[0] & 1; right = ucontrol->value.integer.value[1] & 1; spin_lock_irq(&dummy->mixer_lock); change = dummy->capture_source[addr][0] != left && dummy->capture_source[addr][1] != right; dummy->capture_source[addr][0] = left; dummy->capture_source[addr][1] = right; spin_unlock_irq(&dummy->mixer_lock); return change;}static struct snd_kcontrol_new snd_dummy_controls[] = {DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)};static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy){ struct snd_card *card = dummy->card; unsigned int idx; int err; snd_assert(dummy != NULL, return -EINVAL); spin_lock_init(&dummy->mixer_lock); strcpy(card->mixername, "Dummy Mixer"); for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0) return err; } return 0;}static int __devinit snd_dummy_probe(struct platform_device *devptr){ struct snd_card *card; struct snd_dummy *dummy; int idx, err; int dev = devptr->id; card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_dummy)); if (card == NULL) return -ENOMEM; dummy = card->private_data; dummy->card = card; for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { if (pcm_substreams[dev] < 1) pcm_substreams[dev] = 1; if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0) goto __nodev; } if ((err = snd_card_dummy_new_mixer(dummy)) < 0) goto __nodev; strcpy(card->driver, "Dummy"); strcpy(card->shortname, "Dummy"); sprintf(card->longname, "Dummy %i", dev + 1); snd_card_set_dev(card, &devptr->dev); if ((err = snd_card_register(card)) == 0) { platform_set_drvdata(devptr, card); return 0; } __nodev: snd_card_free(card); return err;}static int __devexit snd_dummy_remove(struct platform_device *devptr){ snd_card_free(platform_get_drvdata(devptr)); platform_set_drvdata(devptr, NULL); return 0;}#ifdef CONFIG_PMstatic int snd_dummy_suspend(struct platform_device *pdev, pm_message_t state){ struct snd_card *card = platform_get_drvdata(pdev); struct snd_dummy *dummy = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(dummy->pcm); return 0;} static int snd_dummy_resume(struct platform_device *pdev){ struct snd_card *card = platform_get_drvdata(pdev); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endif#define SND_DUMMY_DRIVER "snd_dummy"static struct platform_driver snd_dummy_driver = { .probe = snd_dummy_probe, .remove = __devexit_p(snd_dummy_remove),#ifdef CONFIG_PM .suspend = snd_dummy_suspend, .resume = snd_dummy_resume,#endif .driver = { .name = SND_DUMMY_DRIVER },};static void snd_dummy_unregister_all(void){ int i; for (i = 0; i < ARRAY_SIZE(devices); ++i) platform_device_unregister(devices[i]); platform_driver_unregister(&snd_dummy_driver);}static int __init alsa_card_dummy_init(void){ int i, cards, err; if ((err = platform_driver_register(&snd_dummy_driver)) < 0) return err; cards = 0; for (i = 0; i < SNDRV_CARDS; i++) { struct platform_device *device; if (! enable[i]) continue; device = platform_device_register_simple(SND_DUMMY_DRIVER, i, NULL, 0); if (IS_ERR(device)) continue; if (!platform_get_drvdata(device)) { platform_device_unregister(device); continue; } devices[i] = device; cards++; } if (!cards) {#ifdef MODULE printk(KERN_ERR "Dummy soundcard not found or device busy\n");#endif snd_dummy_unregister_all(); return -ENODEV; } return 0;}static void __exit alsa_card_dummy_exit(void){ snd_dummy_unregister_all();}module_init(alsa_card_dummy_init)module_exit(alsa_card_dummy_exit)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?