Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OSS compatible sequencer driver
0004  *
0005  * open/close and reset interface
0006  *
0007  * Copyright (C) 1998-1999 Takashi Iwai <tiwai@suse.de>
0008  */
0009 
0010 #include "seq_oss_device.h"
0011 #include "seq_oss_synth.h"
0012 #include "seq_oss_midi.h"
0013 #include "seq_oss_writeq.h"
0014 #include "seq_oss_readq.h"
0015 #include "seq_oss_timer.h"
0016 #include "seq_oss_event.h"
0017 #include <linux/init.h>
0018 #include <linux/export.h>
0019 #include <linux/moduleparam.h>
0020 #include <linux/slab.h>
0021 #include <linux/workqueue.h>
0022 
0023 /*
0024  * common variables
0025  */
0026 static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
0027 module_param(maxqlen, int, 0444);
0028 MODULE_PARM_DESC(maxqlen, "maximum queue length");
0029 
0030 static int system_client = -1; /* ALSA sequencer client number */
0031 static int system_port = -1;
0032 
0033 static int num_clients;
0034 static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
0035 
0036 
0037 /*
0038  * prototypes
0039  */
0040 static int receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop);
0041 static int translate_mode(struct file *file);
0042 static int create_port(struct seq_oss_devinfo *dp);
0043 static int delete_port(struct seq_oss_devinfo *dp);
0044 static int alloc_seq_queue(struct seq_oss_devinfo *dp);
0045 static int delete_seq_queue(int queue);
0046 static void free_devinfo(void *private);
0047 
0048 #define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
0049 
0050 
0051 /* call snd_seq_oss_midi_lookup_ports() asynchronously */
0052 static void async_call_lookup_ports(struct work_struct *work)
0053 {
0054     snd_seq_oss_midi_lookup_ports(system_client);
0055 }
0056 
0057 static DECLARE_WORK(async_lookup_work, async_call_lookup_ports);
0058 
0059 /*
0060  * create sequencer client for OSS sequencer
0061  */
0062 int __init
0063 snd_seq_oss_create_client(void)
0064 {
0065     int rc;
0066     struct snd_seq_port_info *port;
0067     struct snd_seq_port_callback port_callback;
0068 
0069     port = kzalloc(sizeof(*port), GFP_KERNEL);
0070     if (!port) {
0071         rc = -ENOMEM;
0072         goto __error;
0073     }
0074 
0075     /* create ALSA client */
0076     rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS,
0077                       "OSS sequencer");
0078     if (rc < 0)
0079         goto __error;
0080 
0081     system_client = rc;
0082 
0083     /* create announcement receiver port */
0084     strcpy(port->name, "Receiver");
0085     port->addr.client = system_client;
0086     port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
0087     port->type = 0;
0088 
0089     memset(&port_callback, 0, sizeof(port_callback));
0090     /* don't set port_callback.owner here. otherwise the module counter
0091      * is incremented and we can no longer release the module..
0092      */
0093     port_callback.event_input = receive_announce;
0094     port->kernel = &port_callback;
0095     
0096     if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) {
0097         struct snd_seq_port_subscribe subs;
0098 
0099         system_port = port->addr.port;
0100         memset(&subs, 0, sizeof(subs));
0101         subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
0102         subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
0103         subs.dest.client = system_client;
0104         subs.dest.port = system_port;
0105         call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
0106     }
0107     rc = 0;
0108 
0109     /* look up midi devices */
0110     schedule_work(&async_lookup_work);
0111 
0112  __error:
0113     kfree(port);
0114     return rc;
0115 }
0116 
0117 
0118 /*
0119  * receive annoucement from system port, and check the midi device
0120  */
0121 static int
0122 receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop)
0123 {
0124     struct snd_seq_port_info pinfo;
0125 
0126     if (atomic)
0127         return 0; /* it must not happen */
0128 
0129     switch (ev->type) {
0130     case SNDRV_SEQ_EVENT_PORT_START:
0131     case SNDRV_SEQ_EVENT_PORT_CHANGE:
0132         if (ev->data.addr.client == system_client)
0133             break; /* ignore myself */
0134         memset(&pinfo, 0, sizeof(pinfo));
0135         pinfo.addr = ev->data.addr;
0136         if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0)
0137             snd_seq_oss_midi_check_new_port(&pinfo);
0138         break;
0139 
0140     case SNDRV_SEQ_EVENT_PORT_EXIT:
0141         if (ev->data.addr.client == system_client)
0142             break; /* ignore myself */
0143         snd_seq_oss_midi_check_exit_port(ev->data.addr.client,
0144                         ev->data.addr.port);
0145         break;
0146     }
0147     return 0;
0148 }
0149 
0150 
0151 /*
0152  * delete OSS sequencer client
0153  */
0154 int
0155 snd_seq_oss_delete_client(void)
0156 {
0157     cancel_work_sync(&async_lookup_work);
0158     if (system_client >= 0)
0159         snd_seq_delete_kernel_client(system_client);
0160 
0161     snd_seq_oss_midi_clear_all();
0162 
0163     return 0;
0164 }
0165 
0166 
0167 /*
0168  * open sequencer device
0169  */
0170 int
0171 snd_seq_oss_open(struct file *file, int level)
0172 {
0173     int i, rc;
0174     struct seq_oss_devinfo *dp;
0175 
0176     dp = kzalloc(sizeof(*dp), GFP_KERNEL);
0177     if (!dp)
0178         return -ENOMEM;
0179 
0180     dp->cseq = system_client;
0181     dp->port = -1;
0182     dp->queue = -1;
0183 
0184     for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
0185         if (client_table[i] == NULL)
0186             break;
0187     }
0188 
0189     dp->index = i;
0190     if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
0191         pr_debug("ALSA: seq_oss: too many applications\n");
0192         rc = -ENOMEM;
0193         goto _error;
0194     }
0195 
0196     /* look up synth and midi devices */
0197     snd_seq_oss_synth_setup(dp);
0198     snd_seq_oss_midi_setup(dp);
0199 
0200     if (dp->synth_opened == 0 && dp->max_mididev == 0) {
0201         /* pr_err("ALSA: seq_oss: no device found\n"); */
0202         rc = -ENODEV;
0203         goto _error;
0204     }
0205 
0206     /* create port */
0207     rc = create_port(dp);
0208     if (rc < 0) {
0209         pr_err("ALSA: seq_oss: can't create port\n");
0210         goto _error;
0211     }
0212 
0213     /* allocate queue */
0214     rc = alloc_seq_queue(dp);
0215     if (rc < 0)
0216         goto _error;
0217 
0218     /* set address */
0219     dp->addr.client = dp->cseq;
0220     dp->addr.port = dp->port;
0221     /*dp->addr.queue = dp->queue;*/
0222     /*dp->addr.channel = 0;*/
0223 
0224     dp->seq_mode = level;
0225 
0226     /* set up file mode */
0227     dp->file_mode = translate_mode(file);
0228 
0229     /* initialize read queue */
0230     if (is_read_mode(dp->file_mode)) {
0231         dp->readq = snd_seq_oss_readq_new(dp, maxqlen);
0232         if (!dp->readq) {
0233             rc = -ENOMEM;
0234             goto _error;
0235         }
0236     }
0237 
0238     /* initialize write queue */
0239     if (is_write_mode(dp->file_mode)) {
0240         dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
0241         if (!dp->writeq) {
0242             rc = -ENOMEM;
0243             goto _error;
0244         }
0245     }
0246 
0247     /* initialize timer */
0248     dp->timer = snd_seq_oss_timer_new(dp);
0249     if (!dp->timer) {
0250         pr_err("ALSA: seq_oss: can't alloc timer\n");
0251         rc = -ENOMEM;
0252         goto _error;
0253     }
0254 
0255     /* set private data pointer */
0256     file->private_data = dp;
0257 
0258     /* set up for mode2 */
0259     if (level == SNDRV_SEQ_OSS_MODE_MUSIC)
0260         snd_seq_oss_synth_setup_midi(dp);
0261     else if (is_read_mode(dp->file_mode))
0262         snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ);
0263 
0264     client_table[dp->index] = dp;
0265     num_clients++;
0266 
0267     return 0;
0268 
0269  _error:
0270     snd_seq_oss_synth_cleanup(dp);
0271     snd_seq_oss_midi_cleanup(dp);
0272     delete_seq_queue(dp->queue);
0273     delete_port(dp);
0274 
0275     return rc;
0276 }
0277 
0278 /*
0279  * translate file flags to private mode
0280  */
0281 static int
0282 translate_mode(struct file *file)
0283 {
0284     int file_mode = 0;
0285     if ((file->f_flags & O_ACCMODE) != O_RDONLY)
0286         file_mode |= SNDRV_SEQ_OSS_FILE_WRITE;
0287     if ((file->f_flags & O_ACCMODE) != O_WRONLY)
0288         file_mode |= SNDRV_SEQ_OSS_FILE_READ;
0289     if (file->f_flags & O_NONBLOCK)
0290         file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK;
0291     return file_mode;
0292 }
0293 
0294 
0295 /*
0296  * create sequencer port
0297  */
0298 static int
0299 create_port(struct seq_oss_devinfo *dp)
0300 {
0301     int rc;
0302     struct snd_seq_port_info port;
0303     struct snd_seq_port_callback callback;
0304 
0305     memset(&port, 0, sizeof(port));
0306     port.addr.client = dp->cseq;
0307     sprintf(port.name, "Sequencer-%d", dp->index);
0308     port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */
0309     port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
0310     port.midi_channels = 128;
0311     port.synth_voices = 128;
0312 
0313     memset(&callback, 0, sizeof(callback));
0314     callback.owner = THIS_MODULE;
0315     callback.private_data = dp;
0316     callback.event_input = snd_seq_oss_event_input;
0317     callback.private_free = free_devinfo;
0318     port.kernel = &callback;
0319 
0320     rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
0321     if (rc < 0)
0322         return rc;
0323 
0324     dp->port = port.addr.port;
0325 
0326     return 0;
0327 }
0328 
0329 /*
0330  * delete ALSA port
0331  */
0332 static int
0333 delete_port(struct seq_oss_devinfo *dp)
0334 {
0335     if (dp->port < 0) {
0336         kfree(dp);
0337         return 0;
0338     }
0339 
0340     return snd_seq_event_port_detach(dp->cseq, dp->port);
0341 }
0342 
0343 /*
0344  * allocate a queue
0345  */
0346 static int
0347 alloc_seq_queue(struct seq_oss_devinfo *dp)
0348 {
0349     struct snd_seq_queue_info qinfo;
0350     int rc;
0351 
0352     memset(&qinfo, 0, sizeof(qinfo));
0353     qinfo.owner = system_client;
0354     qinfo.locked = 1;
0355     strcpy(qinfo.name, "OSS Sequencer Emulation");
0356     rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
0357     if (rc < 0)
0358         return rc;
0359     dp->queue = qinfo.queue;
0360     return 0;
0361 }
0362 
0363 /*
0364  * release queue
0365  */
0366 static int
0367 delete_seq_queue(int queue)
0368 {
0369     struct snd_seq_queue_info qinfo;
0370     int rc;
0371 
0372     if (queue < 0)
0373         return 0;
0374     memset(&qinfo, 0, sizeof(qinfo));
0375     qinfo.queue = queue;
0376     rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
0377     if (rc < 0)
0378         pr_err("ALSA: seq_oss: unable to delete queue %d (%d)\n", queue, rc);
0379     return rc;
0380 }
0381 
0382 
0383 /*
0384  * free device informations - private_free callback of port
0385  */
0386 static void
0387 free_devinfo(void *private)
0388 {
0389     struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
0390 
0391     snd_seq_oss_timer_delete(dp->timer);
0392         
0393     snd_seq_oss_writeq_delete(dp->writeq);
0394 
0395     snd_seq_oss_readq_delete(dp->readq);
0396     
0397     kfree(dp);
0398 }
0399 
0400 
0401 /*
0402  * close sequencer device
0403  */
0404 void
0405 snd_seq_oss_release(struct seq_oss_devinfo *dp)
0406 {
0407     int queue;
0408 
0409     client_table[dp->index] = NULL;
0410     num_clients--;
0411 
0412     snd_seq_oss_reset(dp);
0413 
0414     snd_seq_oss_synth_cleanup(dp);
0415     snd_seq_oss_midi_cleanup(dp);
0416 
0417     /* clear slot */
0418     queue = dp->queue;
0419     if (dp->port >= 0)
0420         delete_port(dp);
0421     delete_seq_queue(queue);
0422 }
0423 
0424 
0425 /*
0426  * reset sequencer devices
0427  */
0428 void
0429 snd_seq_oss_reset(struct seq_oss_devinfo *dp)
0430 {
0431     int i;
0432 
0433     /* reset all synth devices */
0434     for (i = 0; i < dp->max_synthdev; i++)
0435         snd_seq_oss_synth_reset(dp, i);
0436 
0437     /* reset all midi devices */
0438     if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) {
0439         for (i = 0; i < dp->max_mididev; i++)
0440             snd_seq_oss_midi_reset(dp, i);
0441     }
0442 
0443     /* remove queues */
0444     if (dp->readq)
0445         snd_seq_oss_readq_clear(dp->readq);
0446     if (dp->writeq)
0447         snd_seq_oss_writeq_clear(dp->writeq);
0448 
0449     /* reset timer */
0450     snd_seq_oss_timer_stop(dp->timer);
0451 }
0452 
0453 #ifdef CONFIG_SND_PROC_FS
0454 /*
0455  * misc. functions for proc interface
0456  */
0457 char *
0458 enabled_str(int bool)
0459 {
0460     return bool ? "enabled" : "disabled";
0461 }
0462 
0463 static const char *
0464 filemode_str(int val)
0465 {
0466     static const char * const str[] = {
0467         "none", "read", "write", "read/write",
0468     };
0469     return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];
0470 }
0471 
0472 
0473 /*
0474  * proc interface
0475  */
0476 void
0477 snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
0478 {
0479     int i;
0480     struct seq_oss_devinfo *dp;
0481 
0482     snd_iprintf(buf, "ALSA client number %d\n", system_client);
0483     snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
0484 
0485     snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
0486     for (i = 0; i < num_clients; i++) {
0487         snd_iprintf(buf, "\nApplication %d: ", i);
0488         dp = client_table[i];
0489         if (!dp) {
0490             snd_iprintf(buf, "*empty*\n");
0491             continue;
0492         }
0493         snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
0494         snd_iprintf(buf, "  sequencer mode = %s : file open mode = %s\n",
0495                 (dp->seq_mode ? "music" : "synth"),
0496                 filemode_str(dp->file_mode));
0497         if (dp->seq_mode)
0498             snd_iprintf(buf, "  timer tempo = %d, timebase = %d\n",
0499                     dp->timer->oss_tempo, dp->timer->oss_timebase);
0500         snd_iprintf(buf, "  max queue length %d\n", maxqlen);
0501         if (is_read_mode(dp->file_mode) && dp->readq)
0502             snd_seq_oss_readq_info_read(dp->readq, buf);
0503     }
0504 }
0505 #endif /* CONFIG_SND_PROC_FS */