Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * OPL4 sequencer functions
0003  *
0004  * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
0005  * All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions, and the following disclaimer,
0012  *    without modification.
0013  * 2. The name of the author may not be used to endorse or promote products
0014  *    derived from this software without specific prior written permission.
0015  *
0016  * Alternatively, this software may be distributed and/or modified under the
0017  * terms of the GNU General Public License as published by the Free Software
0018  * Foundation; either version 2 of the License, or (at your option) any later
0019  * version.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
0025  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0031  * SUCH DAMAGE.
0032  */
0033 
0034 #include "opl4_local.h"
0035 #include <linux/init.h>
0036 #include <linux/moduleparam.h>
0037 #include <linux/module.h>
0038 #include <sound/initval.h>
0039 
0040 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
0041 MODULE_DESCRIPTION("OPL4 wavetable synth driver");
0042 MODULE_LICENSE("Dual BSD/GPL");
0043 
0044 int volume_boost = 8;
0045 
0046 module_param(volume_boost, int, 0644);
0047 MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds.");
0048 
0049 static int snd_opl4_seq_use_inc(struct snd_opl4 *opl4)
0050 {
0051     if (!try_module_get(opl4->card->module))
0052         return -EFAULT;
0053     return 0;
0054 }
0055 
0056 static void snd_opl4_seq_use_dec(struct snd_opl4 *opl4)
0057 {
0058     module_put(opl4->card->module);
0059 }
0060 
0061 static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *info)
0062 {
0063     struct snd_opl4 *opl4 = private_data;
0064     int err;
0065 
0066     mutex_lock(&opl4->access_mutex);
0067 
0068     if (opl4->used) {
0069         mutex_unlock(&opl4->access_mutex);
0070         return -EBUSY;
0071     }
0072     opl4->used++;
0073 
0074     if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
0075         err = snd_opl4_seq_use_inc(opl4);
0076         if (err < 0) {
0077             mutex_unlock(&opl4->access_mutex);
0078             return err;
0079         }
0080     }
0081 
0082     mutex_unlock(&opl4->access_mutex);
0083 
0084     snd_opl4_synth_reset(opl4);
0085     return 0;
0086 }
0087 
0088 static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe *info)
0089 {
0090     struct snd_opl4 *opl4 = private_data;
0091 
0092     snd_opl4_synth_shutdown(opl4);
0093 
0094     mutex_lock(&opl4->access_mutex);
0095     opl4->used--;
0096     mutex_unlock(&opl4->access_mutex);
0097 
0098     if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
0099         snd_opl4_seq_use_dec(opl4);
0100     return 0;
0101 }
0102 
0103 static const struct snd_midi_op opl4_ops = {
0104     .note_on =      snd_opl4_note_on,
0105     .note_off =     snd_opl4_note_off,
0106     .note_terminate =   snd_opl4_terminate_note,
0107     .control =      snd_opl4_control,
0108     .sysex =        snd_opl4_sysex,
0109 };
0110 
0111 static int snd_opl4_seq_event_input(struct snd_seq_event *ev, int direct,
0112                     void *private_data, int atomic, int hop)
0113 {
0114     struct snd_opl4 *opl4 = private_data;
0115 
0116     snd_midi_process_event(&opl4_ops, ev, opl4->chset);
0117     return 0;
0118 }
0119 
0120 static void snd_opl4_seq_free_port(void *private_data)
0121 {
0122     struct snd_opl4 *opl4 = private_data;
0123 
0124     snd_midi_channel_free_set(opl4->chset);
0125 }
0126 
0127 static int snd_opl4_seq_probe(struct device *_dev)
0128 {
0129     struct snd_seq_device *dev = to_seq_dev(_dev);
0130     struct snd_opl4 *opl4;
0131     int client;
0132     struct snd_seq_port_callback pcallbacks;
0133 
0134     opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
0135     if (!opl4)
0136         return -EINVAL;
0137 
0138     if (snd_yrw801_detect(opl4) < 0)
0139         return -ENODEV;
0140 
0141     opl4->chset = snd_midi_channel_alloc_set(16);
0142     if (!opl4->chset)
0143         return -ENOMEM;
0144     opl4->chset->private_data = opl4;
0145 
0146     /* allocate new client */
0147     client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
0148                           "OPL4 Wavetable");
0149     if (client < 0) {
0150         snd_midi_channel_free_set(opl4->chset);
0151         return client;
0152     }
0153     opl4->seq_client = client;
0154     opl4->chset->client = client;
0155 
0156     /* create new port */
0157     memset(&pcallbacks, 0, sizeof(pcallbacks));
0158     pcallbacks.owner = THIS_MODULE;
0159     pcallbacks.use = snd_opl4_seq_use;
0160     pcallbacks.unuse = snd_opl4_seq_unuse;
0161     pcallbacks.event_input = snd_opl4_seq_event_input;
0162     pcallbacks.private_free = snd_opl4_seq_free_port;
0163     pcallbacks.private_data = opl4;
0164 
0165     opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
0166                               SNDRV_SEQ_PORT_CAP_WRITE |
0167                               SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
0168                               SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
0169                               SNDRV_SEQ_PORT_TYPE_MIDI_GM |
0170                               SNDRV_SEQ_PORT_TYPE_HARDWARE |
0171                               SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
0172                               16, 24,
0173                               "OPL4 Wavetable Port");
0174     if (opl4->chset->port < 0) {
0175         int err = opl4->chset->port;
0176         snd_midi_channel_free_set(opl4->chset);
0177         snd_seq_delete_kernel_client(client);
0178         opl4->seq_client = -1;
0179         return err;
0180     }
0181     return 0;
0182 }
0183 
0184 static int snd_opl4_seq_remove(struct device *_dev)
0185 {
0186     struct snd_seq_device *dev = to_seq_dev(_dev);
0187     struct snd_opl4 *opl4;
0188 
0189     opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
0190     if (!opl4)
0191         return -EINVAL;
0192 
0193     if (opl4->seq_client >= 0) {
0194         snd_seq_delete_kernel_client(opl4->seq_client);
0195         opl4->seq_client = -1;
0196     }
0197     return 0;
0198 }
0199 
0200 static struct snd_seq_driver opl4_seq_driver = {
0201     .driver = {
0202         .name = KBUILD_MODNAME,
0203         .probe = snd_opl4_seq_probe,
0204         .remove = snd_opl4_seq_remove,
0205     },
0206     .id = SNDRV_SEQ_DEV_ID_OPL4,
0207     .argsize = sizeof(struct snd_opl4 *),
0208 };
0209 
0210 module_snd_seq_driver(opl4_seq_driver);