ALSA: seq: More constifications
[muen/linux.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 = 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 */