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 + -
显示快捷键?