^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * OPL4 sequencer functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Redistribution and use in source and binary forms, with or without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * modification, are permitted provided that the following conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * are met:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 1. Redistributions of source code must retain the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * notice, this list of conditions, and the following disclaimer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * without modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * 2. The name of the author may not be used to endorse or promote products
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * derived from this software without specific prior written permission.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Alternatively, this software may be distributed and/or modified under the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * terms of the GNU General Public License as published by the Free Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Foundation; either version 2 of the License, or (at your option) any later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * SUCH DAMAGE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include "opl4_local.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) MODULE_DESCRIPTION("OPL4 wavetable synth driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) MODULE_LICENSE("Dual BSD/GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int volume_boost = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) module_param(volume_boost, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int snd_opl4_seq_use_inc(struct snd_opl4 *opl4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!try_module_get(opl4->card->module))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static void snd_opl4_seq_use_dec(struct snd_opl4 *opl4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) module_put(opl4->card->module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct snd_opl4 *opl4 = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) mutex_lock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (opl4->used) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) mutex_unlock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) opl4->used++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) err = snd_opl4_seq_use_inc(opl4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) mutex_unlock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mutex_unlock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) snd_opl4_synth_reset(opl4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct snd_opl4 *opl4 = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) snd_opl4_synth_shutdown(opl4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) mutex_lock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) opl4->used--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) mutex_unlock(&opl4->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) snd_opl4_seq_use_dec(opl4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static const struct snd_midi_op opl4_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .note_on = snd_opl4_note_on,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .note_off = snd_opl4_note_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .note_terminate = snd_opl4_terminate_note,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .control = snd_opl4_control,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .sysex = snd_opl4_sysex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static int snd_opl4_seq_event_input(struct snd_seq_event *ev, int direct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) void *private_data, int atomic, int hop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct snd_opl4 *opl4 = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) snd_midi_process_event(&opl4_ops, ev, opl4->chset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static void snd_opl4_seq_free_port(void *private_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct snd_opl4 *opl4 = private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) snd_midi_channel_free_set(opl4->chset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static int snd_opl4_seq_probe(struct device *_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct snd_seq_device *dev = to_seq_dev(_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct snd_opl4 *opl4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct snd_seq_port_callback pcallbacks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!opl4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (snd_yrw801_detect(opl4) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) opl4->chset = snd_midi_channel_alloc_set(16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!opl4->chset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) opl4->chset->private_data = opl4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* allocate new client */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) "OPL4 Wavetable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (client < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) snd_midi_channel_free_set(opl4->chset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) opl4->seq_client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) opl4->chset->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* create new port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) memset(&pcallbacks, 0, sizeof(pcallbacks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) pcallbacks.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) pcallbacks.use = snd_opl4_seq_use;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) pcallbacks.unuse = snd_opl4_seq_unuse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pcallbacks.event_input = snd_opl4_seq_event_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) pcallbacks.private_free = snd_opl4_seq_free_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) pcallbacks.private_data = opl4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) SNDRV_SEQ_PORT_CAP_WRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) SNDRV_SEQ_PORT_TYPE_MIDI_GM |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) SNDRV_SEQ_PORT_TYPE_HARDWARE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 16, 24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) "OPL4 Wavetable Port");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (opl4->chset->port < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int err = opl4->chset->port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) snd_midi_channel_free_set(opl4->chset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) snd_seq_delete_kernel_client(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) opl4->seq_client = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int snd_opl4_seq_remove(struct device *_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct snd_seq_device *dev = to_seq_dev(_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct snd_opl4 *opl4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (!opl4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (opl4->seq_client >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) snd_seq_delete_kernel_client(opl4->seq_client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) opl4->seq_client = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static struct snd_seq_driver opl4_seq_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .name = KBUILD_MODNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .probe = snd_opl4_seq_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .remove = snd_opl4_seq_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .id = SNDRV_SEQ_DEV_ID_OPL4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .argsize = sizeof(struct snd_opl4 *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) module_snd_seq_driver(opl4_seq_driver);