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