xref: /openbmc/linux/sound/core/seq/oss/seq_oss_init.c (revision 75016ca3)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * OSS compatible sequencer driver
4  *
5  * open/close and reset interface
6  *
7  * Copyright (C) 1998-1999 Takashi Iwai <tiwai@suse.de>
8  */
9 
10 #include "seq_oss_device.h"
11 #include "seq_oss_synth.h"
12 #include "seq_oss_midi.h"
13 #include "seq_oss_writeq.h"
14 #include "seq_oss_readq.h"
15 #include "seq_oss_timer.h"
16 #include "seq_oss_event.h"
17 #include <linux/init.h>
18 #include <linux/export.h>
19 #include <linux/moduleparam.h>
20 #include <linux/slab.h>
21 #include <linux/workqueue.h>
22 
23 /*
24  * common variables
25  */
26 static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
27 module_param(maxqlen, int, 0444);
28 MODULE_PARM_DESC(maxqlen, "maximum queue length");
29 
30 static int system_client = -1; /* ALSA sequencer client number */
31 static int system_port = -1;
32 
33 static int num_clients;
34 static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
35 
36 
37 /*
38  * prototypes
39  */
40 static int receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop);
41 static int translate_mode(struct file *file);
42 static int create_port(struct seq_oss_devinfo *dp);
43 static int delete_port(struct seq_oss_devinfo *dp);
44 static int alloc_seq_queue(struct seq_oss_devinfo *dp);
45 static int delete_seq_queue(int queue);
46 static void free_devinfo(void *private);
47 
48 #define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
49 
50 
51 /* call snd_seq_oss_midi_lookup_ports() asynchronously */
52 static void async_call_lookup_ports(struct work_struct *work)
53 {
54 	snd_seq_oss_midi_lookup_ports(system_client);
55 }
56 
57 static DECLARE_WORK(async_lookup_work, async_call_lookup_ports);
58 
59 /*
60  * create sequencer client for OSS sequencer
61  */
62 int __init
63 snd_seq_oss_create_client(void)
64 {
65 	int rc;
66 	struct snd_seq_port_info *port;
67 	struct snd_seq_port_callback port_callback;
68 
69 	port = kmalloc(sizeof(*port), GFP_KERNEL);
70 	if (!port) {
71 		rc = -ENOMEM;
72 		goto __error;
73 	}
74 
75 	/* create ALSA client */
76 	rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
77 					  "OSS sequencer");
78 	if (rc < 0)
79 		goto __error;
80 
81 	system_client = rc;
82 
83 	/* create annoucement receiver port */
84 	memset(port, 0, sizeof(*port));
85 	strcpy(port->name, "Receiver");
86 	port->addr.client = system_client;
87 	port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
88 	port->type = 0;
89 
90 	memset(&port_callback, 0, sizeof(port_callback));
91 	/* don't set port_callback.owner here. otherwise the module counter
92 	 * is incremented and we can no longer release the module..
93 	 */
94 	port_callback.event_input = receive_announce;
95 	port->kernel = &port_callback;
96 
97 	if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) {
98 		struct snd_seq_port_subscribe subs;
99 
100 		system_port = port->addr.port;
101 		memset(&subs, 0, sizeof(subs));
102 		subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
103 		subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
104 		subs.dest.client = system_client;
105 		subs.dest.port = system_port;
106 		call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
107 	}
108 	rc = 0;
109 
110 	/* look up midi devices */
111 	schedule_work(&async_lookup_work);
112 
113  __error:
114 	kfree(port);
115 	return rc;
116 }
117 
118 
119 /*
120  * receive annoucement from system port, and check the midi device
121  */
122 static int
123 receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop)
124 {
125 	struct snd_seq_port_info pinfo;
126 
127 	if (atomic)
128 		return 0; /* it must not happen */
129 
130 	switch (ev->type) {
131 	case SNDRV_SEQ_EVENT_PORT_START:
132 	case SNDRV_SEQ_EVENT_PORT_CHANGE:
133 		if (ev->data.addr.client == system_client)
134 			break; /* ignore myself */
135 		memset(&pinfo, 0, sizeof(pinfo));
136 		pinfo.addr = ev->data.addr;
137 		if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0)
138 			snd_seq_oss_midi_check_new_port(&pinfo);
139 		break;
140 
141 	case SNDRV_SEQ_EVENT_PORT_EXIT:
142 		if (ev->data.addr.client == system_client)
143 			break; /* ignore myself */
144 		snd_seq_oss_midi_check_exit_port(ev->data.addr.client,
145 						ev->data.addr.port);
146 		break;
147 	}
148 	return 0;
149 }
150 
151 
152 /*
153  * delete OSS sequencer client
154  */
155 int
156 snd_seq_oss_delete_client(void)
157 {
158 	cancel_work_sync(&async_lookup_work);
159 	if (system_client >= 0)
160 		snd_seq_delete_kernel_client(system_client);
161 
162 	snd_seq_oss_midi_clear_all();
163 
164 	return 0;
165 }
166 
167 
168 /*
169  * open sequencer device
170  */
171 int
172 snd_seq_oss_open(struct file *file, int level)
173 {
174 	int i, rc;
175 	struct seq_oss_devinfo *dp;
176 
177 	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
178 	if (!dp)
179 		return -ENOMEM;
180 
181 	dp->cseq = system_client;
182 	dp->port = -1;
183 	dp->queue = -1;
184 
185 	for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
186 		if (client_table[i] == NULL)
187 			break;
188 	}
189 
190 	dp->index = i;
191 	if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
192 		pr_debug("ALSA: seq_oss: too many applications\n");
193 		rc = -ENOMEM;
194 		goto _error;
195 	}
196 
197 	/* look up synth and midi devices */
198 	snd_seq_oss_synth_setup(dp);
199 	snd_seq_oss_midi_setup(dp);
200 
201 	if (dp->synth_opened == 0 && dp->max_mididev == 0) {
202 		/* pr_err("ALSA: seq_oss: no device found\n"); */
203 		rc = -ENODEV;
204 		goto _error;
205 	}
206 
207 	/* create port */
208 	rc = create_port(dp);
209 	if (rc < 0) {
210 		pr_err("ALSA: seq_oss: can't create port\n");
211 		goto _error;
212 	}
213 
214 	/* allocate queue */
215 	rc = alloc_seq_queue(dp);
216 	if (rc < 0)
217 		goto _error;
218 
219 	/* set address */
220 	dp->addr.client = dp->cseq;
221 	dp->addr.port = dp->port;
222 	/*dp->addr.queue = dp->queue;*/
223 	/*dp->addr.channel = 0;*/
224 
225 	dp->seq_mode = level;
226 
227 	/* set up file mode */
228 	dp->file_mode = translate_mode(file);
229 
230 	/* initialize read queue */
231 	if (is_read_mode(dp->file_mode)) {
232 		dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
233 		if (!dp->readq) {
234 			rc = -ENOMEM;
235 			goto _error;
236 		}
237 	}
238 
239 	/* initialize write queue */
240 	if (is_write_mode(dp->file_mode)) {
241 		dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
242 		if (!dp->writeq) {
243 			rc = -ENOMEM;
244 			goto _error;
245 		}
246 	}
247 
248 	/* initialize timer */
249 	dp->timer = snd_seq_oss_timer_new(dp);
250 	if (!dp->timer) {
251 		pr_err("ALSA: seq_oss: can't alloc timer\n");
252 		rc = -ENOMEM;
253 		goto _error;
254 	}
255 
256 	/* set private data pointer */
257 	file->private_data = dp;
258 
259 	/* set up for mode2 */
260 	if (level == SNDRV_SEQ_OSS_MODE_MUSIC)
261 		snd_seq_oss_synth_setup_midi(dp);
262 	else if (is_read_mode(dp->file_mode))
263 		snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ);
264 
265 	client_table[dp->index] = dp;
266 	num_clients++;
267 
268 	return 0;
269 
270  _error:
271 	snd_seq_oss_synth_cleanup(dp);
272 	snd_seq_oss_midi_cleanup(dp);
273 	delete_seq_queue(dp->queue);
274 	delete_port(dp);
275 
276 	return rc;
277 }
278 
279 /*
280  * translate file flags to private mode
281  */
282 static int
283 translate_mode(struct file *file)
284 {
285 	int file_mode = 0;
286 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
287 		file_mode |= SNDRV_SEQ_OSS_FILE_WRITE;
288 	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
289 		file_mode |= SNDRV_SEQ_OSS_FILE_READ;
290 	if (file->f_flags & O_NONBLOCK)
291 		file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK;
292 	return file_mode;
293 }
294 
295 
296 /*
297  * create sequencer port
298  */
299 static int
300 create_port(struct seq_oss_devinfo *dp)
301 {
302 	int rc;
303 	struct snd_seq_port_info port;
304 	struct snd_seq_port_callback callback;
305 
306 	memset(&port, 0, sizeof(port));
307 	port.addr.client = dp->cseq;
308 	sprintf(port.name, "Sequencer-%d", dp->index);
309 	port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */
310 	port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
311 	port.midi_channels = 128;
312 	port.synth_voices = 128;
313 
314 	memset(&callback, 0, sizeof(callback));
315 	callback.owner = THIS_MODULE;
316 	callback.private_data = dp;
317 	callback.event_input = snd_seq_oss_event_input;
318 	callback.private_free = free_devinfo;
319 	port.kernel = &callback;
320 
321 	rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
322 	if (rc < 0)
323 		return rc;
324 
325 	dp->port = port.addr.port;
326 
327 	return 0;
328 }
329 
330 /*
331  * delete ALSA port
332  */
333 static int
334 delete_port(struct seq_oss_devinfo *dp)
335 {
336 	if (dp->port < 0) {
337 		kfree(dp);
338 		return 0;
339 	}
340 
341 	return snd_seq_event_port_detach(dp->cseq, dp->port);
342 }
343 
344 /*
345  * allocate a queue
346  */
347 static int
348 alloc_seq_queue(struct seq_oss_devinfo *dp)
349 {
350 	struct snd_seq_queue_info qinfo;
351 	int rc;
352 
353 	memset(&qinfo, 0, sizeof(qinfo));
354 	qinfo.owner = system_client;
355 	qinfo.locked = 1;
356 	strcpy(qinfo.name, "OSS Sequencer Emulation");
357 	rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
358 	if (rc < 0)
359 		return rc;
360 	dp->queue = qinfo.queue;
361 	return 0;
362 }
363 
364 /*
365  * release queue
366  */
367 static int
368 delete_seq_queue(int queue)
369 {
370 	struct snd_seq_queue_info qinfo;
371 	int rc;
372 
373 	if (queue < 0)
374 		return 0;
375 	memset(&qinfo, 0, sizeof(qinfo));
376 	qinfo.queue = queue;
377 	rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
378 	if (rc < 0)
379 		pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
380 	return rc;
381 }
382 
383 
384 /*
385  * free device informations - private_free callback of port
386  */
387 static void
388 free_devinfo(void *private)
389 {
390 	struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
391 
392 	snd_seq_oss_timer_delete(dp->timer);
393 
394 	snd_seq_oss_writeq_delete(dp->writeq);
395 
396 	snd_seq_oss_readq_delete(dp->readq);
397 
398 	kfree(dp);
399 }
400 
401 
402 /*
403  * close sequencer device
404  */
405 void
406 snd_seq_oss_release(struct seq_oss_devinfo *dp)
407 {
408 	int queue;
409 
410 	client_table[dp->index] = NULL;
411 	num_clients--;
412 
413 	snd_seq_oss_reset(dp);
414 
415 	snd_seq_oss_synth_cleanup(dp);
416 	snd_seq_oss_midi_cleanup(dp);
417 
418 	/* clear slot */
419 	queue = dp->queue;
420 	if (dp->port >= 0)
421 		delete_port(dp);
422 	delete_seq_queue(queue);
423 }
424 
425 
426 /*
427  * reset sequencer devices
428  */
429 void
430 snd_seq_oss_reset(struct seq_oss_devinfo *dp)
431 {
432 	int i;
433 
434 	/* reset all synth devices */
435 	for (i = 0; i < dp->max_synthdev; i++)
436 		snd_seq_oss_synth_reset(dp, i);
437 
438 	/* reset all midi devices */
439 	if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) {
440 		for (i = 0; i < dp->max_mididev; i++)
441 			snd_seq_oss_midi_reset(dp, i);
442 	}
443 
444 	/* remove queues */
445 	if (dp->readq)
446 		snd_seq_oss_readq_clear(dp->readq);
447 	if (dp->writeq)
448 		snd_seq_oss_writeq_clear(dp->writeq);
449 
450 	/* reset timer */
451 	snd_seq_oss_timer_stop(dp->timer);
452 }
453 
454 #ifdef CONFIG_SND_PROC_FS
455 /*
456  * misc. functions for proc interface
457  */
458 char *
459 enabled_str(int bool)
460 {
461 	return bool ? "enabled" : "disabled";
462 }
463 
464 static const char *
465 filemode_str(int val)
466 {
467 	static const char * const str[] = {
468 		"none", "read", "write", "read/write",
469 	};
470 	return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];
471 }
472 
473 
474 /*
475  * proc interface
476  */
477 void
478 snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
479 {
480 	int i;
481 	struct seq_oss_devinfo *dp;
482 
483 	snd_iprintf(buf, "ALSA client number %d\n", system_client);
484 	snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
485 
486 	snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
487 	for (i = 0; i < num_clients; i++) {
488 		snd_iprintf(buf, "\nApplication %d: ", i);
489 		dp = client_table[i];
490 		if (!dp) {
491 			snd_iprintf(buf, "*empty*\n");
492 			continue;
493 		}
494 		snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
495 		snd_iprintf(buf, "  sequencer mode = %s : file open mode = %s\n",
496 			    (dp->seq_mode ? "music" : "synth"),
497 			    filemode_str(dp->file_mode));
498 		if (dp->seq_mode)
499 			snd_iprintf(buf, "  timer tempo = %d, timebase = %d\n",
500 				    dp->timer->oss_tempo, dp->timer->oss_timebase);
501 		snd_iprintf(buf, "  max queue length %d\n", maxqlen);
502 		if (is_read_mode(dp->file_mode) && dp->readq)
503 			snd_seq_oss_readq_info_read(dp->readq, buf);
504 	}
505 }
506 #endif /* CONFIG_SND_PROC_FS */
507