patch-1.3.9 linux/drivers/sound/opl3.c
Next file: linux/drivers/sound/opl3.h
Previous file: linux/drivers/sound/mpu401.c
Back to the patch index
Back to the overall index
- Lines: 331
- Date:
Mon Jul 10 01:45:13 1995
- Orig file:
v1.3.8/linux/drivers/sound/opl3.c
- Orig date:
Mon Jul 18 09:50:55 1994
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
@@ -46,6 +46,7 @@
* * OP4 * * begin here */
static int opl3_enabled = 0;
+static int opl4_enabled = 0;
static int left_address = 0x388, right_address = 0x388, both_address = 0;
static int nr_voices = 9;
@@ -189,7 +190,7 @@
* Note2! The chip is initialized if detected.
*/
- unsigned char stat1, stat2;
+ unsigned char stat1, stat2, signature;
int i;
if (already_initialized)
@@ -202,22 +203,13 @@
if (opl3_enabled)
ioaddr = left_address;
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /*
- * Reset
- * timers
- * 1
- * and
- * 2
- */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /*
- * Reset the
- * IRQ of FM
- * * chicp
- */
+ /* Reset timers 1 and 2 */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
- stat1 = INB (ioaddr); /*
- * Read status register
- */
+ /* Reset the IRQ of the FM chip */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
+
+ signature = stat1 = INB (ioaddr); /* Status register */
if ((stat1 & 0xE0) != 0x00)
{
@@ -226,23 +218,19 @@
*/
}
- opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /*
- * Set timer 1 to
- * 0xff
- */
+ opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */
+
opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
TIMER2_MASK | TIMER1_START); /*
* Unmask and start timer 1
*/
/*
- * Now we have to delay at least 80 msec
+ * Now we have to delay at least 80 usec
*/
for (i = 0; i < 50; i++)
- tenmicrosec (); /*
- * To be sure
- */
+ tenmicrosec ();
stat2 = INB (ioaddr); /*
* Read status after timers have expired
@@ -252,18 +240,10 @@
* Stop the timers
*/
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /*
- * Reset
- * timers
- * 1
- * and
- * 2
- */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /*
- * Reset the
- * IRQ of FM
- * * chicp
- */
+ /* Reset timers 1 and 2 */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
+ /* Reset the IRQ of the FM chip */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
if ((stat2 & 0xE0) != 0xc0)
{
@@ -273,9 +253,41 @@
}
/*
- * There is a FM chicp in this address. Now set some default values.
+ * There is a FM chicp in this address. Detect the type (OPL2 to OPL4)
*/
+ if (signature == 0x06) /* OPL2 */
+ {
+ opl3_enabled = 0;
+ }
+ else if (signature == 0x00) /* OPL3 or OPL4 */
+ {
+ unsigned char tmp;
+
+ if (!opl3_enabled) /* Was not already enabled */
+ {
+ left_address = ioaddr;
+ right_address = ioaddr + 2;
+ opl3_enabled = 1;
+ }
+
+ /*
+ * Detect availability of OPL4 (_experimental_). Works propably
+ * only after a cold boot. In addition the OPL4 port
+ * of the chip may not be connected to the PC bus at all.
+ */
+
+ opl3_command (right_address, OPL3_MODE_REGISTER, 0x00);
+ opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
+
+ if ((tmp = INB (ioaddr)) == 0x02) /* Have a OPL4 */
+ {
+ opl4_enabled = 1;
+ }
+ opl3_command (right_address, OPL3_MODE_REGISTER, 0);
+
+ }
+
for (i = 0; i < 9; i++)
opl3_command (ioaddr, KEYON_BLOCK + i, 0); /*
* Note off
@@ -374,14 +386,14 @@
-11, -11, -10, -10, -10, -9, -9, -8, /*
* 24 - 31
*/
- -8, -8, -7, -7, -7, -6, -6, -6,/*
- * 32 - 39
+ -8, -8, -7, -7, -7, -6, -6, -6, /*
+ * 32 - 39
*/
- -5, -5, -5, -5, -4, -4, -4, -4,/*
- * 40 - 47
+ -5, -5, -5, -5, -4, -4, -4, -4, /*
+ * 40 - 47
*/
- -3, -3, -3, -3, -2, -2, -2, -2,/*
- * 48 - 55
+ -3, -3, -3, -3, -2, -2, -2, -2, /*
+ * 48 - 55
*/
-2, -1, -1, -1, -1, 0, 0, 0, /*
* 56 - 63
@@ -473,13 +485,13 @@
calc_vol (&vol2, volume);
}
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /*
- * Modulator
- * volume
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /*
+ * Modulator
+ * volume
*/
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /*
- * Carrier
- * volume
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /*
+ * Carrier
+ * volume
*/
}
else
@@ -526,7 +538,7 @@
default: /*
* Why ??
- */ ;
+ */ ;
}
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@@ -858,12 +870,23 @@
static int
opl3_open (int dev, int mode)
{
+ int i;
+
if (!opl3_ok)
return RET_ERROR (ENXIO);
if (opl3_busy)
return RET_ERROR (EBUSY);
opl3_busy = 1;
+ voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+ voice_alloc->timestamp = 0;
+
+ for (i = 0; i < 18; i++)
+ {
+ voice_alloc->map[i] = 0;
+ voice_alloc->alloc_times[i] = 0;
+ }
+
connection_mask = 0x00; /*
* Just 2 OP voices
*/
@@ -877,6 +900,7 @@
{
opl3_busy = 0;
voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+
fm_info.nr_drums = 0;
fm_info.perc_mode = 0;
@@ -1076,7 +1100,7 @@
static int
opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
{
- int i, p, avail_voices;
+ int i, p, best, first, avail_voices, best_time = 0x7fffffff;
struct sbi_instrument *instr;
int is4op;
int instr_no;
@@ -1097,21 +1121,22 @@
if (is4op)
{
- p = 0;
+ first = p = 0;
avail_voices = 6;
}
else
{
if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */
- p = 6;
+ first = p = 6;
else
- p = 0;
+ first = p = 0;
avail_voices = nr_voices;
}
/*
- * Now try to find a free voice
- */
+ * Now try to find a free voice
+ */
+ best = first;
for (i = 0; i < avail_voices; i++)
{
@@ -1119,15 +1144,36 @@
{
return p;
}
- p = (p + 1) % nr_voices;
+ if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */
+ {
+ best_time = alloc->alloc_times[p];
+ best = p;
+ }
+ p = (p + 1) % avail_voices;
}
/*
- * Insert some kind of priority mechanism here.
- */
+ * Insert some kind of priority mechanism here.
+ */
+
+ if (best < 0)
+ best = 0;
+ if (best > nr_voices)
+ best -= nr_voices;
- printk ("OPL3: Out of free voices\n");
- return 0; /* All voices in use. Select the first one. */
+ return best; /* All voices in use. Select the first one. */
+}
+
+static void
+opl3_setup_voice (int dev, int voice, int chn)
+{
+ struct channel_info *info =
+ &synth_devs[dev]->chn_info[chn];
+
+ opl3_set_instr (dev, voice,
+ info->pgm_num);
+
+ voices[voice].bender = info->bender_value;
}
static struct synth_operations opl3_operations =
@@ -1151,7 +1197,8 @@
opl3_volume_method,
opl3_patchmgr,
opl3_bender,
- opl3_alloc_voice
+ opl3_alloc_voice,
+ opl3_setup_voice
};
long
@@ -1175,14 +1222,16 @@
opl3_ok = 1;
if (opl3_enabled)
{
- printk (" <Yamaha OPL-3 FM>");
+ if (opl4_enabled)
+ printk (" <Yamaha OPL4/OPL3 FM>");
+ else
+ printk (" <Yamaha OPL-3 FM>");
+
fm_model = 2;
voice_alloc->max_voice = nr_voices = 18;
fm_info.nr_drums = 0;
fm_info.capabilities |= SYNTH_CAP_OPL3;
-#ifndef SCO
strcpy (fm_info.name, "Yamaha OPL-3");
-#endif
for (i = 0; i < 18; i++)
if (physical_voices[i].ioaddr == USE_LEFT)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this