xref: /OK3568_Linux_fs/kernel/sound/core/seq_device.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  ALSA sequencer device management
4*4882a593Smuzhiyun  *  Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *----------------------------------------------------------------
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This device handler separates the card driver module from sequencer
9*4882a593Smuzhiyun  * stuff (sequencer core, synth drivers, etc), so that user can avoid
10*4882a593Smuzhiyun  * to spend unnecessary resources e.g. if he needs only listening to
11*4882a593Smuzhiyun  * MP3s.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * The card (or lowlevel) driver creates a sequencer device entry
14*4882a593Smuzhiyun  * via snd_seq_device_new().  This is an entry pointer to communicate
15*4882a593Smuzhiyun  * with the sequencer device "driver", which is involved with the
16*4882a593Smuzhiyun  * actual part to communicate with the sequencer core.
17*4882a593Smuzhiyun  * Each sequencer device entry has an id string and the corresponding
18*4882a593Smuzhiyun  * driver with the same id is loaded when required.  For example,
19*4882a593Smuzhiyun  * lowlevel codes to access emu8000 chip on sbawe card are included in
20*4882a593Smuzhiyun  * emu8000-synth module.  To activate this module, the hardware
21*4882a593Smuzhiyun  * resources like i/o port are passed via snd_seq_device argument.
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <linux/device.h>
25*4882a593Smuzhiyun #include <linux/init.h>
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <sound/core.h>
28*4882a593Smuzhiyun #include <sound/info.h>
29*4882a593Smuzhiyun #include <sound/seq_device.h>
30*4882a593Smuzhiyun #include <sound/seq_kernel.h>
31*4882a593Smuzhiyun #include <sound/initval.h>
32*4882a593Smuzhiyun #include <linux/kmod.h>
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun #include <linux/mutex.h>
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
37*4882a593Smuzhiyun MODULE_DESCRIPTION("ALSA sequencer device management");
38*4882a593Smuzhiyun MODULE_LICENSE("GPL");
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /*
41*4882a593Smuzhiyun  * bus definition
42*4882a593Smuzhiyun  */
snd_seq_bus_match(struct device * dev,struct device_driver * drv)43*4882a593Smuzhiyun static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	struct snd_seq_device *sdev = to_seq_dev(dev);
46*4882a593Smuzhiyun 	struct snd_seq_driver *sdrv = to_seq_drv(drv);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	return strcmp(sdrv->id, sdev->id) == 0 &&
49*4882a593Smuzhiyun 		sdrv->argsize == sdev->argsize;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static struct bus_type snd_seq_bus_type = {
53*4882a593Smuzhiyun 	.name = "snd_seq",
54*4882a593Smuzhiyun 	.match = snd_seq_bus_match,
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun  * proc interface -- just for compatibility
59*4882a593Smuzhiyun  */
60*4882a593Smuzhiyun #ifdef CONFIG_SND_PROC_FS
61*4882a593Smuzhiyun static struct snd_info_entry *info_entry;
62*4882a593Smuzhiyun 
print_dev_info(struct device * dev,void * data)63*4882a593Smuzhiyun static int print_dev_info(struct device *dev, void *data)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	struct snd_seq_device *sdev = to_seq_dev(dev);
66*4882a593Smuzhiyun 	struct snd_info_buffer *buffer = data;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
69*4882a593Smuzhiyun 		    dev->driver ? "loaded" : "empty",
70*4882a593Smuzhiyun 		    dev->driver ? 1 : 0);
71*4882a593Smuzhiyun 	return 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
snd_seq_device_info(struct snd_info_entry * entry,struct snd_info_buffer * buffer)74*4882a593Smuzhiyun static void snd_seq_device_info(struct snd_info_entry *entry,
75*4882a593Smuzhiyun 				struct snd_info_buffer *buffer)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun  * load all registered drivers (called from seq_clientmgr.c)
83*4882a593Smuzhiyun  */
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #ifdef CONFIG_MODULES
86*4882a593Smuzhiyun /* flag to block auto-loading */
87*4882a593Smuzhiyun static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
88*4882a593Smuzhiyun 
request_seq_drv(struct device * dev,void * data)89*4882a593Smuzhiyun static int request_seq_drv(struct device *dev, void *data)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct snd_seq_device *sdev = to_seq_dev(dev);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (!dev->driver)
94*4882a593Smuzhiyun 		request_module("snd-%s", sdev->id);
95*4882a593Smuzhiyun 	return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
autoload_drivers(struct work_struct * work)98*4882a593Smuzhiyun static void autoload_drivers(struct work_struct *work)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	/* avoid reentrance */
101*4882a593Smuzhiyun 	if (atomic_inc_return(&snd_seq_in_init) == 1)
102*4882a593Smuzhiyun 		bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
103*4882a593Smuzhiyun 				 request_seq_drv);
104*4882a593Smuzhiyun 	atomic_dec(&snd_seq_in_init);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static DECLARE_WORK(autoload_work, autoload_drivers);
108*4882a593Smuzhiyun 
queue_autoload_drivers(void)109*4882a593Smuzhiyun static void queue_autoload_drivers(void)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	schedule_work(&autoload_work);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
snd_seq_autoload_init(void)114*4882a593Smuzhiyun void snd_seq_autoload_init(void)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	atomic_dec(&snd_seq_in_init);
117*4882a593Smuzhiyun #ifdef CONFIG_SND_SEQUENCER_MODULE
118*4882a593Smuzhiyun 	/* initial autoload only when snd-seq is a module */
119*4882a593Smuzhiyun 	queue_autoload_drivers();
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun EXPORT_SYMBOL(snd_seq_autoload_init);
123*4882a593Smuzhiyun 
snd_seq_autoload_exit(void)124*4882a593Smuzhiyun void snd_seq_autoload_exit(void)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	atomic_inc(&snd_seq_in_init);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun EXPORT_SYMBOL(snd_seq_autoload_exit);
129*4882a593Smuzhiyun 
snd_seq_device_load_drivers(void)130*4882a593Smuzhiyun void snd_seq_device_load_drivers(void)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	queue_autoload_drivers();
133*4882a593Smuzhiyun 	flush_work(&autoload_work);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun EXPORT_SYMBOL(snd_seq_device_load_drivers);
136*4882a593Smuzhiyun #define cancel_autoload_drivers()	cancel_work_sync(&autoload_work)
137*4882a593Smuzhiyun #else
138*4882a593Smuzhiyun #define queue_autoload_drivers() /* NOP */
139*4882a593Smuzhiyun #define cancel_autoload_drivers() /* NOP */
140*4882a593Smuzhiyun #endif
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun  * device management
144*4882a593Smuzhiyun  */
snd_seq_device_dev_free(struct snd_device * device)145*4882a593Smuzhiyun static int snd_seq_device_dev_free(struct snd_device *device)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct snd_seq_device *dev = device->device_data;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	cancel_autoload_drivers();
150*4882a593Smuzhiyun 	if (dev->private_free)
151*4882a593Smuzhiyun 		dev->private_free(dev);
152*4882a593Smuzhiyun 	put_device(&dev->dev);
153*4882a593Smuzhiyun 	return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
snd_seq_device_dev_register(struct snd_device * device)156*4882a593Smuzhiyun static int snd_seq_device_dev_register(struct snd_device *device)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct snd_seq_device *dev = device->device_data;
159*4882a593Smuzhiyun 	int err;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	err = device_add(&dev->dev);
162*4882a593Smuzhiyun 	if (err < 0)
163*4882a593Smuzhiyun 		return err;
164*4882a593Smuzhiyun 	if (!dev->dev.driver)
165*4882a593Smuzhiyun 		queue_autoload_drivers();
166*4882a593Smuzhiyun 	return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
snd_seq_device_dev_disconnect(struct snd_device * device)169*4882a593Smuzhiyun static int snd_seq_device_dev_disconnect(struct snd_device *device)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct snd_seq_device *dev = device->device_data;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	device_del(&dev->dev);
174*4882a593Smuzhiyun 	return 0;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
snd_seq_dev_release(struct device * dev)177*4882a593Smuzhiyun static void snd_seq_dev_release(struct device *dev)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	kfree(to_seq_dev(dev));
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun /*
183*4882a593Smuzhiyun  * register a sequencer device
184*4882a593Smuzhiyun  * card = card info
185*4882a593Smuzhiyun  * device = device number (if any)
186*4882a593Smuzhiyun  * id = id of driver
187*4882a593Smuzhiyun  * result = return pointer (NULL allowed if unnecessary)
188*4882a593Smuzhiyun  */
snd_seq_device_new(struct snd_card * card,int device,const char * id,int argsize,struct snd_seq_device ** result)189*4882a593Smuzhiyun int snd_seq_device_new(struct snd_card *card, int device, const char *id,
190*4882a593Smuzhiyun 		       int argsize, struct snd_seq_device **result)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct snd_seq_device *dev;
193*4882a593Smuzhiyun 	int err;
194*4882a593Smuzhiyun 	static const struct snd_device_ops dops = {
195*4882a593Smuzhiyun 		.dev_free = snd_seq_device_dev_free,
196*4882a593Smuzhiyun 		.dev_register = snd_seq_device_dev_register,
197*4882a593Smuzhiyun 		.dev_disconnect = snd_seq_device_dev_disconnect,
198*4882a593Smuzhiyun 	};
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (result)
201*4882a593Smuzhiyun 		*result = NULL;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (snd_BUG_ON(!id))
204*4882a593Smuzhiyun 		return -EINVAL;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
207*4882a593Smuzhiyun 	if (!dev)
208*4882a593Smuzhiyun 		return -ENOMEM;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* set up device info */
211*4882a593Smuzhiyun 	dev->card = card;
212*4882a593Smuzhiyun 	dev->device = device;
213*4882a593Smuzhiyun 	dev->id = id;
214*4882a593Smuzhiyun 	dev->argsize = argsize;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	device_initialize(&dev->dev);
217*4882a593Smuzhiyun 	dev->dev.parent = &card->card_dev;
218*4882a593Smuzhiyun 	dev->dev.bus = &snd_seq_bus_type;
219*4882a593Smuzhiyun 	dev->dev.release = snd_seq_dev_release;
220*4882a593Smuzhiyun 	dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* add this device to the list */
223*4882a593Smuzhiyun 	err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
224*4882a593Smuzhiyun 	if (err < 0) {
225*4882a593Smuzhiyun 		put_device(&dev->dev);
226*4882a593Smuzhiyun 		return err;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	if (result)
230*4882a593Smuzhiyun 		*result = dev;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun EXPORT_SYMBOL(snd_seq_device_new);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun  * driver registration
238*4882a593Smuzhiyun  */
__snd_seq_driver_register(struct snd_seq_driver * drv,struct module * mod)239*4882a593Smuzhiyun int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	if (WARN_ON(!drv->driver.name || !drv->id))
242*4882a593Smuzhiyun 		return -EINVAL;
243*4882a593Smuzhiyun 	drv->driver.bus = &snd_seq_bus_type;
244*4882a593Smuzhiyun 	drv->driver.owner = mod;
245*4882a593Smuzhiyun 	return driver_register(&drv->driver);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
248*4882a593Smuzhiyun 
snd_seq_driver_unregister(struct snd_seq_driver * drv)249*4882a593Smuzhiyun void snd_seq_driver_unregister(struct snd_seq_driver *drv)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	driver_unregister(&drv->driver);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun /*
256*4882a593Smuzhiyun  * module part
257*4882a593Smuzhiyun  */
258*4882a593Smuzhiyun 
seq_dev_proc_init(void)259*4882a593Smuzhiyun static int __init seq_dev_proc_init(void)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun #ifdef CONFIG_SND_PROC_FS
262*4882a593Smuzhiyun 	info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
263*4882a593Smuzhiyun 						  snd_seq_root);
264*4882a593Smuzhiyun 	if (info_entry == NULL)
265*4882a593Smuzhiyun 		return -ENOMEM;
266*4882a593Smuzhiyun 	info_entry->content = SNDRV_INFO_CONTENT_TEXT;
267*4882a593Smuzhiyun 	info_entry->c.text.read = snd_seq_device_info;
268*4882a593Smuzhiyun 	if (snd_info_register(info_entry) < 0) {
269*4882a593Smuzhiyun 		snd_info_free_entry(info_entry);
270*4882a593Smuzhiyun 		return -ENOMEM;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
alsa_seq_device_init(void)276*4882a593Smuzhiyun static int __init alsa_seq_device_init(void)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	int err;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	err = bus_register(&snd_seq_bus_type);
281*4882a593Smuzhiyun 	if (err < 0)
282*4882a593Smuzhiyun 		return err;
283*4882a593Smuzhiyun 	err = seq_dev_proc_init();
284*4882a593Smuzhiyun 	if (err < 0)
285*4882a593Smuzhiyun 		bus_unregister(&snd_seq_bus_type);
286*4882a593Smuzhiyun 	return err;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
alsa_seq_device_exit(void)289*4882a593Smuzhiyun static void __exit alsa_seq_device_exit(void)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun #ifdef CONFIG_MODULES
292*4882a593Smuzhiyun 	cancel_work_sync(&autoload_work);
293*4882a593Smuzhiyun #endif
294*4882a593Smuzhiyun #ifdef CONFIG_SND_PROC_FS
295*4882a593Smuzhiyun 	snd_info_free_entry(info_entry);
296*4882a593Smuzhiyun #endif
297*4882a593Smuzhiyun 	bus_unregister(&snd_seq_bus_type);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun subsys_initcall(alsa_seq_device_init)
301*4882a593Smuzhiyun module_exit(alsa_seq_device_exit)
302