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