GNU Linux-libre 6.1.91-gnu
[releases.git] / sound / core / seq / oss / seq_oss_init.c
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 = kzalloc(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 announcement receiver port */
84         strcpy(port->name, "Receiver");
85         port->addr.client = system_client;
86         port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
87         port->type = 0;
88
89         memset(&port_callback, 0, sizeof(port_callback));
90         /* don't set port_callback.owner here. otherwise the module counter
91          * is incremented and we can no longer release the module..
92          */
93         port_callback.event_input = receive_announce;
94         port->kernel = &port_callback;
95         
96         if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) {
97                 struct snd_seq_port_subscribe subs;
98
99                 system_port = port->addr.port;
100                 memset(&subs, 0, sizeof(subs));
101                 subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
102                 subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
103                 subs.dest.client = system_client;
104                 subs.dest.port = system_port;
105                 call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
106         }
107         rc = 0;
108
109         /* look up midi devices */
110         schedule_work(&async_lookup_work);
111
112  __error:
113         kfree(port);
114         return rc;
115 }
116
117
118 /*
119  * receive annoucement from system port, and check the midi device
120  */
121 static int
122 receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop)
123 {
124         struct snd_seq_port_info pinfo;
125
126         if (atomic)
127                 return 0; /* it must not happen */
128
129         switch (ev->type) {
130         case SNDRV_SEQ_EVENT_PORT_START:
131         case SNDRV_SEQ_EVENT_PORT_CHANGE:
132                 if (ev->data.addr.client == system_client)
133                         break; /* ignore myself */
134                 memset(&pinfo, 0, sizeof(pinfo));
135                 pinfo.addr = ev->data.addr;
136                 if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0)
137                         snd_seq_oss_midi_check_new_port(&pinfo);
138                 break;
139
140         case SNDRV_SEQ_EVENT_PORT_EXIT:
141                 if (ev->data.addr.client == system_client)
142                         break; /* ignore myself */
143                 snd_seq_oss_midi_check_exit_port(ev->data.addr.client,
144                                                 ev->data.addr.port);
145                 break;
146         }
147         return 0;
148 }
149
150
151 /*
152  * delete OSS sequencer client
153  */
154 int
155 snd_seq_oss_delete_client(void)
156 {
157         cancel_work_sync(&async_lookup_work);
158         if (system_client >= 0)
159                 snd_seq_delete_kernel_client(system_client);
160
161         snd_seq_oss_midi_clear_all();
162
163         return 0;
164 }
165
166
167 /*
168  * open sequencer device
169  */
170 int
171 snd_seq_oss_open(struct file *file, int level)
172 {
173         int i, rc;
174         struct seq_oss_devinfo *dp;
175
176         dp = kzalloc(sizeof(*dp), GFP_KERNEL);
177         if (!dp)
178                 return -ENOMEM;
179
180         dp->cseq = system_client;
181         dp->port = -1;
182         dp->queue = -1;
183
184         for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
185                 if (client_table[i] == NULL)
186                         break;
187         }
188
189         dp->index = i;
190         if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
191                 pr_debug("ALSA: seq_oss: too many applications\n");
192                 rc = -ENOMEM;
193                 goto _error;
194         }
195
196         /* look up synth and midi devices */
197         snd_seq_oss_synth_setup(dp);
198         snd_seq_oss_midi_setup(dp);
199
200         if (dp->synth_opened == 0 && dp->max_mididev == 0) {
201                 /* pr_err("ALSA: seq_oss: no device found\n"); */
202                 rc = -ENODEV;
203                 goto _error;
204         }
205
206         /* create port */
207         rc = create_port(dp);
208         if (rc < 0) {
209                 pr_err("ALSA: seq_oss: can't create port\n");
210                 goto _error;
211         }
212
213         /* allocate queue */
214         rc = alloc_seq_queue(dp);
215         if (rc < 0)
216                 goto _error;
217
218         /* set address */
219         dp->addr.client = dp->cseq;
220         dp->addr.port = dp->port;
221         /*dp->addr.queue = dp->queue;*/
222         /*dp->addr.channel = 0;*/
223
224         dp->seq_mode = level;
225
226         /* set up file mode */
227         dp->file_mode = translate_mode(file);
228
229         /* initialize read queue */
230         if (is_read_mode(dp->file_mode)) {
231                 dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
232                 if (!dp->readq) {
233                         rc = -ENOMEM;
234                         goto _error;
235                 }
236         }
237
238         /* initialize write queue */
239         if (is_write_mode(dp->file_mode)) {
240                 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
241                 if (!dp->writeq) {
242                         rc = -ENOMEM;
243                         goto _error;
244                 }
245         }
246
247         /* initialize timer */
248         dp->timer = snd_seq_oss_timer_new(dp);
249         if (!dp->timer) {
250                 pr_err("ALSA: seq_oss: can't alloc timer\n");
251                 rc = -ENOMEM;
252                 goto _error;
253         }
254
255         /* set private data pointer */
256         file->private_data = dp;
257
258         /* set up for mode2 */
259         if (level == SNDRV_SEQ_OSS_MODE_MUSIC)
260                 snd_seq_oss_synth_setup_midi(dp);
261         else if (is_read_mode(dp->file_mode))
262                 snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ);
263
264         client_table[dp->index] = dp;
265         num_clients++;
266
267         return 0;
268
269  _error:
270         snd_seq_oss_synth_cleanup(dp);
271         snd_seq_oss_midi_cleanup(dp);
272         delete_seq_queue(dp->queue);
273         delete_port(dp);
274
275         return rc;
276 }
277
278 /*
279  * translate file flags to private mode
280  */
281 static int
282 translate_mode(struct file *file)
283 {
284         int file_mode = 0;
285         if ((file->f_flags & O_ACCMODE) != O_RDONLY)
286                 file_mode |= SNDRV_SEQ_OSS_FILE_WRITE;
287         if ((file->f_flags & O_ACCMODE) != O_WRONLY)
288                 file_mode |= SNDRV_SEQ_OSS_FILE_READ;
289         if (file->f_flags & O_NONBLOCK)
290                 file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK;
291         return file_mode;
292 }
293
294
295 /*
296  * create sequencer port
297  */
298 static int
299 create_port(struct seq_oss_devinfo *dp)
300 {
301         int rc;
302         struct snd_seq_port_info port;
303         struct snd_seq_port_callback callback;
304
305         memset(&port, 0, sizeof(port));
306         port.addr.client = dp->cseq;
307         sprintf(port.name, "Sequencer-%d", dp->index);
308         port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */
309         port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
310         port.midi_channels = 128;
311         port.synth_voices = 128;
312
313         memset(&callback, 0, sizeof(callback));
314         callback.owner = THIS_MODULE;
315         callback.private_data = dp;
316         callback.event_input = snd_seq_oss_event_input;
317         callback.private_free = free_devinfo;
318         port.kernel = &callback;
319
320         rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
321         if (rc < 0)
322                 return rc;
323
324         dp->port = port.addr.port;
325
326         return 0;
327 }
328
329 /*
330  * delete ALSA port
331  */
332 static int
333 delete_port(struct seq_oss_devinfo *dp)
334 {
335         if (dp->port < 0) {
336                 kfree(dp);
337                 return 0;
338         }
339
340         return snd_seq_event_port_detach(dp->cseq, dp->port);
341 }
342
343 /*
344  * allocate a queue
345  */
346 static int
347 alloc_seq_queue(struct seq_oss_devinfo *dp)
348 {
349         struct snd_seq_queue_info qinfo;
350         int rc;
351
352         memset(&qinfo, 0, sizeof(qinfo));
353         qinfo.owner = system_client;
354         qinfo.locked = 1;
355         strcpy(qinfo.name, "OSS Sequencer Emulation");
356         rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
357         if (rc < 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                 dp = client_table[i];
489                 if (!dp) {
490                         snd_iprintf(buf, "*empty*\n");
491                         continue;
492                 }
493                 snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
494                 snd_iprintf(buf, "  sequencer mode = %s : file open mode = %s\n",
495                             (dp->seq_mode ? "music" : "synth"),
496                             filemode_str(dp->file_mode));
497                 if (dp->seq_mode)
498                         snd_iprintf(buf, "  timer tempo = %d, timebase = %d\n",
499                                     dp->timer->oss_tempo, dp->timer->oss_timebase);
500                 snd_iprintf(buf, "  max queue length %d\n", maxqlen);
501                 if (is_read_mode(dp->file_mode) && dp->readq)
502                         snd_seq_oss_readq_info_read(dp->readq, buf);
503         }
504 }
505 #endif /* CONFIG_SND_PROC_FS */