1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Uros Bizjak <uros@kss-loka.si> 4 * 5 * Midi Sequencer interface routines for OPL2/OPL3/OPL4 FM 6 * 7 * OPL2/3 FM instrument loader: 8 * alsa-tools/seq/sbiload/ 9 */ 10 11 #include "opl3_voice.h" 12 #include <linux/init.h> 13 #include <linux/moduleparam.h> 14 #include <linux/module.h> 15 #include <sound/initval.h> 16 17 MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>"); 18 MODULE_LICENSE("GPL"); 19 MODULE_DESCRIPTION("ALSA driver for OPL3 FM synth"); 20 21 bool use_internal_drums = 0; 22 module_param(use_internal_drums, bool, 0444); 23 MODULE_PARM_DESC(use_internal_drums, "Enable internal OPL2/3 drums."); 24 25 int snd_opl3_synth_use_inc(struct snd_opl3 * opl3) 26 { 27 if (!try_module_get(opl3->card->module)) 28 return -EFAULT; 29 return 0; 30 31 } 32 33 void snd_opl3_synth_use_dec(struct snd_opl3 * opl3) 34 { 35 module_put(opl3->card->module); 36 } 37 38 int snd_opl3_synth_setup(struct snd_opl3 * opl3) 39 { 40 int idx; 41 struct snd_hwdep *hwdep = opl3->hwdep; 42 43 scoped_guard(mutex, &hwdep->open_mutex) { 44 if (hwdep->used) 45 return -EBUSY; 46 hwdep->used++; 47 } 48 49 snd_opl3_reset(opl3); 50 51 for (idx = 0; idx < MAX_OPL3_VOICES; idx++) { 52 opl3->voices[idx].state = SNDRV_OPL3_ST_OFF; 53 opl3->voices[idx].time = 0; 54 opl3->voices[idx].keyon_reg = 0x00; 55 } 56 opl3->use_time = 0; 57 opl3->connection_reg = 0x00; 58 if (opl3->hardware >= OPL3_HW_OPL3) { 59 /* Clear 4-op connections */ 60 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT, 61 opl3->connection_reg); 62 opl3->max_voices = MAX_OPL3_VOICES; 63 } 64 return 0; 65 } 66 67 void snd_opl3_synth_cleanup(struct snd_opl3 * opl3) 68 { 69 struct snd_hwdep *hwdep; 70 71 /* Stop system timer */ 72 scoped_guard(spinlock_irq, &opl3->sys_timer_lock) { 73 if (opl3->sys_timer_status) { 74 timer_delete(&opl3->tlist); 75 opl3->sys_timer_status = 0; 76 } 77 } 78 79 snd_opl3_reset(opl3); 80 hwdep = opl3->hwdep; 81 scoped_guard(mutex, &hwdep->open_mutex) { 82 hwdep->used--; 83 } 84 wake_up(&hwdep->open_wait); 85 } 86 87 static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info) 88 { 89 struct snd_opl3 *opl3 = private_data; 90 int err; 91 92 err = snd_opl3_synth_setup(opl3); 93 if (err < 0) 94 return err; 95 96 if (use_internal_drums) { 97 /* Percussion mode */ 98 opl3->voices[6].state = opl3->voices[7].state = 99 opl3->voices[8].state = SNDRV_OPL3_ST_NOT_AVAIL; 100 snd_opl3_load_drums(opl3); 101 opl3->drum_reg = OPL3_PERCUSSION_ENABLE; 102 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, opl3->drum_reg); 103 } else { 104 opl3->drum_reg = 0x00; 105 } 106 107 if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) { 108 err = snd_opl3_synth_use_inc(opl3); 109 if (err < 0) 110 return err; 111 } 112 opl3->synth_mode = SNDRV_OPL3_MODE_SEQ; 113 return 0; 114 } 115 116 static int snd_opl3_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info) 117 { 118 struct snd_opl3 *opl3 = private_data; 119 120 snd_opl3_synth_cleanup(opl3); 121 122 if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) 123 snd_opl3_synth_use_dec(opl3); 124 return 0; 125 } 126 127 /* 128 * MIDI emulation operators 129 */ 130 const struct snd_midi_op opl3_ops = { 131 .note_on = snd_opl3_note_on, 132 .note_off = snd_opl3_note_off, 133 .key_press = snd_opl3_key_press, 134 .note_terminate = snd_opl3_terminate_note, 135 .control = snd_opl3_control, 136 .nrpn = snd_opl3_nrpn, 137 .sysex = snd_opl3_sysex, 138 }; 139 140 static int snd_opl3_synth_event_input(struct snd_seq_event * ev, int direct, 141 void *private_data, int atomic, int hop) 142 { 143 struct snd_opl3 *opl3 = private_data; 144 145 snd_midi_process_event(&opl3_ops, ev, opl3->chset); 146 return 0; 147 } 148 149 /* ------------------------------ */ 150 151 static void snd_opl3_synth_free_port(void *private_data) 152 { 153 struct snd_opl3 *opl3 = private_data; 154 155 snd_midi_channel_free_set(opl3->chset); 156 } 157 158 static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) 159 { 160 struct snd_seq_port_callback callbacks; 161 char name[32]; 162 int voices, opl_ver; 163 164 voices = (opl3->hardware < OPL3_HW_OPL3) ? 165 MAX_OPL2_VOICES : MAX_OPL3_VOICES; 166 opl3->chset = snd_midi_channel_alloc_set(16); 167 if (opl3->chset == NULL) 168 return -ENOMEM; 169 opl3->chset->private_data = opl3; 170 171 memset(&callbacks, 0, sizeof(callbacks)); 172 callbacks.owner = THIS_MODULE; 173 callbacks.use = snd_opl3_synth_use; 174 callbacks.unuse = snd_opl3_synth_unuse; 175 callbacks.event_input = snd_opl3_synth_event_input; 176 callbacks.private_free = snd_opl3_synth_free_port; 177 callbacks.private_data = opl3; 178 179 opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8; 180 sprintf(name, "OPL%i FM Port", opl_ver); 181 182 opl3->chset->client = opl3->seq_client; 183 opl3->chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks, 184 SNDRV_SEQ_PORT_CAP_WRITE | 185 SNDRV_SEQ_PORT_CAP_SUBS_WRITE, 186 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | 187 SNDRV_SEQ_PORT_TYPE_MIDI_GM | 188 SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | 189 SNDRV_SEQ_PORT_TYPE_HARDWARE | 190 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, 191 16, voices, 192 name); 193 if (opl3->chset->port < 0) { 194 int port; 195 port = opl3->chset->port; 196 snd_midi_channel_free_set(opl3->chset); 197 return port; 198 } 199 return 0; 200 } 201 202 /* ------------------------------ */ 203 204 static int snd_opl3_seq_probe(struct device *_dev) 205 { 206 struct snd_seq_device *dev = to_seq_dev(_dev); 207 struct snd_opl3 *opl3; 208 int client, err; 209 char name[32]; 210 int opl_ver; 211 212 opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); 213 if (opl3 == NULL) 214 return -EINVAL; 215 216 spin_lock_init(&opl3->voice_lock); 217 218 opl3->seq_client = -1; 219 220 /* allocate new client */ 221 opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8; 222 sprintf(name, "OPL%i FM synth", opl_ver); 223 client = opl3->seq_client = 224 snd_seq_create_kernel_client(opl3->card, opl3->seq_dev_num, 225 name); 226 if (client < 0) 227 return client; 228 229 err = snd_opl3_synth_create_port(opl3); 230 if (err < 0) { 231 snd_seq_delete_kernel_client(client); 232 opl3->seq_client = -1; 233 return err; 234 } 235 236 /* setup system timer */ 237 timer_setup(&opl3->tlist, snd_opl3_timer_func, 0); 238 spin_lock_init(&opl3->sys_timer_lock); 239 opl3->sys_timer_status = 0; 240 241 #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) 242 snd_opl3_init_seq_oss(opl3, name); 243 #endif 244 return 0; 245 } 246 247 static int snd_opl3_seq_remove(struct device *_dev) 248 { 249 struct snd_seq_device *dev = to_seq_dev(_dev); 250 struct snd_opl3 *opl3; 251 252 opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); 253 if (opl3 == NULL) 254 return -EINVAL; 255 256 #if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) 257 snd_opl3_free_seq_oss(opl3); 258 #endif 259 if (opl3->seq_client >= 0) { 260 snd_seq_delete_kernel_client(opl3->seq_client); 261 opl3->seq_client = -1; 262 } 263 return 0; 264 } 265 266 static struct snd_seq_driver opl3_seq_driver = { 267 .driver = { 268 .name = KBUILD_MODNAME, 269 .probe = snd_opl3_seq_probe, 270 .remove = snd_opl3_seq_remove, 271 }, 272 .id = SNDRV_SEQ_DEV_ID_OPL3, 273 .argsize = sizeof(struct snd_opl3 *), 274 }; 275 276 module_snd_seq_driver(opl3_seq_driver); 277