xref: /linux/sound/core/seq/oss/seq_oss_init.c (revision f86fd32d)
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 	call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
98 	if ((system_port = port->addr.port) >= 0) {
99 		struct snd_seq_port_subscribe subs;
100 
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 	if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0)
358 		return rc;
359 	dp->queue = qinfo.queue;
360 	return 0;
361 }
362 
363 /*
364  * release queue
365  */
366 static int
367 delete_seq_queue(int queue)
368 {
369 	struct snd_seq_queue_info qinfo;
370 	int rc;
371 
372 	if (queue < 0)
373 		return 0;
374 	memset(&qinfo, 0, sizeof(qinfo));
375 	qinfo.queue = queue;
376 	rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
377 	if (rc < 0)
378 		pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
379 	return rc;
380 }
381 
382 
383 /*
384  * free device informations - private_free callback of port
385  */
386 static void
387 free_devinfo(void *private)
388 {
389 	struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
390 
391 	snd_seq_oss_timer_delete(dp->timer);
392 
393 	snd_seq_oss_writeq_delete(dp->writeq);
394 
395 	snd_seq_oss_readq_delete(dp->readq);
396 
397 	kfree(dp);
398 }
399 
400 
401 /*
402  * close sequencer device
403  */
404 void
405 snd_seq_oss_release(struct seq_oss_devinfo *dp)
406 {
407 	int queue;
408 
409 	client_table[dp->index] = NULL;
410 	num_clients--;
411 
412 	snd_seq_oss_reset(dp);
413 
414 	snd_seq_oss_synth_cleanup(dp);
415 	snd_seq_oss_midi_cleanup(dp);
416 
417 	/* clear slot */
418 	queue = dp->queue;
419 	if (dp->port >= 0)
420 		delete_port(dp);
421 	delete_seq_queue(queue);
422 }
423 
424 
425 /*
426  * reset sequencer devices
427  */
428 void
429 snd_seq_oss_reset(struct seq_oss_devinfo *dp)
430 {
431 	int i;
432 
433 	/* reset all synth devices */
434 	for (i = 0; i < dp->max_synthdev; i++)
435 		snd_seq_oss_synth_reset(dp, i);
436 
437 	/* reset all midi devices */
438 	if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) {
439 		for (i = 0; i < dp->max_mididev; i++)
440 			snd_seq_oss_midi_reset(dp, i);
441 	}
442 
443 	/* remove queues */
444 	if (dp->readq)
445 		snd_seq_oss_readq_clear(dp->readq);
446 	if (dp->writeq)
447 		snd_seq_oss_writeq_clear(dp->writeq);
448 
449 	/* reset timer */
450 	snd_seq_oss_timer_stop(dp->timer);
451 }
452 
453 #ifdef CONFIG_SND_PROC_FS
454 /*
455  * misc. functions for proc interface
456  */
457 char *
458 enabled_str(int bool)
459 {
460 	return bool ? "enabled" : "disabled";
461 }
462 
463 static const char *
464 filemode_str(int val)
465 {
466 	static const char * const str[] = {
467 		"none", "read", "write", "read/write",
468 	};
469 	return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];
470 }
471 
472 
473 /*
474  * proc interface
475  */
476 void
477 snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
478 {
479 	int i;
480 	struct seq_oss_devinfo *dp;
481 
482 	snd_iprintf(buf, "ALSA client number %d\n", system_client);
483 	snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
484 
485 	snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
486 	for (i = 0; i < num_clients; i++) {
487 		snd_iprintf(buf, "\nApplication %d: ", i);
488 		if ((dp = client_table[i]) == NULL) {
489 			snd_iprintf(buf, "*empty*\n");
490 			continue;
491 		}
492 		snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
493 		snd_iprintf(buf, "  sequencer mode = %s : file open mode = %s\n",
494 			    (dp->seq_mode ? "music" : "synth"),
495 			    filemode_str(dp->file_mode));
496 		if (dp->seq_mode)
497 			snd_iprintf(buf, "  timer tempo = %d, timebase = %d\n",
498 				    dp->timer->oss_tempo, dp->timer->oss_timebase);
499 		snd_iprintf(buf, "  max queue length %d\n", maxqlen);
500 		if (is_read_mode(dp->file_mode) && dp->readq)
501 			snd_seq_oss_readq_info_read(dp->readq, buf);
502 	}
503 }
504 #endif /* CONFIG_SND_PROC_FS */
505