xref: /OK3568_Linux_fs/kernel/sound/synth/emux/emux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Routines for control of EMU WaveTable chip
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/wait.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/string.h>
11*4882a593Smuzhiyun #include <sound/core.h>
12*4882a593Smuzhiyun #include <sound/emux_synth.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include "emux_voice.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun MODULE_AUTHOR("Takashi Iwai");
18*4882a593Smuzhiyun MODULE_DESCRIPTION("Routines for control of EMU WaveTable chip");
19*4882a593Smuzhiyun MODULE_LICENSE("GPL");
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun  * create a new hardware dependent device for Emu8000/Emu10k1
23*4882a593Smuzhiyun  */
snd_emux_new(struct snd_emux ** remu)24*4882a593Smuzhiyun int snd_emux_new(struct snd_emux **remu)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct snd_emux *emu;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	*remu = NULL;
29*4882a593Smuzhiyun 	emu = kzalloc(sizeof(*emu), GFP_KERNEL);
30*4882a593Smuzhiyun 	if (emu == NULL)
31*4882a593Smuzhiyun 		return -ENOMEM;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	spin_lock_init(&emu->voice_lock);
34*4882a593Smuzhiyun 	mutex_init(&emu->register_mutex);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	emu->client = -1;
37*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
38*4882a593Smuzhiyun 	emu->oss_synth = NULL;
39*4882a593Smuzhiyun #endif
40*4882a593Smuzhiyun 	emu->max_voices = 0;
41*4882a593Smuzhiyun 	emu->use_time = 0;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	timer_setup(&emu->tlist, snd_emux_timer_callback, 0);
44*4882a593Smuzhiyun 	emu->timer_active = 0;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	*remu = emu;
47*4882a593Smuzhiyun 	return 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun EXPORT_SYMBOL(snd_emux_new);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun  */
sf_sample_new(void * private_data,struct snd_sf_sample * sp,struct snd_util_memhdr * hdr,const void __user * buf,long count)54*4882a593Smuzhiyun static int sf_sample_new(void *private_data, struct snd_sf_sample *sp,
55*4882a593Smuzhiyun 				  struct snd_util_memhdr *hdr,
56*4882a593Smuzhiyun 				  const void __user *buf, long count)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct snd_emux *emu = private_data;
59*4882a593Smuzhiyun 	return emu->ops.sample_new(emu, sp, hdr, buf, count);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
sf_sample_free(void * private_data,struct snd_sf_sample * sp,struct snd_util_memhdr * hdr)63*4882a593Smuzhiyun static int sf_sample_free(void *private_data, struct snd_sf_sample *sp,
64*4882a593Smuzhiyun 				   struct snd_util_memhdr *hdr)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct snd_emux *emu = private_data;
67*4882a593Smuzhiyun 	return emu->ops.sample_free(emu, sp, hdr);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
sf_sample_reset(void * private_data)71*4882a593Smuzhiyun static void sf_sample_reset(void *private_data)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct snd_emux *emu = private_data;
74*4882a593Smuzhiyun 	emu->ops.sample_reset(emu);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
snd_emux_register(struct snd_emux * emu,struct snd_card * card,int index,char * name)77*4882a593Smuzhiyun int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, char *name)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int err;
80*4882a593Smuzhiyun 	struct snd_sf_callback sf_cb;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (snd_BUG_ON(!emu->hw || emu->max_voices <= 0))
83*4882a593Smuzhiyun 		return -EINVAL;
84*4882a593Smuzhiyun 	if (snd_BUG_ON(!card || !name))
85*4882a593Smuzhiyun 		return -EINVAL;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	emu->card = card;
88*4882a593Smuzhiyun 	emu->name = kstrdup(name, GFP_KERNEL);
89*4882a593Smuzhiyun 	emu->voices = kcalloc(emu->max_voices, sizeof(struct snd_emux_voice),
90*4882a593Smuzhiyun 			      GFP_KERNEL);
91*4882a593Smuzhiyun 	if (emu->name == NULL || emu->voices == NULL)
92*4882a593Smuzhiyun 		return -ENOMEM;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* create soundfont list */
95*4882a593Smuzhiyun 	memset(&sf_cb, 0, sizeof(sf_cb));
96*4882a593Smuzhiyun 	sf_cb.private_data = emu;
97*4882a593Smuzhiyun 	if (emu->ops.sample_new)
98*4882a593Smuzhiyun 		sf_cb.sample_new = sf_sample_new;
99*4882a593Smuzhiyun 	if (emu->ops.sample_free)
100*4882a593Smuzhiyun 		sf_cb.sample_free = sf_sample_free;
101*4882a593Smuzhiyun 	if (emu->ops.sample_reset)
102*4882a593Smuzhiyun 		sf_cb.sample_reset = sf_sample_reset;
103*4882a593Smuzhiyun 	emu->sflist = snd_sf_new(&sf_cb, emu->memhdr);
104*4882a593Smuzhiyun 	if (emu->sflist == NULL)
105*4882a593Smuzhiyun 		return -ENOMEM;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if ((err = snd_emux_init_hwdep(emu)) < 0)
108*4882a593Smuzhiyun 		return err;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	snd_emux_init_voices(emu);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	snd_emux_init_seq(emu, card, index);
113*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
114*4882a593Smuzhiyun 	snd_emux_init_seq_oss(emu);
115*4882a593Smuzhiyun #endif
116*4882a593Smuzhiyun 	snd_emux_init_virmidi(emu, card);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	snd_emux_proc_init(emu, card, index);
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun EXPORT_SYMBOL(snd_emux_register);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun  */
snd_emux_free(struct snd_emux * emu)126*4882a593Smuzhiyun int snd_emux_free(struct snd_emux *emu)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	if (! emu)
129*4882a593Smuzhiyun 		return -EINVAL;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	del_timer_sync(&emu->tlist);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	snd_emux_proc_free(emu);
134*4882a593Smuzhiyun 	snd_emux_delete_virmidi(emu);
135*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
136*4882a593Smuzhiyun 	snd_emux_detach_seq_oss(emu);
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun 	snd_emux_detach_seq(emu);
139*4882a593Smuzhiyun 	snd_emux_delete_hwdep(emu);
140*4882a593Smuzhiyun 	snd_sf_free(emu->sflist);
141*4882a593Smuzhiyun 	kfree(emu->voices);
142*4882a593Smuzhiyun 	kfree(emu->name);
143*4882a593Smuzhiyun 	kfree(emu);
144*4882a593Smuzhiyun 	return 0;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun EXPORT_SYMBOL(snd_emux_free);
148