aboutsummaryrefslogtreecommitdiffstats
path: root/sound/drivers/opl3
diff options
context:
space:
mode:
Diffstat (limited to 'sound/drivers/opl3')
-rw-r--r--sound/drivers/opl3/Makefile22
-rw-r--r--sound/drivers/opl3/opl3_drums.c223
-rw-r--r--sound/drivers/opl3/opl3_lib.c558
-rw-r--r--sound/drivers/opl3/opl3_midi.c873
-rw-r--r--sound/drivers/opl3/opl3_oss.c356
-rw-r--r--sound/drivers/opl3/opl3_seq.c314
-rw-r--r--sound/drivers/opl3/opl3_synth.c447
-rw-r--r--sound/drivers/opl3/opl3_voice.h52
8 files changed, 2845 insertions, 0 deletions
diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
new file mode 100644
index 000000000000..12059785b5cb
--- /dev/null
+++ b/sound/drivers/opl3/Makefile
@@ -0,0 +1,22 @@
1#
2# Makefile for ALSA
3# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-opl3-lib-objs := opl3_lib.o opl3_synth.o
7snd-opl3-synth-objs := opl3_seq.o opl3_midi.o opl3_drums.o
8ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
9snd-opl3-synth-objs += opl3_oss.o
10endif
11
12#
13# this function returns:
14# "m" - CONFIG_SND_SEQUENCER is m
15# <empty string> - CONFIG_SND_SEQUENCER is undefined
16# otherwise parameter #1 value
17#
18sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
19
20obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o
21obj-$(CONFIG_SND_OPL4_LIB) += snd-opl3-lib.o
22obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o
diff --git a/sound/drivers/opl3/opl3_drums.c b/sound/drivers/opl3/opl3_drums.c
new file mode 100644
index 000000000000..f26332680c19
--- /dev/null
+++ b/sound/drivers/opl3/opl3_drums.c
@@ -0,0 +1,223 @@
1/*
2 * Copyright (c) by Uros Bizjak <uros@kss-loka.si>
3 *
4 * OPL2/OPL3/OPL4 FM routines for internal percussion channels
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "opl3_voice.h"
23
24extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
25
26static char snd_opl3_drum_table[47] =
27{
28 OPL3_BASSDRUM_ON, OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, /* 35 - 37 */
29 OPL3_SNAREDRUM_ON, OPL3_HIHAT_ON, OPL3_SNAREDRUM_ON, /* 38 - 40 */
30 OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, OPL3_BASSDRUM_ON, /* 41 - 43 */
31 OPL3_HIHAT_ON, OPL3_TOMTOM_ON, OPL3_HIHAT_ON, /* 44 - 46 */
32 OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_CYMBAL_ON, /* 47 - 49 */
33
34 OPL3_TOMTOM_ON, OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, /* 50 - 52 */
35 OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, OPL3_CYMBAL_ON, /* 53 - 55 */
36 OPL3_HIHAT_ON, OPL3_CYMBAL_ON, OPL3_TOMTOM_ON, /* 56 - 58 */
37 OPL3_CYMBAL_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 59 - 61 */
38 OPL3_HIHAT_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 62 - 64 */
39
40 OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 65 - 67 */
41 OPL3_TOMTOM_ON, OPL3_HIHAT_ON, OPL3_HIHAT_ON, /* 68 - 70 */
42 OPL3_HIHAT_ON, OPL3_HIHAT_ON, OPL3_TOMTOM_ON, /* 71 - 73 */
43 OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 74 - 76 */
44 OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, OPL3_TOMTOM_ON, /* 77 - 79 */
45 OPL3_CYMBAL_ON, OPL3_CYMBAL_ON /* 80 - 81 */
46};
47
48typedef struct snd_opl3_drum_voice {
49 int voice;
50 int op;
51 unsigned char am_vib;
52 unsigned char ksl_level;
53 unsigned char attack_decay;
54 unsigned char sustain_release;
55 unsigned char feedback_connection;
56 unsigned char wave_select;
57} snd_opl3_drum_voice_t;
58
59typedef struct snd_opl3_drum_note {
60 int voice;
61 unsigned char fnum;
62 unsigned char octave_f;
63 unsigned char feedback_connection;
64} snd_opl3_drum_note_t;
65
66static snd_opl3_drum_voice_t bass_op0 = {6, 0, 0x00, 0x32, 0xf8, 0x66, 0x30, 0x00};
67static snd_opl3_drum_voice_t bass_op1 = {6, 1, 0x00, 0x03, 0xf6, 0x57, 0x30, 0x00};
68static snd_opl3_drum_note_t bass_note = {6, 0x90, 0x09};
69
70static snd_opl3_drum_voice_t hihat = {7, 0, 0x00, 0x03, 0xf0, 0x06, 0x20, 0x00};
71
72static snd_opl3_drum_voice_t snare = {7, 1, 0x00, 0x03, 0xf0, 0x07, 0x20, 0x02};
73static snd_opl3_drum_note_t snare_note = {7, 0xf4, 0x0d};
74
75static snd_opl3_drum_voice_t tomtom = {8, 0, 0x02, 0x03, 0xf0, 0x06, 0x10, 0x00};
76static snd_opl3_drum_note_t tomtom_note = {8, 0xf4, 0x09};
77
78static snd_opl3_drum_voice_t cymbal = {8, 1, 0x04, 0x03, 0xf0, 0x06, 0x10, 0x00};
79
80/*
81 * set drum voice characteristics
82 */
83static void snd_opl3_drum_voice_set(opl3_t *opl3, snd_opl3_drum_voice_t *data)
84{
85 unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
86 unsigned char voice_offset = data->voice;
87 unsigned short opl3_reg;
88
89 /* Set OPL3 AM_VIB register */
90 opl3_reg = OPL3_LEFT | (OPL3_REG_AM_VIB + op_offset);
91 opl3->command(opl3, opl3_reg, data->am_vib);
92
93 /* Set OPL3 KSL_LEVEL register */
94 opl3_reg = OPL3_LEFT | (OPL3_REG_KSL_LEVEL + op_offset);
95 opl3->command(opl3, opl3_reg, data->ksl_level);
96
97 /* Set OPL3 ATTACK_DECAY register */
98 opl3_reg = OPL3_LEFT | (OPL3_REG_ATTACK_DECAY + op_offset);
99 opl3->command(opl3, opl3_reg, data->attack_decay);
100
101 /* Set OPL3 SUSTAIN_RELEASE register */
102 opl3_reg = OPL3_LEFT | (OPL3_REG_SUSTAIN_RELEASE + op_offset);
103 opl3->command(opl3, opl3_reg, data->sustain_release);
104
105 /* Set OPL3 FEEDBACK_CONNECTION register */
106 opl3_reg = OPL3_LEFT | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
107 opl3->command(opl3, opl3_reg, data->feedback_connection);
108
109 /* Select waveform */
110 opl3_reg = OPL3_LEFT | (OPL3_REG_WAVE_SELECT + op_offset);
111 opl3->command(opl3, opl3_reg, data->wave_select);
112}
113
114/*
115 * Set drum voice pitch
116 */
117static void snd_opl3_drum_note_set(opl3_t *opl3, snd_opl3_drum_note_t *data)
118{
119 unsigned char voice_offset = data->voice;
120 unsigned short opl3_reg;
121
122 /* Set OPL3 FNUM_LOW register */
123 opl3_reg = OPL3_LEFT | (OPL3_REG_FNUM_LOW + voice_offset);
124 opl3->command(opl3, opl3_reg, data->fnum);
125
126 /* Set OPL3 KEYON_BLOCK register */
127 opl3_reg = OPL3_LEFT | (OPL3_REG_KEYON_BLOCK + voice_offset);
128 opl3->command(opl3, opl3_reg, data->octave_f);
129}
130
131/*
132 * Set drum voice volume and position
133 */
134static void snd_opl3_drum_vol_set(opl3_t *opl3, snd_opl3_drum_voice_t *data,
135 int vel, snd_midi_channel_t *chan)
136{
137 unsigned char op_offset = snd_opl3_regmap[data->voice][data->op];
138 unsigned char voice_offset = data->voice;
139 unsigned char reg_val;
140 unsigned short opl3_reg;
141
142 /* Set OPL3 KSL_LEVEL register */
143 reg_val = data->ksl_level;
144 snd_opl3_calc_volume(&reg_val, vel, chan);
145 opl3_reg = OPL3_LEFT | (OPL3_REG_KSL_LEVEL + op_offset);
146 opl3->command(opl3, opl3_reg, reg_val);
147
148 /* Set OPL3 FEEDBACK_CONNECTION register */
149 /* Set output voice connection */
150 reg_val = data->feedback_connection | OPL3_STEREO_BITS;
151 if (chan->gm_pan < 43)
152 reg_val &= ~OPL3_VOICE_TO_RIGHT;
153 if (chan->gm_pan > 85)
154 reg_val &= ~OPL3_VOICE_TO_LEFT;
155 opl3_reg = OPL3_LEFT | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
156 opl3->command(opl3, opl3_reg, reg_val);
157}
158
159/*
160 * Loads drum voices at init time
161 */
162void snd_opl3_load_drums(opl3_t *opl3)
163{
164 snd_opl3_drum_voice_set(opl3, &bass_op0);
165 snd_opl3_drum_voice_set(opl3, &bass_op1);
166 snd_opl3_drum_note_set(opl3, &bass_note);
167
168 snd_opl3_drum_voice_set(opl3, &hihat);
169
170 snd_opl3_drum_voice_set(opl3, &snare);
171 snd_opl3_drum_note_set(opl3, &snare_note);
172
173 snd_opl3_drum_voice_set(opl3, &tomtom);
174 snd_opl3_drum_note_set(opl3, &tomtom_note);
175
176 snd_opl3_drum_voice_set(opl3, &cymbal);
177}
178
179/*
180 * Switch drum voice on or off
181 */
182void snd_opl3_drum_switch(opl3_t *opl3, int note, int vel, int on_off,
183 snd_midi_channel_t *chan)
184{
185 unsigned char drum_mask;
186 snd_opl3_drum_voice_t *drum_voice;
187
188 if (!(opl3->drum_reg & OPL3_PERCUSSION_ENABLE))
189 return;
190
191 if ((note < 35) || (note > 81))
192 return;
193 drum_mask = snd_opl3_drum_table[note - 35];
194
195 if (on_off) {
196 switch (drum_mask) {
197 case OPL3_BASSDRUM_ON:
198 drum_voice = &bass_op1;
199 break;
200 case OPL3_HIHAT_ON:
201 drum_voice = &hihat;
202 break;
203 case OPL3_SNAREDRUM_ON:
204 drum_voice = &snare;
205 break;
206 case OPL3_TOMTOM_ON:
207 drum_voice = &tomtom;
208 break;
209 case OPL3_CYMBAL_ON:
210 drum_voice = &cymbal;
211 break;
212 default:
213 drum_voice = &tomtom;
214 }
215
216 snd_opl3_drum_vol_set(opl3, drum_voice, vel, chan);
217 opl3->drum_reg |= drum_mask;
218 } else {
219 opl3->drum_reg &= ~drum_mask;
220 }
221 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
222 opl3->drum_reg);
223}
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
new file mode 100644
index 000000000000..c313e5205cb8
--- /dev/null
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -0,0 +1,558 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
3 * Hannu Savolainen 1993-1996,
4 * Rob Hooft
5 *
6 * Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)
7 *
8 * Most if code is ported from OSS/Lite.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <sound/opl3.h>
27#include <asm/io.h>
28#include <linux/delay.h>
29#include <linux/init.h>
30#include <linux/slab.h>
31#include <linux/ioport.h>
32#include <sound/minors.h>
33
34MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
35MODULE_DESCRIPTION("Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)");
36MODULE_LICENSE("GPL");
37
38extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
39
40static void snd_opl2_command(opl3_t * opl3, unsigned short cmd, unsigned char val)
41{
42 unsigned long flags;
43 unsigned long port;
44
45 /*
46 * The original 2-OP synth requires a quite long delay
47 * after writing to a register.
48 */
49
50 port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
51
52 spin_lock_irqsave(&opl3->reg_lock, flags);
53
54 outb((unsigned char) cmd, port);
55 udelay(10);
56
57 outb((unsigned char) val, port + 1);
58 udelay(30);
59
60 spin_unlock_irqrestore(&opl3->reg_lock, flags);
61}
62
63static void snd_opl3_command(opl3_t * opl3, unsigned short cmd, unsigned char val)
64{
65 unsigned long flags;
66 unsigned long port;
67
68 /*
69 * The OPL-3 survives with just two INBs
70 * after writing to a register.
71 */
72
73 port = (cmd & OPL3_RIGHT) ? opl3->r_port : opl3->l_port;
74
75 spin_lock_irqsave(&opl3->reg_lock, flags);
76
77 outb((unsigned char) cmd, port);
78 inb(opl3->l_port);
79 inb(opl3->l_port);
80
81 outb((unsigned char) val, port + 1);
82 inb(opl3->l_port);
83 inb(opl3->l_port);
84
85 spin_unlock_irqrestore(&opl3->reg_lock, flags);
86}
87
88static int snd_opl3_detect(opl3_t * opl3)
89{
90 /*
91 * This function returns 1 if the FM chip is present at the given I/O port
92 * The detection algorithm plays with the timer built in the FM chip and
93 * looks for a change in the status register.
94 *
95 * Note! The timers of the FM chip are not connected to AdLib (and compatible)
96 * boards.
97 *
98 * Note2! The chip is initialized if detected.
99 */
100
101 unsigned char stat1, stat2, signature;
102
103 /* Reset timers 1 and 2 */
104 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);
105 /* Reset the IRQ of the FM chip */
106 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
107 signature = stat1 = inb(opl3->l_port); /* Status register */
108 if ((stat1 & 0xe0) != 0x00) { /* Should be 0x00 */
109 snd_printd("OPL3: stat1 = 0x%x\n", stat1);
110 return -ENODEV;
111 }
112 /* Set timer1 to 0xff */
113 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 0xff);
114 /* Unmask and start timer 1 */
115 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER2_MASK | OPL3_TIMER1_START);
116 /* Now we have to delay at least 80us */
117 udelay(200);
118 /* Read status after timers have expired */
119 stat2 = inb(opl3->l_port);
120 /* Stop the timers */
121 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_TIMER1_MASK | OPL3_TIMER2_MASK);
122 /* Reset the IRQ of the FM chip */
123 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
124 if ((stat2 & 0xe0) != 0xc0) { /* There is no YM3812 */
125 snd_printd("OPL3: stat2 = 0x%x\n", stat2);
126 return -ENODEV;
127 }
128
129 /* If the toplevel code knows exactly the type of chip, don't try
130 to detect it. */
131 if (opl3->hardware != OPL3_HW_AUTO)
132 return 0;
133
134 /* There is a FM chip on this address. Detect the type (OPL2 to OPL4) */
135 if (signature == 0x06) { /* OPL2 */
136 opl3->hardware = OPL3_HW_OPL2;
137 } else {
138 /*
139 * If we had an OPL4 chip, opl3->hardware would have been set
140 * by the OPL4 driver; so we can assume OPL3 here.
141 */
142 snd_assert(opl3->r_port != 0, return -ENODEV);
143 opl3->hardware = OPL3_HW_OPL3;
144 }
145 return 0;
146}
147
148/*
149 * AdLib timers
150 */
151
152/*
153 * Timer 1 - 80us
154 */
155
156static int snd_opl3_timer1_start(snd_timer_t * timer)
157{
158 unsigned long flags;
159 unsigned char tmp;
160 unsigned int ticks;
161 opl3_t *opl3;
162
163 opl3 = snd_timer_chip(timer);
164 spin_lock_irqsave(&opl3->timer_lock, flags);
165 ticks = timer->sticks;
166 tmp = (opl3->timer_enable | OPL3_TIMER1_START) & ~OPL3_TIMER1_MASK;
167 opl3->timer_enable = tmp;
168 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER1, 256 - ticks); /* timer 1 count */
169 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */
170 spin_unlock_irqrestore(&opl3->timer_lock, flags);
171 return 0;
172}
173
174static int snd_opl3_timer1_stop(snd_timer_t * timer)
175{
176 unsigned long flags;
177 unsigned char tmp;
178 opl3_t *opl3;
179
180 opl3 = snd_timer_chip(timer);
181 spin_lock_irqsave(&opl3->timer_lock, flags);
182 tmp = (opl3->timer_enable | OPL3_TIMER1_MASK) & ~OPL3_TIMER1_START;
183 opl3->timer_enable = tmp;
184 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */
185 spin_unlock_irqrestore(&opl3->timer_lock, flags);
186 return 0;
187}
188
189/*
190 * Timer 2 - 320us
191 */
192
193static int snd_opl3_timer2_start(snd_timer_t * timer)
194{
195 unsigned long flags;
196 unsigned char tmp;
197 unsigned int ticks;
198 opl3_t *opl3;
199
200 opl3 = snd_timer_chip(timer);
201 spin_lock_irqsave(&opl3->timer_lock, flags);
202 ticks = timer->sticks;
203 tmp = (opl3->timer_enable | OPL3_TIMER2_START) & ~OPL3_TIMER2_MASK;
204 opl3->timer_enable = tmp;
205 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER2, 256 - ticks); /* timer 1 count */
206 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* enable timer 1 IRQ */
207 spin_unlock_irqrestore(&opl3->timer_lock, flags);
208 return 0;
209}
210
211static int snd_opl3_timer2_stop(snd_timer_t * timer)
212{
213 unsigned long flags;
214 unsigned char tmp;
215 opl3_t *opl3;
216
217 opl3 = snd_timer_chip(timer);
218 spin_lock_irqsave(&opl3->timer_lock, flags);
219 tmp = (opl3->timer_enable | OPL3_TIMER2_MASK) & ~OPL3_TIMER2_START;
220 opl3->timer_enable = tmp;
221 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, tmp); /* disable timer #1 */
222 spin_unlock_irqrestore(&opl3->timer_lock, flags);
223 return 0;
224}
225
226/*
227
228 */
229
230static struct _snd_timer_hardware snd_opl3_timer1 =
231{
232 .flags = SNDRV_TIMER_HW_STOP,
233 .resolution = 80000,
234 .ticks = 256,
235 .start = snd_opl3_timer1_start,
236 .stop = snd_opl3_timer1_stop,
237};
238
239static struct _snd_timer_hardware snd_opl3_timer2 =
240{
241 .flags = SNDRV_TIMER_HW_STOP,
242 .resolution = 320000,
243 .ticks = 256,
244 .start = snd_opl3_timer2_start,
245 .stop = snd_opl3_timer2_stop,
246};
247
248static int snd_opl3_timer1_init(opl3_t * opl3, int timer_no)
249{
250 snd_timer_t *timer = NULL;
251 snd_timer_id_t tid;
252 int err;
253
254 tid.dev_class = SNDRV_TIMER_CLASS_CARD;
255 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
256 tid.card = opl3->card->number;
257 tid.device = timer_no;
258 tid.subdevice = 0;
259 if ((err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer)) >= 0) {
260 strcpy(timer->name, "AdLib timer #1");
261 timer->private_data = opl3;
262 timer->hw = snd_opl3_timer1;
263 }
264 opl3->timer1 = timer;
265 return err;
266}
267
268static int snd_opl3_timer2_init(opl3_t * opl3, int timer_no)
269{
270 snd_timer_t *timer = NULL;
271 snd_timer_id_t tid;
272 int err;
273
274 tid.dev_class = SNDRV_TIMER_CLASS_CARD;
275 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
276 tid.card = opl3->card->number;
277 tid.device = timer_no;
278 tid.subdevice = 0;
279 if ((err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer)) >= 0) {
280 strcpy(timer->name, "AdLib timer #2");
281 timer->private_data = opl3;
282 timer->hw = snd_opl3_timer2;
283 }
284 opl3->timer2 = timer;
285 return err;
286}
287
288/*
289
290 */
291
292void snd_opl3_interrupt(snd_hwdep_t * hw)
293{
294 unsigned char status;
295 opl3_t *opl3;
296 snd_timer_t *timer;
297
298 if (hw == NULL)
299 return;
300
301 opl3 = hw->private_data;
302 status = inb(opl3->l_port);
303#if 0
304 snd_printk("AdLib IRQ status = 0x%x\n", status);
305#endif
306 if (!(status & 0x80))
307 return;
308
309 if (status & 0x40) {
310 timer = opl3->timer1;
311 snd_timer_interrupt(timer, timer->sticks);
312 }
313 if (status & 0x20) {
314 timer = opl3->timer2;
315 snd_timer_interrupt(timer, timer->sticks);
316 }
317}
318
319/*
320
321 */
322
323static int snd_opl3_free(opl3_t *opl3)
324{
325 snd_assert(opl3 != NULL, return -ENXIO);
326 if (opl3->private_free)
327 opl3->private_free(opl3);
328 if (opl3->res_l_port) {
329 release_resource(opl3->res_l_port);
330 kfree_nocheck(opl3->res_l_port);
331 }
332 if (opl3->res_r_port) {
333 release_resource(opl3->res_r_port);
334 kfree_nocheck(opl3->res_r_port);
335 }
336 kfree(opl3);
337 return 0;
338}
339
340static int snd_opl3_dev_free(snd_device_t *device)
341{
342 opl3_t *opl3 = device->device_data;
343 return snd_opl3_free(opl3);
344}
345
346int snd_opl3_new(snd_card_t *card,
347 unsigned short hardware,
348 opl3_t **ropl3)
349{
350 static snd_device_ops_t ops = {
351 .dev_free = snd_opl3_dev_free,
352 };
353 opl3_t *opl3;
354 int err;
355
356 *ropl3 = NULL;
357 opl3 = kcalloc(1, sizeof(*opl3), GFP_KERNEL);
358 if (opl3 == NULL)
359 return -ENOMEM;
360
361 opl3->card = card;
362 opl3->hardware = hardware;
363 spin_lock_init(&opl3->reg_lock);
364 spin_lock_init(&opl3->timer_lock);
365 init_MUTEX(&opl3->access_mutex);
366
367 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
368 snd_opl3_free(opl3);
369 return err;
370 }
371
372 *ropl3 = opl3;
373 return 0;
374}
375
376int snd_opl3_init(opl3_t *opl3)
377{
378 if (! opl3->command) {
379 printk(KERN_ERR "snd_opl3_init: command not defined!\n");
380 return -EINVAL;
381 }
382
383 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TEST, OPL3_ENABLE_WAVE_SELECT);
384 /* Melodic mode */
385 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 0x00);
386
387 switch (opl3->hardware & OPL3_HW_MASK) {
388 case OPL3_HW_OPL2:
389 opl3->max_voices = MAX_OPL2_VOICES;
390 break;
391 case OPL3_HW_OPL3:
392 case OPL3_HW_OPL4:
393 opl3->max_voices = MAX_OPL3_VOICES;
394 /* Enter OPL3 mode */
395 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_MODE, OPL3_OPL3_ENABLE);
396 }
397 return 0;
398}
399
400int snd_opl3_create(snd_card_t * card,
401 unsigned long l_port,
402 unsigned long r_port,
403 unsigned short hardware,
404 int integrated,
405 opl3_t ** ropl3)
406{
407 opl3_t *opl3;
408 int err;
409
410 *ropl3 = NULL;
411 if ((err = snd_opl3_new(card, hardware, &opl3)) < 0)
412 return err;
413 if (! integrated) {
414 if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) {
415 snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port);
416 snd_opl3_free(opl3);
417 return -EBUSY;
418 }
419 if (r_port != 0 &&
420 (opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) {
421 snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
422 snd_opl3_free(opl3);
423 return -EBUSY;
424 }
425 }
426 opl3->l_port = l_port;
427 opl3->r_port = r_port;
428
429 switch (opl3->hardware) {
430 /* some hardware doesn't support timers */
431 case OPL3_HW_OPL3_SV:
432 case OPL3_HW_OPL3_CS:
433 case OPL3_HW_OPL3_FM801:
434 opl3->command = &snd_opl3_command;
435 break;
436 default:
437 opl3->command = &snd_opl2_command;
438 if ((err = snd_opl3_detect(opl3)) < 0) {
439 snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n",
440 opl3->l_port, opl3->r_port);
441 snd_opl3_free(opl3);
442 return err;
443 }
444 /* detect routine returns correct hardware type */
445 switch (opl3->hardware & OPL3_HW_MASK) {
446 case OPL3_HW_OPL3:
447 case OPL3_HW_OPL4:
448 opl3->command = &snd_opl3_command;
449 }
450 }
451
452 snd_opl3_init(opl3);
453
454 *ropl3 = opl3;
455 return 0;
456}
457
458int snd_opl3_timer_new(opl3_t * opl3, int timer1_dev, int timer2_dev)
459{
460 int err;
461
462 if (timer1_dev >= 0)
463 if ((err = snd_opl3_timer1_init(opl3, timer1_dev)) < 0)
464 return err;
465 if (timer2_dev >= 0) {
466 if ((err = snd_opl3_timer2_init(opl3, timer2_dev)) < 0) {
467 snd_device_free(opl3->card, opl3->timer1);
468 opl3->timer1 = NULL;
469 return err;
470 }
471 }
472 return 0;
473}
474
475int snd_opl3_hwdep_new(opl3_t * opl3,
476 int device, int seq_device,
477 snd_hwdep_t ** rhwdep)
478{
479 snd_hwdep_t *hw;
480 snd_card_t *card = opl3->card;
481 int err;
482
483 if (rhwdep)
484 *rhwdep = NULL;
485
486 /* create hardware dependent device (direct FM) */
487
488 if ((err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw)) < 0) {
489 snd_device_free(card, opl3);
490 return err;
491 }
492 hw->private_data = opl3;
493#ifdef CONFIG_SND_OSSEMUL
494 if (device == 0) {
495 hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
496 sprintf(hw->oss_dev, "dmfm%i", card->number);
497 }
498#endif
499 strcpy(hw->name, hw->id);
500 switch (opl3->hardware & OPL3_HW_MASK) {
501 case OPL3_HW_OPL2:
502 strcpy(hw->name, "OPL2 FM");
503 hw->iface = SNDRV_HWDEP_IFACE_OPL2;
504 break;
505 case OPL3_HW_OPL3:
506 strcpy(hw->name, "OPL3 FM");
507 hw->iface = SNDRV_HWDEP_IFACE_OPL3;
508 break;
509 case OPL3_HW_OPL4:
510 strcpy(hw->name, "OPL4 FM");
511 hw->iface = SNDRV_HWDEP_IFACE_OPL4;
512 break;
513 }
514
515 /* operators - only ioctl */
516 hw->ops.open = snd_opl3_open;
517 hw->ops.ioctl = snd_opl3_ioctl;
518 hw->ops.release = snd_opl3_release;
519
520 opl3->seq_dev_num = seq_device;
521#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
522 if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
523 sizeof(opl3_t*), &opl3->seq_dev) >= 0) {
524 strcpy(opl3->seq_dev->name, hw->name);
525 *(opl3_t**)SNDRV_SEQ_DEVICE_ARGPTR(opl3->seq_dev) = opl3;
526 }
527#endif
528 if (rhwdep)
529 *rhwdep = hw;
530 return 0;
531}
532
533EXPORT_SYMBOL(snd_opl3_interrupt);
534EXPORT_SYMBOL(snd_opl3_new);
535EXPORT_SYMBOL(snd_opl3_init);
536EXPORT_SYMBOL(snd_opl3_create);
537EXPORT_SYMBOL(snd_opl3_timer_new);
538EXPORT_SYMBOL(snd_opl3_hwdep_new);
539
540/* opl3_synth.c */
541EXPORT_SYMBOL(snd_opl3_regmap);
542EXPORT_SYMBOL(snd_opl3_reset);
543
544/*
545 * INIT part
546 */
547
548static int __init alsa_opl3_init(void)
549{
550 return 0;
551}
552
553static void __exit alsa_opl3_exit(void)
554{
555}
556
557module_init(alsa_opl3_init)
558module_exit(alsa_opl3_exit)
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
new file mode 100644
index 000000000000..93d674070b71
--- /dev/null
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -0,0 +1,873 @@
1/*
2 * Copyright (c) by Uros Bizjak <uros@kss-loka.si>
3 *
4 * Midi synth routines for OPL2/OPL3/OPL4 FM
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#undef DEBUG_ALLOC
23#undef DEBUG_MIDI
24
25#include "opl3_voice.h"
26#include <sound/asoundef.h>
27
28extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
29
30extern int use_internal_drums;
31
32/*
33 * The next table looks magical, but it certainly is not. Its values have
34 * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception
35 * for i=0. This log-table converts a linear volume-scaling (0..127) to a
36 * logarithmic scaling as present in the FM-synthesizer chips. so : Volume
37 * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative
38 * volume -8 it was implemented as a table because it is only 128 bytes and
39 * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>)
40 */
41
42static char opl3_volume_table[128] =
43{
44 -63, -48, -40, -35, -32, -29, -27, -26,
45 -24, -23, -21, -20, -19, -18, -18, -17,
46 -16, -15, -15, -14, -13, -13, -12, -12,
47 -11, -11, -10, -10, -10, -9, -9, -8,
48 -8, -8, -7, -7, -7, -6, -6, -6,
49 -5, -5, -5, -5, -4, -4, -4, -4,
50 -3, -3, -3, -3, -2, -2, -2, -2,
51 -2, -1, -1, -1, -1, 0, 0, 0,
52 0, 0, 0, 1, 1, 1, 1, 1,
53 1, 2, 2, 2, 2, 2, 2, 2,
54 3, 3, 3, 3, 3, 3, 3, 4,
55 4, 4, 4, 4, 4, 4, 4, 5,
56 5, 5, 5, 5, 5, 5, 5, 5,
57 6, 6, 6, 6, 6, 6, 6, 6,
58 6, 7, 7, 7, 7, 7, 7, 7,
59 7, 7, 7, 8, 8, 8, 8, 8
60};
61
62void snd_opl3_calc_volume(unsigned char *volbyte, int vel,
63 snd_midi_channel_t *chan)
64{
65 int oldvol, newvol, n;
66 int volume;
67
68 volume = (vel * chan->gm_volume * chan->gm_expression) / (127*127);
69 if (volume > 127)
70 volume = 127;
71
72 oldvol = OPL3_TOTAL_LEVEL_MASK - (*volbyte & OPL3_TOTAL_LEVEL_MASK);
73
74 newvol = opl3_volume_table[volume] + oldvol;
75 if (newvol > OPL3_TOTAL_LEVEL_MASK)
76 newvol = OPL3_TOTAL_LEVEL_MASK;
77 else if (newvol < 0)
78 newvol = 0;
79
80 n = OPL3_TOTAL_LEVEL_MASK - (newvol & OPL3_TOTAL_LEVEL_MASK);
81
82 *volbyte = (*volbyte & OPL3_KSL_MASK) | (n & OPL3_TOTAL_LEVEL_MASK);
83}
84
85/*
86 * Converts the note frequency to block and fnum values for the FM chip
87 */
88static short opl3_note_table[16] =
89{
90 305, 323, /* for pitch bending, -2 semitones */
91 343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647,
92 686, 726 /* for pitch bending, +2 semitones */
93};
94
95static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum,
96 int note, snd_midi_channel_t *chan)
97{
98 int block = ((note / 12) & 0x07) - 1;
99 int idx = (note % 12) + 2;
100 int freq;
101
102 if (chan->midi_pitchbend) {
103 int pitchbend = chan->midi_pitchbend;
104 int segment;
105
106 if (pitchbend > 0x1FFF)
107 pitchbend = 0x1FFF;
108
109 segment = pitchbend / 0x1000;
110 freq = opl3_note_table[idx+segment];
111 freq += ((opl3_note_table[idx+segment+1] - freq) *
112 (pitchbend % 0x1000)) / 0x1000;
113 } else {
114 freq = opl3_note_table[idx];
115 }
116
117 *fnum = (unsigned char) freq;
118 *blocknum = ((freq >> 8) & OPL3_FNUM_HIGH_MASK) |
119 ((block << 2) & OPL3_BLOCKNUM_MASK);
120}
121
122
123#ifdef DEBUG_ALLOC
124static void debug_alloc(opl3_t *opl3, char *s, int voice) {
125 int i;
126 char *str = "x.24";
127
128 printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
129 for (i = 0; i < opl3->max_voices; i++)
130 printk("%c", *(str + opl3->voices[i].state + 1));
131 printk("\n");
132}
133#endif
134
135/*
136 * Get a FM voice (channel) to play a note on.
137 */
138static int opl3_get_voice(opl3_t *opl3, int instr_4op,
139 snd_midi_channel_t *chan) {
140 int chan_4op_1; /* first voice for 4op instrument */
141 int chan_4op_2; /* second voice for 4op instrument */
142
143 snd_opl3_voice_t *vp, *vp2;
144 unsigned int voice_time;
145 int i;
146
147#ifdef DEBUG_ALLOC
148 char *alloc_type[3] = { "FREE ", "CHEAP ", "EXPENSIVE" };
149#endif
150
151 /* This is our "allocation cost" table */
152 enum {
153 FREE = 0, CHEAP, EXPENSIVE, END
154 };
155
156 /* Keeps track of what we are finding */
157 struct best {
158 unsigned int time;
159 int voice;
160 } best[END];
161 struct best *bp;
162
163 for (i = 0; i < END; i++) {
164 best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
165 best[i].voice = -1;
166 }
167
168 /* Look through all the channels for the most suitable. */
169 for (i = 0; i < opl3->max_voices; i++) {
170 vp = &opl3->voices[i];
171
172 if (vp->state == SNDRV_OPL3_ST_NOT_AVAIL)
173 /* skip unavailable channels, allocated by
174 drum voices or by bounded 4op voices) */
175 continue;
176
177 voice_time = vp->time;
178 bp = best;
179
180 chan_4op_1 = ((i < 3) || (i > 8 && i < 12));
181 chan_4op_2 = ((i > 2 && i < 6) || (i > 11 && i < 15));
182 if (instr_4op) {
183 /* allocate 4op voice */
184 /* skip channels unavailable to 4op instrument */
185 if (!chan_4op_1)
186 continue;
187
188 if (vp->state)
189 /* kill one voice, CHEAP */
190 bp++;
191 /* get state of bounded 2op channel
192 to be allocated for 4op instrument */
193 vp2 = &opl3->voices[i + 3];
194 if (vp2->state == SNDRV_OPL3_ST_ON_2OP) {
195 /* kill two voices, EXPENSIVE */
196 bp++;
197 voice_time = (voice_time > vp->time) ?
198 voice_time : vp->time;
199 }
200 } else {
201 /* allocate 2op voice */
202 if ((chan_4op_1) || (chan_4op_2))
203 /* use bounded channels for 2op, CHEAP */
204 bp++;
205 else if (vp->state)
206 /* kill one voice on 2op channel, CHEAP */
207 bp++;
208 /* raise kill cost to EXPENSIVE for all channels */
209 if (vp->state)
210 bp++;
211 }
212 if (voice_time < bp->time) {
213 bp->time = voice_time;
214 bp->voice = i;
215 }
216 }
217
218 for (i = 0; i < END; i++) {
219 if (best[i].voice >= 0) {
220#ifdef DEBUG_ALLOC
221 printk("%s %iop allocation on voice %i\n",
222 alloc_type[i], instr_4op ? 4 : 2,
223 best[i].voice);
224#endif
225 return best[i].voice;
226 }
227 }
228 /* not found */
229 return -1;
230}
231
232/* ------------------------------ */
233
234/*
235 * System timer interrupt function
236 */
237void snd_opl3_timer_func(unsigned long data)
238{
239
240 opl3_t *opl3 = (opl3_t *)data;
241 int again = 0;
242 int i;
243
244 spin_lock(&opl3->sys_timer_lock);
245 for (i = 0; i < opl3->max_voices; i++) {
246 snd_opl3_voice_t *vp = &opl3->voices[i];
247 if (vp->state > 0 && vp->note_off_check) {
248 if (vp->note_off == jiffies)
249 snd_opl3_note_off(opl3, vp->note, 0, vp->chan);
250 else
251 again++;
252 }
253 }
254 if (again) {
255 opl3->tlist.expires = jiffies + 1; /* invoke again */
256 add_timer(&opl3->tlist);
257 } else {
258 opl3->sys_timer_status = 0;
259 }
260 spin_unlock(&opl3->sys_timer_lock);
261}
262
263/*
264 * Start system timer
265 */
266static void snd_opl3_start_timer(opl3_t *opl3)
267{
268 unsigned long flags;
269 spin_lock_irqsave(&opl3->sys_timer_lock, flags);
270 if (! opl3->sys_timer_status) {
271 opl3->tlist.expires = jiffies + 1;
272 add_timer(&opl3->tlist);
273 opl3->sys_timer_status = 1;
274 }
275 spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
276}
277
278/* ------------------------------ */
279
280
281static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
282 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14
283};
284
285/*
286 * Start a note.
287 */
288void snd_opl3_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
289{
290 opl3_t *opl3;
291 snd_seq_instr_t wanted;
292 snd_seq_kinstr_t *kinstr;
293 int instr_4op;
294
295 int voice;
296 snd_opl3_voice_t *vp, *vp2;
297 unsigned short connect_mask;
298 unsigned char connection;
299 unsigned char vol_op[4];
300
301 int extra_prg = 0;
302
303 unsigned short reg_side;
304 unsigned char op_offset;
305 unsigned char voice_offset;
306 unsigned short opl3_reg;
307 unsigned char reg_val;
308
309 int key = note;
310 unsigned char fnum, blocknum;
311 int i;
312
313 fm_instrument_t *fm;
314 unsigned long flags;
315
316 opl3 = p;
317
318#ifdef DEBUG_MIDI
319 snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
320 chan->number, chan->midi_program, note, vel);
321#endif
322 wanted.cluster = 0;
323 wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
324
325 /* in SYNTH mode, application takes care of voices */
326 /* in SEQ mode, drum voice numbers are notes on drum channel */
327 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
328 if (chan->drum_channel) {
329 /* percussion instruments are located in bank 128 */
330 wanted.bank = 128;
331 wanted.prg = note;
332 } else {
333 wanted.bank = chan->gm_bank_select;
334 wanted.prg = chan->midi_program;
335 }
336 } else {
337 /* Prepare for OSS mode */
338 if (chan->number >= MAX_OPL3_VOICES)
339 return;
340
341 /* OSS instruments are located in bank 127 */
342 wanted.bank = 127;
343 wanted.prg = chan->midi_program;
344 }
345
346 spin_lock_irqsave(&opl3->voice_lock, flags);
347
348 if (use_internal_drums) {
349 snd_opl3_drum_switch(opl3, note, vel, 1, chan);
350 spin_unlock_irqrestore(&opl3->voice_lock, flags);
351 return;
352 }
353
354 __extra_prg:
355 kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0);
356 if (kinstr == NULL) {
357 spin_unlock_irqrestore(&opl3->voice_lock, flags);
358 return;
359 }
360
361 fm = KINSTR_DATA(kinstr);
362
363 switch (fm->type) {
364 case FM_PATCH_OPL2:
365 instr_4op = 0;
366 break;
367 case FM_PATCH_OPL3:
368 if (opl3->hardware >= OPL3_HW_OPL3) {
369 instr_4op = 1;
370 break;
371 }
372 default:
373 snd_seq_instr_free_use(opl3->ilist, kinstr);
374 spin_unlock_irqrestore(&opl3->voice_lock, flags);
375 return;
376 }
377
378#ifdef DEBUG_MIDI
379 snd_printk(" --> OPL%i instrument: %s\n",
380 instr_4op ? 3 : 2, kinstr->name);
381#endif
382 /* in SYNTH mode, application takes care of voices */
383 /* in SEQ mode, allocate voice on free OPL3 channel */
384 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
385 voice = opl3_get_voice(opl3, instr_4op, chan);
386 } else {
387 /* remap OSS voice */
388 voice = snd_opl3_oss_map[chan->number];
389 }
390
391 if (voice < MAX_OPL2_VOICES) {
392 /* Left register block for voices 0 .. 8 */
393 reg_side = OPL3_LEFT;
394 voice_offset = voice;
395 connect_mask = (OPL3_LEFT_4OP_0 << voice_offset) & 0x07;
396 } else {
397 /* Right register block for voices 9 .. 17 */
398 reg_side = OPL3_RIGHT;
399 voice_offset = voice - MAX_OPL2_VOICES;
400 connect_mask = (OPL3_RIGHT_4OP_0 << voice_offset) & 0x38;
401 }
402
403 /* kill voice on channel */
404 vp = &opl3->voices[voice];
405 if (vp->state > 0) {
406 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
407 reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
408 opl3->command(opl3, opl3_reg, reg_val);
409 }
410 if (instr_4op) {
411 vp2 = &opl3->voices[voice + 3];
412 if (vp->state > 0) {
413 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK +
414 voice_offset + 3);
415 reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
416 opl3->command(opl3, opl3_reg, reg_val);
417 }
418 }
419
420 /* set connection register */
421 if (instr_4op) {
422 if ((opl3->connection_reg ^ connect_mask) & connect_mask) {
423 opl3->connection_reg |= connect_mask;
424 /* set connection bit */
425 opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT;
426 opl3->command(opl3, opl3_reg, opl3->connection_reg);
427 }
428 } else {
429 if ((opl3->connection_reg ^ ~connect_mask) & connect_mask) {
430 opl3->connection_reg &= ~connect_mask;
431 /* clear connection bit */
432 opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT;
433 opl3->command(opl3, opl3_reg, opl3->connection_reg);
434 }
435 }
436
437#ifdef DEBUG_MIDI
438 snd_printk(" --> setting OPL3 connection: 0x%x\n",
439 opl3->connection_reg);
440#endif
441 /*
442 * calculate volume depending on connection
443 * between FM operators (see include/opl3.h)
444 */
445 for (i = 0; i < (instr_4op ? 4 : 2); i++)
446 vol_op[i] = fm->op[i].ksl_level;
447
448 connection = fm->feedback_connection[0] & 0x01;
449 if (instr_4op) {
450 connection <<= 1;
451 connection |= fm->feedback_connection[1] & 0x01;
452
453 snd_opl3_calc_volume(&vol_op[3], vel, chan);
454 switch (connection) {
455 case 0x03:
456 snd_opl3_calc_volume(&vol_op[2], vel, chan);
457 /* fallthru */
458 case 0x02:
459 snd_opl3_calc_volume(&vol_op[0], vel, chan);
460 break;
461 case 0x01:
462 snd_opl3_calc_volume(&vol_op[1], vel, chan);
463 }
464 } else {
465 snd_opl3_calc_volume(&vol_op[1], vel, chan);
466 if (connection)
467 snd_opl3_calc_volume(&vol_op[0], vel, chan);
468 }
469
470 /* Program the FM voice characteristics */
471 for (i = 0; i < (instr_4op ? 4 : 2); i++) {
472#ifdef DEBUG_MIDI
473 snd_printk(" --> programming operator %i\n", i);
474#endif
475 op_offset = snd_opl3_regmap[voice_offset][i];
476
477 /* Set OPL3 AM_VIB register of requested voice/operator */
478 reg_val = fm->op[i].am_vib;
479 opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset);
480 opl3->command(opl3, opl3_reg, reg_val);
481
482 /* Set OPL3 KSL_LEVEL register of requested voice/operator */
483 reg_val = vol_op[i];
484 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset);
485 opl3->command(opl3, opl3_reg, reg_val);
486
487 /* Set OPL3 ATTACK_DECAY register of requested voice/operator */
488 reg_val = fm->op[i].attack_decay;
489 opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset);
490 opl3->command(opl3, opl3_reg, reg_val);
491
492 /* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */
493 reg_val = fm->op[i].sustain_release;
494 opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset);
495 opl3->command(opl3, opl3_reg, reg_val);
496
497 /* Select waveform */
498 reg_val = fm->op[i].wave_select;
499 opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset);
500 opl3->command(opl3, opl3_reg, reg_val);
501 }
502
503 /* Set operator feedback and 2op inter-operator connection */
504 reg_val = fm->feedback_connection[0];
505 /* Set output voice connection */
506 reg_val |= OPL3_STEREO_BITS;
507 if (chan->gm_pan < 43)
508 reg_val &= ~OPL3_VOICE_TO_RIGHT;
509 if (chan->gm_pan > 85)
510 reg_val &= ~OPL3_VOICE_TO_LEFT;
511 opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
512 opl3->command(opl3, opl3_reg, reg_val);
513
514 if (instr_4op) {
515 /* Set 4op inter-operator connection */
516 reg_val = fm->feedback_connection[1] & OPL3_CONNECTION_BIT;
517 /* Set output voice connection */
518 reg_val |= OPL3_STEREO_BITS;
519 if (chan->gm_pan < 43)
520 reg_val &= ~OPL3_VOICE_TO_RIGHT;
521 if (chan->gm_pan > 85)
522 reg_val &= ~OPL3_VOICE_TO_LEFT;
523 opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION +
524 voice_offset + 3);
525 opl3->command(opl3, opl3_reg, reg_val);
526 }
527
528 /*
529 * Special treatment of percussion notes for fm:
530 * Requested pitch is really program, and pitch for
531 * device is whatever was specified in the patch library.
532 */
533 if (fm->fix_key)
534 note = fm->fix_key;
535 /*
536 * use transpose if defined in patch library
537 */
538 if (fm->trnsps)
539 note += (fm->trnsps - 64);
540
541 snd_opl3_calc_pitch(&fnum, &blocknum, note, chan);
542
543 /* Set OPL3 FNUM_LOW register of requested voice */
544 opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);
545 opl3->command(opl3, opl3_reg, fnum);
546
547 opl3->voices[voice].keyon_reg = blocknum;
548
549 /* Set output sound flag */
550 blocknum |= OPL3_KEYON_BIT;
551
552#ifdef DEBUG_MIDI
553 snd_printk(" --> trigger voice %i\n", voice);
554#endif
555 /* Set OPL3 KEYON_BLOCK register of requested voice */
556 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
557 opl3->command(opl3, opl3_reg, blocknum);
558
559 /* kill note after fixed duration (in centiseconds) */
560 if (fm->fix_dur) {
561 opl3->voices[voice].note_off = jiffies +
562 (fm->fix_dur * HZ) / 100;
563 snd_opl3_start_timer(opl3);
564 opl3->voices[voice].note_off_check = 1;
565 } else
566 opl3->voices[voice].note_off_check = 0;
567
568 /* get extra pgm, but avoid possible loops */
569 extra_prg = (extra_prg) ? 0 : fm->modes;
570
571 snd_seq_instr_free_use(opl3->ilist, kinstr);
572
573 /* do the bookkeeping */
574 vp->time = opl3->use_time++;
575 vp->note = key;
576 vp->chan = chan;
577
578 if (instr_4op) {
579 vp->state = SNDRV_OPL3_ST_ON_4OP;
580
581 vp2 = &opl3->voices[voice + 3];
582 vp2->time = opl3->use_time++;
583 vp2->note = key;
584 vp2->chan = chan;
585 vp2->state = SNDRV_OPL3_ST_NOT_AVAIL;
586 } else {
587 if (vp->state == SNDRV_OPL3_ST_ON_4OP) {
588 /* 4op killed by 2op, release bounded voice */
589 vp2 = &opl3->voices[voice + 3];
590 vp2->time = opl3->use_time++;
591 vp2->state = SNDRV_OPL3_ST_OFF;
592 }
593 vp->state = SNDRV_OPL3_ST_ON_2OP;
594 }
595
596#ifdef DEBUG_ALLOC
597 debug_alloc(opl3, "note on ", voice);
598#endif
599
600 /* allocate extra program if specified in patch library */
601 if (extra_prg) {
602 if (extra_prg > 128) {
603 wanted.bank = 128;
604 /* percussions start at 35 */
605 wanted.prg = extra_prg - 128 + 35 - 1;
606 } else {
607 wanted.bank = 0;
608 wanted.prg = extra_prg - 1;
609 }
610#ifdef DEBUG_MIDI
611 snd_printk(" *** allocating extra program\n");
612#endif
613 goto __extra_prg;
614 }
615 spin_unlock_irqrestore(&opl3->voice_lock, flags);
616}
617
618static void snd_opl3_kill_voice(opl3_t *opl3, int voice)
619{
620 unsigned short reg_side;
621 unsigned char voice_offset;
622 unsigned short opl3_reg;
623
624 snd_opl3_voice_t *vp, *vp2;
625
626 snd_assert(voice < MAX_OPL3_VOICES, return);
627
628 vp = &opl3->voices[voice];
629 if (voice < MAX_OPL2_VOICES) {
630 /* Left register block for voices 0 .. 8 */
631 reg_side = OPL3_LEFT;
632 voice_offset = voice;
633 } else {
634 /* Right register block for voices 9 .. 17 */
635 reg_side = OPL3_RIGHT;
636 voice_offset = voice - MAX_OPL2_VOICES;
637 }
638
639 /* kill voice */
640#ifdef DEBUG_MIDI
641 snd_printk(" --> kill voice %i\n", voice);
642#endif
643 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
644 /* clear Key ON bit */
645 opl3->command(opl3, opl3_reg, vp->keyon_reg);
646
647 /* do the bookkeeping */
648 vp->time = opl3->use_time++;
649
650 if (vp->state == SNDRV_OPL3_ST_ON_4OP) {
651 vp2 = &opl3->voices[voice + 3];
652
653 vp2->time = opl3->use_time++;
654 vp2->state = SNDRV_OPL3_ST_OFF;
655 }
656 vp->state = SNDRV_OPL3_ST_OFF;
657#ifdef DEBUG_ALLOC
658 debug_alloc(opl3, "note off", voice);
659#endif
660
661}
662
663/*
664 * Release a note in response to a midi note off.
665 */
666void snd_opl3_note_off(void *p, int note, int vel, snd_midi_channel_t *chan)
667{
668 opl3_t *opl3;
669
670 int voice;
671 snd_opl3_voice_t *vp;
672
673 unsigned long flags;
674
675 opl3 = p;
676
677#ifdef DEBUG_MIDI
678 snd_printk("Note off, ch %i, inst %i, note %i\n",
679 chan->number, chan->midi_program, note);
680#endif
681
682 spin_lock_irqsave(&opl3->voice_lock, flags);
683
684 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
685 if (chan->drum_channel && use_internal_drums) {
686 snd_opl3_drum_switch(opl3, note, vel, 0, chan);
687 spin_unlock_irqrestore(&opl3->voice_lock, flags);
688 return;
689 }
690 /* this loop will hopefully kill all extra voices, because
691 they are grouped by the same channel and note values */
692 for (voice = 0; voice < opl3->max_voices; voice++) {
693 vp = &opl3->voices[voice];
694 if (vp->state > 0 && vp->chan == chan && vp->note == note) {
695 snd_opl3_kill_voice(opl3, voice);
696 }
697 }
698 } else {
699 /* remap OSS voices */
700 if (chan->number < MAX_OPL3_VOICES) {
701 voice = snd_opl3_oss_map[chan->number];
702 snd_opl3_kill_voice(opl3, voice);
703 }
704 }
705 spin_unlock_irqrestore(&opl3->voice_lock, flags);
706}
707
708/*
709 * key pressure change
710 */
711void snd_opl3_key_press(void *p, int note, int vel, snd_midi_channel_t *chan)
712{
713 opl3_t *opl3;
714
715 opl3 = p;
716#ifdef DEBUG_MIDI
717 snd_printk("Key pressure, ch#: %i, inst#: %i\n",
718 chan->number, chan->midi_program);
719#endif
720}
721
722/*
723 * terminate note
724 */
725void snd_opl3_terminate_note(void *p, int note, snd_midi_channel_t *chan)
726{
727 opl3_t *opl3;
728
729 opl3 = p;
730#ifdef DEBUG_MIDI
731 snd_printk("Terminate note, ch#: %i, inst#: %i\n",
732 chan->number, chan->midi_program);
733#endif
734}
735
736static void snd_opl3_update_pitch(opl3_t *opl3, int voice)
737{
738 unsigned short reg_side;
739 unsigned char voice_offset;
740 unsigned short opl3_reg;
741
742 unsigned char fnum, blocknum;
743
744 snd_opl3_voice_t *vp;
745
746 snd_assert(voice < MAX_OPL3_VOICES, return);
747
748 vp = &opl3->voices[voice];
749 if (vp->chan == NULL)
750 return; /* not allocated? */
751
752 if (voice < MAX_OPL2_VOICES) {
753 /* Left register block for voices 0 .. 8 */
754 reg_side = OPL3_LEFT;
755 voice_offset = voice;
756 } else {
757 /* Right register block for voices 9 .. 17 */
758 reg_side = OPL3_RIGHT;
759 voice_offset = voice - MAX_OPL2_VOICES;
760 }
761
762 snd_opl3_calc_pitch(&fnum, &blocknum, vp->note, vp->chan);
763
764 /* Set OPL3 FNUM_LOW register of requested voice */
765 opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);
766 opl3->command(opl3, opl3_reg, fnum);
767
768 vp->keyon_reg = blocknum;
769
770 /* Set output sound flag */
771 blocknum |= OPL3_KEYON_BIT;
772
773 /* Set OPL3 KEYON_BLOCK register of requested voice */
774 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
775 opl3->command(opl3, opl3_reg, blocknum);
776
777 vp->time = opl3->use_time++;
778}
779
780/*
781 * Update voice pitch controller
782 */
783static void snd_opl3_pitch_ctrl(opl3_t *opl3, snd_midi_channel_t *chan)
784{
785 int voice;
786 snd_opl3_voice_t *vp;
787
788 unsigned long flags;
789
790 spin_lock_irqsave(&opl3->voice_lock, flags);
791
792 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
793 for (voice = 0; voice < opl3->max_voices; voice++) {
794 vp = &opl3->voices[voice];
795 if (vp->state > 0 && vp->chan == chan) {
796 snd_opl3_update_pitch(opl3, voice);
797 }
798 }
799 } else {
800 /* remap OSS voices */
801 if (chan->number < MAX_OPL3_VOICES) {
802 voice = snd_opl3_oss_map[chan->number];
803 snd_opl3_update_pitch(opl3, voice);
804 }
805 }
806 spin_unlock_irqrestore(&opl3->voice_lock, flags);
807}
808
809/*
810 * Deal with a controler type event. This includes all types of
811 * control events, not just the midi controllers
812 */
813void snd_opl3_control(void *p, int type, snd_midi_channel_t *chan)
814{
815 opl3_t *opl3;
816
817 opl3 = p;
818#ifdef DEBUG_MIDI
819 snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",
820 type, chan->number, chan->midi_program);
821#endif
822
823 switch (type) {
824 case MIDI_CTL_MSB_MODWHEEL:
825 if (chan->control[MIDI_CTL_MSB_MODWHEEL] > 63)
826 opl3->drum_reg |= OPL3_VIBRATO_DEPTH;
827 else
828 opl3->drum_reg &= ~OPL3_VIBRATO_DEPTH;
829 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
830 opl3->drum_reg);
831 break;
832 case MIDI_CTL_E2_TREMOLO_DEPTH:
833 if (chan->control[MIDI_CTL_E2_TREMOLO_DEPTH] > 63)
834 opl3->drum_reg |= OPL3_TREMOLO_DEPTH;
835 else
836 opl3->drum_reg &= ~OPL3_TREMOLO_DEPTH;
837 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION,
838 opl3->drum_reg);
839 break;
840 case MIDI_CTL_PITCHBEND:
841 snd_opl3_pitch_ctrl(opl3, chan);
842 break;
843 }
844}
845
846/*
847 * NRPN events
848 */
849void snd_opl3_nrpn(void *p, snd_midi_channel_t *chan,
850 snd_midi_channel_set_t *chset)
851{
852 opl3_t *opl3;
853
854 opl3 = p;
855#ifdef DEBUG_MIDI
856 snd_printk("NRPN, ch#: %i, inst#: %i\n",
857 chan->number, chan->midi_program);
858#endif
859}
860
861/*
862 * receive sysex
863 */
864void snd_opl3_sysex(void *p, unsigned char *buf, int len,
865 int parsed, snd_midi_channel_set_t *chset)
866{
867 opl3_t *opl3;
868
869 opl3 = p;
870#ifdef DEBUG_MIDI
871 snd_printk("SYSEX\n");
872#endif
873}
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
new file mode 100644
index 000000000000..33da334ae981
--- /dev/null
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -0,0 +1,356 @@
1/*
2 * Interface for OSS sequencer emulation
3 *
4 * Copyright (C) 2000 Uros Bizjak <uros@kss-loka.si>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "opl3_voice.h"
22#include <linux/slab.h>
23
24static int snd_opl3_open_seq_oss(snd_seq_oss_arg_t *arg, void *closure);
25static int snd_opl3_close_seq_oss(snd_seq_oss_arg_t *arg);
26static int snd_opl3_ioctl_seq_oss(snd_seq_oss_arg_t *arg, unsigned int cmd, unsigned long ioarg);
27static int snd_opl3_load_patch_seq_oss(snd_seq_oss_arg_t *arg, int format, const char __user *buf, int offs, int count);
28static int snd_opl3_reset_seq_oss(snd_seq_oss_arg_t *arg);
29
30/* */
31
32static inline mm_segment_t snd_enter_user(void)
33{
34 mm_segment_t fs = get_fs();
35 set_fs(get_ds());
36 return fs;
37}
38
39static inline void snd_leave_user(mm_segment_t fs)
40{
41 set_fs(fs);
42}
43
44/* operators */
45
46extern snd_midi_op_t opl3_ops;
47
48static snd_seq_oss_callback_t oss_callback = {
49 .owner = THIS_MODULE,
50 .open = snd_opl3_open_seq_oss,
51 .close = snd_opl3_close_seq_oss,
52 .ioctl = snd_opl3_ioctl_seq_oss,
53 .load_patch = snd_opl3_load_patch_seq_oss,
54 .reset = snd_opl3_reset_seq_oss,
55};
56
57static int snd_opl3_oss_event_input(snd_seq_event_t *ev, int direct,
58 void *private_data, int atomic, int hop)
59{
60 opl3_t *opl3 = private_data;
61
62 if (ev->type != SNDRV_SEQ_EVENT_OSS)
63 snd_midi_process_event(&opl3_ops, ev, opl3->oss_chset);
64 return 0;
65}
66
67/* ------------------------------ */
68
69static void snd_opl3_oss_free_port(void *private_data)
70{
71 opl3_t *opl3 = private_data;
72
73 snd_midi_channel_free_set(opl3->oss_chset);
74}
75
76static int snd_opl3_oss_create_port(opl3_t * opl3)
77{
78 snd_seq_port_callback_t callbacks;
79 char name[32];
80 int voices, opl_ver;
81
82 voices = (opl3->hardware < OPL3_HW_OPL3) ?
83 MAX_OPL2_VOICES : MAX_OPL3_VOICES;
84 opl3->oss_chset = snd_midi_channel_alloc_set(voices);
85 if (opl3->oss_chset == NULL)
86 return -ENOMEM;
87 opl3->oss_chset->private_data = opl3;
88
89 memset(&callbacks, 0, sizeof(callbacks));
90 callbacks.owner = THIS_MODULE;
91 callbacks.event_input = snd_opl3_oss_event_input;
92 callbacks.private_free = snd_opl3_oss_free_port;
93 callbacks.private_data = opl3;
94
95 opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
96 sprintf(name, "OPL%i OSS Port", opl_ver);
97
98 opl3->oss_chset->client = opl3->seq_client;
99 opl3->oss_chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks,
100 SNDRV_SEQ_PORT_CAP_WRITE,
101 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
102 SNDRV_SEQ_PORT_TYPE_MIDI_GM |
103 SNDRV_SEQ_PORT_TYPE_SYNTH,
104 voices, voices,
105 name);
106 if (opl3->oss_chset->port < 0) {
107 snd_midi_channel_free_set(opl3->oss_chset);
108 return opl3->oss_chset->port;
109 }
110 return 0;
111}
112
113/* ------------------------------ */
114
115/* register OSS synth */
116void snd_opl3_init_seq_oss(opl3_t *opl3, char *name)
117{
118 snd_seq_oss_reg_t *arg;
119 snd_seq_device_t *dev;
120
121 if (snd_seq_device_new(opl3->card, 0, SNDRV_SEQ_DEV_ID_OSS,
122 sizeof(snd_seq_oss_reg_t), &dev) < 0)
123 return;
124
125 opl3->oss_seq_dev = dev;
126 strlcpy(dev->name, name, sizeof(dev->name));
127 arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
128 arg->type = SYNTH_TYPE_FM;
129 if (opl3->hardware < OPL3_HW_OPL3) {
130 arg->subtype = FM_TYPE_ADLIB;
131 arg->nvoices = MAX_OPL2_VOICES;
132 } else {
133 arg->subtype = FM_TYPE_OPL3;
134 arg->nvoices = MAX_OPL3_VOICES;
135 }
136 arg->oper = oss_callback;
137 arg->private_data = opl3;
138
139 snd_opl3_oss_create_port(opl3);
140
141 /* register to OSS synth table */
142 snd_device_register(opl3->card, dev);
143}
144
145/* unregister */
146void snd_opl3_free_seq_oss(opl3_t *opl3)
147{
148 if (opl3->oss_seq_dev) {
149 snd_device_free(opl3->card, opl3->oss_seq_dev);
150 opl3->oss_seq_dev = NULL;
151 }
152}
153
154/* ------------------------------ */
155
156/* open OSS sequencer */
157static int snd_opl3_open_seq_oss(snd_seq_oss_arg_t *arg, void *closure)
158{
159 opl3_t *opl3 = closure;
160 int err;
161
162 snd_assert(arg != NULL, return -ENXIO);
163
164 if ((err = snd_opl3_synth_setup(opl3)) < 0)
165 return err;
166
167 /* fill the argument data */
168 arg->private_data = opl3;
169 arg->addr.client = opl3->oss_chset->client;
170 arg->addr.port = opl3->oss_chset->port;
171
172 if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
173 return err;
174
175 opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH;
176 return 0;
177}
178
179/* close OSS sequencer */
180static int snd_opl3_close_seq_oss(snd_seq_oss_arg_t *arg)
181{
182 opl3_t *opl3;
183
184 snd_assert(arg != NULL, return -ENXIO);
185 opl3 = arg->private_data;
186
187 snd_opl3_synth_cleanup(opl3);
188
189 snd_opl3_synth_use_dec(opl3);
190 return 0;
191}
192
193/* load patch */
194
195/* offsets for SBI params */
196#define AM_VIB 0
197#define KSL_LEVEL 2
198#define ATTACK_DECAY 4
199#define SUSTAIN_RELEASE 6
200#define WAVE_SELECT 8
201
202/* offset for SBI instrument */
203#define CONNECTION 10
204#define OFFSET_4OP 11
205
206/* from sound_config.h */
207#define SBFM_MAXINSTR 256
208
209static int snd_opl3_load_patch_seq_oss(snd_seq_oss_arg_t *arg, int format,
210 const char __user *buf, int offs, int count)
211{
212 opl3_t *opl3;
213 int err = -EINVAL;
214
215 snd_assert(arg != NULL, return -ENXIO);
216 opl3 = arg->private_data;
217
218 if ((format == FM_PATCH) || (format == OPL3_PATCH)) {
219 struct sbi_instrument sbi;
220
221 size_t size;
222 snd_seq_instr_header_t *put;
223 snd_seq_instr_data_t *data;
224 fm_xinstrument_t *xinstr;
225
226 snd_seq_event_t ev;
227 int i;
228
229 mm_segment_t fs;
230
231 if (count < (int)sizeof(sbi)) {
232 snd_printk("FM Error: Patch record too short\n");
233 return -EINVAL;
234 }
235 if (copy_from_user(&sbi, buf, sizeof(sbi)))
236 return -EFAULT;
237
238 if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
239 snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel);
240 return -EINVAL;
241 }
242
243 size = sizeof(*put) + sizeof(fm_xinstrument_t);
244 put = kcalloc(1, size, GFP_KERNEL);
245 if (put == NULL)
246 return -ENOMEM;
247 /* build header */
248 data = &put->data;
249 data->type = SNDRV_SEQ_INSTR_ATYPE_DATA;
250 strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3);
251 /* build data section */
252 xinstr = (fm_xinstrument_t *)(data + 1);
253 xinstr->stype = FM_STRU_INSTR;
254
255 for (i = 0; i < 2; i++) {
256 xinstr->op[i].am_vib = sbi.operators[AM_VIB + i];
257 xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i];
258 xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i];
259 xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i];
260 xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i];
261 }
262 xinstr->feedback_connection[0] = sbi.operators[CONNECTION];
263
264 if (format == OPL3_PATCH) {
265 xinstr->type = FM_PATCH_OPL3;
266 for (i = 0; i < 2; i++) {
267 xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i];
268 xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i];
269 xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i];
270 xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i];
271 xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i];
272 }
273 xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION];
274 } else {
275 xinstr->type = FM_PATCH_OPL2;
276 }
277
278 put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
279 put->id.instr.bank = 127;
280 put->id.instr.prg = sbi.channel;
281 put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE;
282
283 memset (&ev, 0, sizeof(ev));
284 ev.source.client = SNDRV_SEQ_CLIENT_OSS;
285 ev.dest = arg->addr;
286
287 ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR;
288 ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
289
290 fs = snd_enter_user();
291 __again:
292 ev.type = SNDRV_SEQ_EVENT_INSTR_PUT;
293 ev.data.ext.len = size;
294 ev.data.ext.ptr = put;
295
296 err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
297 opl3->seq_client, 0, 0);
298 if (err == -EBUSY) {
299 snd_seq_instr_header_t remove;
300
301 memset (&remove, 0, sizeof(remove));
302 remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE;
303 remove.id.instr = put->id.instr;
304
305 /* remove instrument */
306 ev.type = SNDRV_SEQ_EVENT_INSTR_FREE;
307 ev.data.ext.len = sizeof(remove);
308 ev.data.ext.ptr = &remove;
309
310 snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
311 opl3->seq_client, 0, 0);
312 goto __again;
313 }
314 snd_leave_user(fs);
315
316 kfree(put);
317 }
318 return err;
319}
320
321/* ioctl */
322static int snd_opl3_ioctl_seq_oss(snd_seq_oss_arg_t *arg, unsigned int cmd,
323 unsigned long ioarg)
324{
325 opl3_t *opl3;
326
327 snd_assert(arg != NULL, return -ENXIO);
328 opl3 = arg->private_data;
329 switch (cmd) {
330 case SNDCTL_FM_LOAD_INSTR:
331 snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
332 return -EINVAL;
333
334 case SNDCTL_SYNTH_MEMAVL:
335 return 0x7fffffff;
336
337 case SNDCTL_FM_4OP_ENABLE:
338 // handled automatically by OPL instrument type
339 return 0;
340
341 default:
342 return -EINVAL;
343 }
344 return 0;
345}
346
347/* reset device */
348static int snd_opl3_reset_seq_oss(snd_seq_oss_arg_t *arg)
349{
350 opl3_t *opl3;
351
352 snd_assert(arg != NULL, return -ENXIO);
353 opl3 = arg->private_data;
354
355 return 0;
356}
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
new file mode 100644
index 000000000000..136964b844de
--- /dev/null
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -0,0 +1,314 @@
1/*
2 * Copyright (c) by Uros Bizjak <uros@kss-loka.si>
3 *
4 * Midi Sequencer interface routines for OPL2/OPL3/OPL4 FM
5 *
6 * OPL2/3 FM instrument loader:
7 * alsa-tools/seq/sbiload/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#include "opl3_voice.h"
26#include <linux/init.h>
27#include <linux/moduleparam.h>
28#include <sound/initval.h>
29
30MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
31MODULE_LICENSE("GPL");
32MODULE_DESCRIPTION("ALSA driver for OPL3 FM synth");
33
34int use_internal_drums = 0;
35module_param(use_internal_drums, bool, 0444);
36MODULE_PARM_DESC(use_internal_drums, "Enable internal OPL2/3 drums.");
37
38int snd_opl3_synth_use_inc(opl3_t * opl3)
39{
40 if (!try_module_get(opl3->card->module))
41 return -EFAULT;
42 return 0;
43
44}
45
46void snd_opl3_synth_use_dec(opl3_t * opl3)
47{
48 module_put(opl3->card->module);
49}
50
51int snd_opl3_synth_setup(opl3_t * opl3)
52{
53 int idx;
54
55 down(&opl3->access_mutex);
56 if (opl3->used) {
57 up(&opl3->access_mutex);
58 return -EBUSY;
59 }
60 opl3->used++;
61 up(&opl3->access_mutex);
62
63 snd_opl3_reset(opl3);
64
65 for (idx = 0; idx < MAX_OPL3_VOICES; idx++) {
66 opl3->voices[idx].state = SNDRV_OPL3_ST_OFF;
67 opl3->voices[idx].time = 0;
68 opl3->voices[idx].keyon_reg = 0x00;
69 }
70 opl3->use_time = 0;
71 opl3->connection_reg = 0x00;
72 if (opl3->hardware >= OPL3_HW_OPL3) {
73 /* Clear 4-op connections */
74 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT,
75 opl3->connection_reg);
76 opl3->max_voices = MAX_OPL3_VOICES;
77 }
78 return 0;
79}
80
81void snd_opl3_synth_cleanup(opl3_t * opl3)
82{
83 unsigned long flags;
84
85 /* Stop system timer */
86 spin_lock_irqsave(&opl3->sys_timer_lock, flags);
87 if (opl3->sys_timer_status) {
88 del_timer(&opl3->tlist);
89 opl3->sys_timer_status = 0;
90 }
91 spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
92
93 snd_opl3_reset(opl3);
94 down(&opl3->access_mutex);
95 opl3->used--;
96 up(&opl3->access_mutex);
97}
98
99static int snd_opl3_synth_use(void *private_data, snd_seq_port_subscribe_t * info)
100{
101 opl3_t *opl3 = private_data;
102 int err;
103
104 if ((err = snd_opl3_synth_setup(opl3)) < 0)
105 return err;
106
107 if (use_internal_drums) {
108 /* Percussion mode */
109 opl3->voices[6].state = opl3->voices[7].state =
110 opl3->voices[8].state = SNDRV_OPL3_ST_NOT_AVAIL;
111 snd_opl3_load_drums(opl3);
112 opl3->drum_reg = OPL3_PERCUSSION_ENABLE;
113 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, opl3->drum_reg);
114 } else {
115 opl3->drum_reg = 0x00;
116 }
117
118 if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
119 if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
120 return err;
121 }
122 opl3->synth_mode = SNDRV_OPL3_MODE_SEQ;
123 return 0;
124}
125
126static int snd_opl3_synth_unuse(void *private_data, snd_seq_port_subscribe_t * info)
127{
128 opl3_t *opl3 = private_data;
129
130 snd_opl3_synth_cleanup(opl3);
131
132 if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
133 snd_opl3_synth_use_dec(opl3);
134 return 0;
135}
136
137/*
138 * MIDI emulation operators
139 */
140snd_midi_op_t opl3_ops = {
141 .note_on = snd_opl3_note_on,
142 .note_off = snd_opl3_note_off,
143 .key_press = snd_opl3_key_press,
144 .note_terminate = snd_opl3_terminate_note,
145 .control = snd_opl3_control,
146 .nrpn = snd_opl3_nrpn,
147 .sysex = snd_opl3_sysex,
148};
149
150static int snd_opl3_synth_event_input(snd_seq_event_t * ev, int direct,
151 void *private_data, int atomic, int hop)
152{
153 opl3_t *opl3 = private_data;
154
155 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN &&
156 ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) {
157 if (direct) {
158 snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev,
159 opl3->seq_client, atomic, hop);
160 }
161 } else {
162 snd_midi_process_event(&opl3_ops, ev, opl3->chset);
163 }
164 return 0;
165}
166
167/* ------------------------------ */
168
169static void snd_opl3_synth_free_port(void *private_data)
170{
171 opl3_t *opl3 = private_data;
172
173 snd_midi_channel_free_set(opl3->chset);
174}
175
176static int snd_opl3_synth_create_port(opl3_t * opl3)
177{
178 snd_seq_port_callback_t callbacks;
179 char name[32];
180 int voices, opl_ver;
181
182 voices = (opl3->hardware < OPL3_HW_OPL3) ?
183 MAX_OPL2_VOICES : MAX_OPL3_VOICES;
184 opl3->chset = snd_midi_channel_alloc_set(16);
185 if (opl3->chset == NULL)
186 return -ENOMEM;
187 opl3->chset->private_data = opl3;
188
189 memset(&callbacks, 0, sizeof(callbacks));
190 callbacks.owner = THIS_MODULE;
191 callbacks.use = snd_opl3_synth_use;
192 callbacks.unuse = snd_opl3_synth_unuse;
193 callbacks.event_input = snd_opl3_synth_event_input;
194 callbacks.private_free = snd_opl3_synth_free_port;
195 callbacks.private_data = opl3;
196
197 opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
198 sprintf(name, "OPL%i FM Port", opl_ver);
199
200 opl3->chset->client = opl3->seq_client;
201 opl3->chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks,
202 SNDRV_SEQ_PORT_CAP_WRITE |
203 SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
204 SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
205 SNDRV_SEQ_PORT_TYPE_MIDI_GM |
206 SNDRV_SEQ_PORT_TYPE_SYNTH,
207 16, voices,
208 name);
209 if (opl3->chset->port < 0) {
210 snd_midi_channel_free_set(opl3->chset);
211 return opl3->chset->port;
212 }
213 return 0;
214}
215
216/* ------------------------------ */
217
218static int snd_opl3_seq_new_device(snd_seq_device_t *dev)
219{
220 opl3_t *opl3;
221 int client;
222 snd_seq_client_callback_t callbacks;
223 snd_seq_client_info_t cinfo;
224 int opl_ver;
225
226 opl3 = *(opl3_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
227 if (opl3 == NULL)
228 return -EINVAL;
229
230 spin_lock_init(&opl3->voice_lock);
231
232 opl3->seq_client = -1;
233
234 /* allocate new client */
235 memset(&callbacks, 0, sizeof(callbacks));
236 callbacks.private_data = opl3;
237 callbacks.allow_output = callbacks.allow_input = 1;
238 client = opl3->seq_client =
239 snd_seq_create_kernel_client(opl3->card, opl3->seq_dev_num, &callbacks);
240 if (client < 0)
241 return client;
242
243 /* change name of client */
244 memset(&cinfo, 0, sizeof(cinfo));
245 cinfo.client = client;
246 cinfo.type = KERNEL_CLIENT;
247 opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
248 sprintf(cinfo.name, "OPL%i FM synth", opl_ver);
249 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
250
251 snd_opl3_synth_create_port(opl3);
252
253 /* initialize instrument list */
254 opl3->ilist = snd_seq_instr_list_new();
255 if (opl3->ilist == NULL) {
256 snd_seq_delete_kernel_client(client);
257 opl3->seq_client = -1;
258 return -ENOMEM;
259 }
260 opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
261 snd_seq_fm_init(&opl3->fm_ops, NULL);
262
263 /* setup system timer */
264 init_timer(&opl3->tlist);
265 opl3->tlist.function = snd_opl3_timer_func;
266 opl3->tlist.data = (unsigned long) opl3;
267 spin_lock_init(&opl3->sys_timer_lock);
268 opl3->sys_timer_status = 0;
269
270#ifdef CONFIG_SND_SEQUENCER_OSS
271 snd_opl3_init_seq_oss(opl3, cinfo.name);
272#endif
273 return 0;
274}
275
276static int snd_opl3_seq_delete_device(snd_seq_device_t *dev)
277{
278 opl3_t *opl3;
279
280 opl3 = *(opl3_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
281 if (opl3 == NULL)
282 return -EINVAL;
283
284#ifdef CONFIG_SND_SEQUENCER_OSS
285 snd_opl3_free_seq_oss(opl3);
286#endif
287 if (opl3->seq_client >= 0) {
288 snd_seq_delete_kernel_client(opl3->seq_client);
289 opl3->seq_client = -1;
290 }
291 if (opl3->ilist)
292 snd_seq_instr_list_free(&opl3->ilist);
293 return 0;
294}
295
296static int __init alsa_opl3_seq_init(void)
297{
298 static snd_seq_dev_ops_t ops =
299 {
300 snd_opl3_seq_new_device,
301 snd_opl3_seq_delete_device
302 };
303
304 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops,
305 sizeof(opl3_t*));
306}
307
308static void __exit alsa_opl3_seq_exit(void)
309{
310 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);
311}
312
313module_init(alsa_opl3_seq_init)
314module_exit(alsa_opl3_seq_exit)
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
new file mode 100644
index 000000000000..04f9f955e5b7
--- /dev/null
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -0,0 +1,447 @@
1/*
2 * Copyright (c) by Uros Bizjak <uros@kss-loka.si>
3 *
4 * Routines for OPL2/OPL3/OPL4 control
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/opl3.h>
23#include <sound/asound_fm.h>
24
25/*
26 * There is 18 possible 2 OP voices
27 * (9 in the left and 9 in the right).
28 * The first OP is the modulator and 2nd is the carrier.
29 *
30 * The first three voices in the both sides may be connected
31 * with another voice to a 4 OP voice. For example voice 0
32 * can be connected with voice 3. The operators of voice 3 are
33 * used as operators 3 and 4 of the new 4 OP voice.
34 * In this case the 2 OP voice number 0 is the 'first half' and
35 * voice 3 is the second.
36 */
37
38
39/*
40 * Register offset table for OPL2/3 voices,
41 * OPL2 / one OPL3 register array side only
42 */
43
44char snd_opl3_regmap[MAX_OPL2_VOICES][4] =
45{
46/* OP1 OP2 OP3 OP4 */
47/* ------------------------ */
48 { 0x00, 0x03, 0x08, 0x0b },
49 { 0x01, 0x04, 0x09, 0x0c },
50 { 0x02, 0x05, 0x0a, 0x0d },
51
52 { 0x08, 0x0b, 0x00, 0x00 },
53 { 0x09, 0x0c, 0x00, 0x00 },
54 { 0x0a, 0x0d, 0x00, 0x00 },
55
56 { 0x10, 0x13, 0x00, 0x00 }, /* used by percussive voices */
57 { 0x11, 0x14, 0x00, 0x00 }, /* if the percussive mode */
58 { 0x12, 0x15, 0x00, 0x00 } /* is selected (only left reg block) */
59};
60
61/*
62 * prototypes
63 */
64static int snd_opl3_play_note(opl3_t * opl3, snd_dm_fm_note_t * note);
65static int snd_opl3_set_voice(opl3_t * opl3, snd_dm_fm_voice_t * voice);
66static int snd_opl3_set_params(opl3_t * opl3, snd_dm_fm_params_t * params);
67static int snd_opl3_set_mode(opl3_t * opl3, int mode);
68static int snd_opl3_set_connection(opl3_t * opl3, int connection);
69
70/* ------------------------------ */
71
72/*
73 * open the device exclusively
74 */
75int snd_opl3_open(snd_hwdep_t * hw, struct file *file)
76{
77 opl3_t *opl3 = hw->private_data;
78
79 down(&opl3->access_mutex);
80 if (opl3->used) {
81 up(&opl3->access_mutex);
82 return -EAGAIN;
83 }
84 opl3->used++;
85 up(&opl3->access_mutex);
86
87 return 0;
88}
89
90/*
91 * ioctl for hwdep device:
92 */
93int snd_opl3_ioctl(snd_hwdep_t * hw, struct file *file,
94 unsigned int cmd, unsigned long arg)
95{
96 opl3_t *opl3 = hw->private_data;
97 void __user *argp = (void __user *)arg;
98
99 snd_assert(opl3 != NULL, return -EINVAL);
100
101 switch (cmd) {
102 /* get information */
103 case SNDRV_DM_FM_IOCTL_INFO:
104 {
105 snd_dm_fm_info_t info;
106
107 info.fm_mode = opl3->fm_mode;
108 info.rhythm = opl3->rhythm;
109 if (copy_to_user(argp, &info, sizeof(snd_dm_fm_info_t)))
110 return -EFAULT;
111 return 0;
112 }
113
114 case SNDRV_DM_FM_IOCTL_RESET:
115#ifdef CONFIG_SND_OSSEMUL
116 case SNDRV_DM_FM_OSS_IOCTL_RESET:
117#endif
118 snd_opl3_reset(opl3);
119 return 0;
120
121 case SNDRV_DM_FM_IOCTL_PLAY_NOTE:
122#ifdef CONFIG_SND_OSSEMUL
123 case SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE:
124#endif
125 {
126 snd_dm_fm_note_t note;
127 if (copy_from_user(&note, argp, sizeof(snd_dm_fm_note_t)))
128 return -EFAULT;
129 return snd_opl3_play_note(opl3, &note);
130 }
131
132 case SNDRV_DM_FM_IOCTL_SET_VOICE:
133#ifdef CONFIG_SND_OSSEMUL
134 case SNDRV_DM_FM_OSS_IOCTL_SET_VOICE:
135#endif
136 {
137 snd_dm_fm_voice_t voice;
138 if (copy_from_user(&voice, argp, sizeof(snd_dm_fm_voice_t)))
139 return -EFAULT;
140 return snd_opl3_set_voice(opl3, &voice);
141 }
142
143 case SNDRV_DM_FM_IOCTL_SET_PARAMS:
144#ifdef CONFIG_SND_OSSEMUL
145 case SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS:
146#endif
147 {
148 snd_dm_fm_params_t params;
149 if (copy_from_user(&params, argp, sizeof(snd_dm_fm_params_t)))
150 return -EFAULT;
151 return snd_opl3_set_params(opl3, &params);
152 }
153
154 case SNDRV_DM_FM_IOCTL_SET_MODE:
155#ifdef CONFIG_SND_OSSEMUL
156 case SNDRV_DM_FM_OSS_IOCTL_SET_MODE:
157#endif
158 return snd_opl3_set_mode(opl3, (int) arg);
159
160 case SNDRV_DM_FM_IOCTL_SET_CONNECTION:
161#ifdef CONFIG_SND_OSSEMUL
162 case SNDRV_DM_FM_OSS_IOCTL_SET_OPL:
163#endif
164 return snd_opl3_set_connection(opl3, (int) arg);
165
166#ifdef CONFIG_SND_DEBUG
167 default:
168 snd_printk("unknown IOCTL: 0x%x\n", cmd);
169#endif
170 }
171 return -ENOTTY;
172}
173
174/*
175 * close the device
176 */
177int snd_opl3_release(snd_hwdep_t * hw, struct file *file)
178{
179 opl3_t *opl3 = hw->private_data;
180
181 snd_opl3_reset(opl3);
182 down(&opl3->access_mutex);
183 opl3->used--;
184 up(&opl3->access_mutex);
185
186 return 0;
187}
188
189/* ------------------------------ */
190
191void snd_opl3_reset(opl3_t * opl3)
192{
193 unsigned short opl3_reg;
194
195 unsigned short reg_side;
196 unsigned char voice_offset;
197
198 int max_voices, i;
199
200 max_voices = (opl3->hardware < OPL3_HW_OPL3) ?
201 MAX_OPL2_VOICES : MAX_OPL3_VOICES;
202
203 for (i = 0; i < max_voices; i++) {
204 /* Get register array side and offset of voice */
205 if (i < MAX_OPL2_VOICES) {
206 /* Left register block for voices 0 .. 8 */
207 reg_side = OPL3_LEFT;
208 voice_offset = i;
209 } else {
210 /* Right register block for voices 9 .. 17 */
211 reg_side = OPL3_RIGHT;
212 voice_offset = i - MAX_OPL2_VOICES;
213 }
214 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + snd_opl3_regmap[voice_offset][0]);
215 opl3->command(opl3, opl3_reg, OPL3_TOTAL_LEVEL_MASK); /* Operator 1 volume */
216 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + snd_opl3_regmap[voice_offset][1]);
217 opl3->command(opl3, opl3_reg, OPL3_TOTAL_LEVEL_MASK); /* Operator 2 volume */
218
219 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
220 opl3->command(opl3, opl3_reg, 0x00); /* Note off */
221 }
222
223 opl3->max_voices = MAX_OPL2_VOICES;
224 opl3->fm_mode = SNDRV_DM_FM_MODE_OPL2;
225
226 opl3->command(opl3, OPL3_LEFT | OPL3_REG_TEST, OPL3_ENABLE_WAVE_SELECT);
227 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 0x00); /* Melodic mode */
228 opl3->rhythm = 0;
229}
230
231
232static int snd_opl3_play_note(opl3_t * opl3, snd_dm_fm_note_t * note)
233{
234 unsigned short reg_side;
235 unsigned char voice_offset;
236
237 unsigned short opl3_reg;
238 unsigned char reg_val;
239
240 /* Voices 0 - 8 in OPL2 mode */
241 /* Voices 0 - 17 in OPL3 mode */
242 if (note->voice >= ((opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) ?
243 MAX_OPL3_VOICES : MAX_OPL2_VOICES))
244 return -EINVAL;
245
246 /* Get register array side and offset of voice */
247 if (note->voice < MAX_OPL2_VOICES) {
248 /* Left register block for voices 0 .. 8 */
249 reg_side = OPL3_LEFT;
250 voice_offset = note->voice;
251 } else {
252 /* Right register block for voices 9 .. 17 */
253 reg_side = OPL3_RIGHT;
254 voice_offset = note->voice - MAX_OPL2_VOICES;
255 }
256
257 /* Set lower 8 bits of note frequency */
258 reg_val = (unsigned char) note->fnum;
259 opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset);
260 opl3->command(opl3, opl3_reg, reg_val);
261
262 reg_val = 0x00;
263 /* Set output sound flag */
264 if (note->key_on)
265 reg_val |= OPL3_KEYON_BIT;
266 /* Set octave */
267 reg_val |= (note->octave << 2) & OPL3_BLOCKNUM_MASK;
268 /* Set higher 2 bits of note frequency */
269 reg_val |= (unsigned char) (note->fnum >> 8) & OPL3_FNUM_HIGH_MASK;
270
271 /* Set OPL3 KEYON_BLOCK register of requested voice */
272 opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
273 opl3->command(opl3, opl3_reg, reg_val);
274
275 return 0;
276}
277
278
279static int snd_opl3_set_voice(opl3_t * opl3, snd_dm_fm_voice_t * voice)
280{
281 unsigned short reg_side;
282 unsigned char op_offset;
283 unsigned char voice_offset;
284
285 unsigned short opl3_reg;
286 unsigned char reg_val;
287
288 /* Only operators 1 and 2 */
289 if (voice->op > 1)
290 return -EINVAL;
291 /* Voices 0 - 8 in OPL2 mode */
292 /* Voices 0 - 17 in OPL3 mode */
293 if (voice->voice >= ((opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) ?
294 MAX_OPL3_VOICES : MAX_OPL2_VOICES))
295 return -EINVAL;
296
297 /* Get register array side and offset of voice */
298 if (voice->voice < MAX_OPL2_VOICES) {
299 /* Left register block for voices 0 .. 8 */
300 reg_side = OPL3_LEFT;
301 voice_offset = voice->voice;
302 } else {
303 /* Right register block for voices 9 .. 17 */
304 reg_side = OPL3_RIGHT;
305 voice_offset = voice->voice - MAX_OPL2_VOICES;
306 }
307 /* Get register offset of operator */
308 op_offset = snd_opl3_regmap[voice_offset][voice->op];
309
310 reg_val = 0x00;
311 /* Set amplitude modulation (tremolo) effect */
312 if (voice->am)
313 reg_val |= OPL3_TREMOLO_ON;
314 /* Set vibrato effect */
315 if (voice->vibrato)
316 reg_val |= OPL3_VIBRATO_ON;
317 /* Set sustaining sound phase */
318 if (voice->do_sustain)
319 reg_val |= OPL3_SUSTAIN_ON;
320 /* Set keyboard scaling bit */
321 if (voice->kbd_scale)
322 reg_val |= OPL3_KSR;
323 /* Set harmonic or frequency multiplier */
324 reg_val |= voice->harmonic & OPL3_MULTIPLE_MASK;
325
326 /* Set OPL3 AM_VIB register of requested voice/operator */
327 opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset);
328 opl3->command(opl3, opl3_reg, reg_val);
329
330 /* Set decreasing volume of higher notes */
331 reg_val = (voice->scale_level << 6) & OPL3_KSL_MASK;
332 /* Set output volume */
333 reg_val |= ~voice->volume & OPL3_TOTAL_LEVEL_MASK;
334
335 /* Set OPL3 KSL_LEVEL register of requested voice/operator */
336 opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset);
337 opl3->command(opl3, opl3_reg, reg_val);
338
339 /* Set attack phase level */
340 reg_val = (voice->attack << 4) & OPL3_ATTACK_MASK;
341 /* Set decay phase level */
342 reg_val |= voice->decay & OPL3_DECAY_MASK;
343
344 /* Set OPL3 ATTACK_DECAY register of requested voice/operator */
345 opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset);
346 opl3->command(opl3, opl3_reg, reg_val);
347
348 /* Set sustain phase level */
349 reg_val = (voice->sustain << 4) & OPL3_SUSTAIN_MASK;
350 /* Set release phase level */
351 reg_val |= voice->release & OPL3_RELEASE_MASK;
352
353 /* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */
354 opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset);
355 opl3->command(opl3, opl3_reg, reg_val);
356
357 /* Set inter-operator feedback */
358 reg_val = (voice->feedback << 1) & OPL3_FEEDBACK_MASK;
359 /* Set inter-operator connection */
360 if (voice->connection)
361 reg_val |= OPL3_CONNECTION_BIT;
362 /* OPL-3 only */
363 if (opl3->fm_mode == SNDRV_DM_FM_MODE_OPL3) {
364 if (voice->left)
365 reg_val |= OPL3_VOICE_TO_LEFT;
366 if (voice->right)
367 reg_val |= OPL3_VOICE_TO_RIGHT;
368 }
369 /* Feedback/connection bits are applicable to voice */
370 opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset);
371 opl3->command(opl3, opl3_reg, reg_val);
372
373 /* Select waveform */
374 reg_val = voice->waveform & OPL3_WAVE_SELECT_MASK;
375 opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset);
376 opl3->command(opl3, opl3_reg, reg_val);
377
378 return 0;
379}
380
381static int snd_opl3_set_params(opl3_t * opl3, snd_dm_fm_params_t * params)
382{
383 unsigned char reg_val;
384
385 reg_val = 0x00;
386 /* Set keyboard split method */
387 if (params->kbd_split)
388 reg_val |= OPL3_KEYBOARD_SPLIT;
389 opl3->command(opl3, OPL3_LEFT | OPL3_REG_KBD_SPLIT, reg_val);
390
391 reg_val = 0x00;
392 /* Set amplitude modulation (tremolo) depth */
393 if (params->am_depth)
394 reg_val |= OPL3_TREMOLO_DEPTH;
395 /* Set vibrato depth */
396 if (params->vib_depth)
397 reg_val |= OPL3_VIBRATO_DEPTH;
398 /* Set percussion mode */
399 if (params->rhythm) {
400 reg_val |= OPL3_PERCUSSION_ENABLE;
401 opl3->rhythm = 1;
402 } else {
403 opl3->rhythm = 0;
404 }
405 /* Play percussion instruments */
406 if (params->bass)
407 reg_val |= OPL3_BASSDRUM_ON;
408 if (params->snare)
409 reg_val |= OPL3_SNAREDRUM_ON;
410 if (params->tomtom)
411 reg_val |= OPL3_TOMTOM_ON;
412 if (params->cymbal)
413 reg_val |= OPL3_CYMBAL_ON;
414 if (params->hihat)
415 reg_val |= OPL3_HIHAT_ON;
416
417 opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, reg_val);
418 return 0;
419}
420
421static int snd_opl3_set_mode(opl3_t * opl3, int mode)
422{
423 if ((mode == SNDRV_DM_FM_MODE_OPL3) && (opl3->hardware < OPL3_HW_OPL3))
424 return -EINVAL;
425
426 opl3->fm_mode = mode;
427 if (opl3->hardware >= OPL3_HW_OPL3)
428 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT, 0x00); /* Clear 4-op connections */
429
430 return 0;
431}
432
433static int snd_opl3_set_connection(opl3_t * opl3, int connection)
434{
435 unsigned char reg_val;
436
437 /* OPL-3 only */
438 if (opl3->fm_mode != SNDRV_DM_FM_MODE_OPL3)
439 return -EINVAL;
440
441 reg_val = connection & (OPL3_RIGHT_4OP_0 | OPL3_RIGHT_4OP_1 | OPL3_RIGHT_4OP_2 |
442 OPL3_LEFT_4OP_0 | OPL3_LEFT_4OP_1 | OPL3_LEFT_4OP_2);
443 /* Set 4-op connections */
444 opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT, reg_val);
445
446 return 0;
447}
diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h
new file mode 100644
index 000000000000..63346a5c3498
--- /dev/null
+++ b/sound/drivers/opl3/opl3_voice.h
@@ -0,0 +1,52 @@
1#ifndef __OPL3_VOICE_H
2#define __OPL3_VOICE_H
3
4/*
5 * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <sound/opl3.h>
23
24/* Prototypes for opl3_seq.c */
25int snd_opl3_synth_use_inc(opl3_t * opl3);
26void snd_opl3_synth_use_dec(opl3_t * opl3);
27int snd_opl3_synth_setup(opl3_t * opl3);
28void snd_opl3_synth_cleanup(opl3_t * opl3);
29
30/* Prototypes for opl3_midi.c */
31void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan);
32void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan);
33void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *chan);
34void snd_opl3_terminate_note(void *p, int note, snd_midi_channel_t *chan);
35void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan);
36void snd_opl3_nrpn(void *p, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset);
37void snd_opl3_sysex(void *p, unsigned char *buf, int len, int parsed, snd_midi_channel_set_t *chset);
38
39void snd_opl3_calc_volume(unsigned char *reg, int vel, snd_midi_channel_t *chan);
40void snd_opl3_timer_func(unsigned long data);
41
42/* Prototypes for opl3_drums.c */
43void snd_opl3_load_drums(opl3_t *opl3);
44void snd_opl3_drum_switch(opl3_t *opl3, int note, int on_off, int vel, snd_midi_channel_t *chan);
45
46/* Prototypes for opl3_oss.c */
47#ifdef CONFIG_SND_SEQUENCER_OSS
48void snd_opl3_init_seq_oss(opl3_t *opl3, char *name);
49void snd_opl3_free_seq_oss(opl3_t *opl3);
50#endif
51
52#endif