patch-1.3.34 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

diff -u --recursive --new-file v1.3.33/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
@@ -41,17 +41,7 @@
 #include "opl3.h"
 
 #define MAX_VOICE	18
-#define OFFS_4OP	11	/*
-				   * * * Definitions for the operators OP3 and
-				   * * 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;
-static int      logical_voices[MAX_VOICE] =
-{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+#define OFFS_4OP	11
 
 struct voice_info
   {
@@ -60,78 +50,78 @@
     long            bender_range;
     unsigned long   orig_freq;
     unsigned long   current_freq;
+    int             volume;
     int             mode;
   };
 
-static struct voice_info voices[MAX_VOICE];
-static struct voice_alloc_info *voice_alloc;
-static struct channel_info *chn_info;
+typedef struct opl_devinfo
+  {
+    int             left_io, right_io;
+    int             nr_voice;
+    int             lv_map[MAX_VOICE];
+
+    struct voice_info voc[MAX_VOICE];
+    struct voice_alloc_info *v_alloc;
+    struct channel_info *chn_info;
+
+    struct sbi_instrument i_map[SBFM_MAXINSTR];
+    struct sbi_instrument *act_i[MAX_VOICE];
 
-static struct sbi_instrument *instrmap;
-static struct sbi_instrument *active_instrument[MAX_VOICE] =
-{NULL};
+    struct synth_info fm_info;
 
-static struct synth_info fm_info =
-{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
+    int             busy;
+    int             model;
+    unsigned char   cmask;
 
-static int      already_initialized = 0;
+    int             is_opl4;
+    sound_os_info  *osp;
+  }
+opl_devinfo;
 
-static int      opl3_ok = 0;
-static int      opl3_busy = 0;
-static int      fm_model = 0;	/*
+static struct opl_devinfo *devc = NULL;
 
 
-				 * *  * * 0=no fm, 1=mono, 2=SB Pro 1, 3=SB
-				 * Pro 2 * *    */
+static int      detected_model;
 
 static int      store_instr (int instr_no, struct sbi_instrument *instr);
 static void     freq_to_fnum (int freq, int *block, int *fnum);
 static void     opl3_command (int io_addr, unsigned int addr, unsigned int val);
 static int      opl3_kill_note (int dev, int voice, int note, int velocity);
-static unsigned char connection_mask = 0x00;
 
 void
 enable_opl3_mode (int left, int right, int both)
 {
-  if (opl3_enabled)
-    return;
-
-  opl3_enabled = 1;
-  left_address = left;
-  right_address = right;
-  both_address = both;
-  fm_info.capabilities = SYNTH_CAP_OPL3;
-  fm_info.synth_subtype = FM_TYPE_OPL3;
+  /* NOP */
 }
 
 static void
 enter_4op_mode (void)
 {
   int             i;
-  static int      voices_4op[MAX_VOICE] =
+  static int      v4op[MAX_VOICE] =
   {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
 
-  connection_mask = 0x3f;	/* Connect all possible 4 OP voices */
-  opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f);
+  devc->cmask = 0x3f;		/* Connect all possible 4 OP voice operators */
+  opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f);
 
   for (i = 0; i < 3; i++)
-    physical_voices[i].voice_mode = 4;
+    pv_map[i].voice_mode = 4;
   for (i = 3; i < 6; i++)
-    physical_voices[i].voice_mode = 0;
+    pv_map[i].voice_mode = 0;
 
   for (i = 9; i < 12; i++)
-    physical_voices[i].voice_mode = 4;
+    pv_map[i].voice_mode = 4;
   for (i = 12; i < 15; i++)
-    physical_voices[i].voice_mode = 0;
+    pv_map[i].voice_mode = 0;
 
   for (i = 0; i < 12; i++)
-    logical_voices[i] = voices_4op[i];
-  voice_alloc->max_voice = nr_voices = 12;
+    devc->lv_map[i] = v4op[i];
+  devc->v_alloc->max_voice = devc->nr_voice = 12;
 }
 
 static int
 opl3_ioctl (int dev,
-	    unsigned int cmd, unsigned int arg)
+	    unsigned int cmd, ioctl_arg arg)
 {
   switch (cmd)
     {
@@ -140,12 +130,12 @@
       {
 	struct sbi_instrument ins;
 
-	IOCTL_FROM_USER ((char *) &ins, (char *) arg, 0, sizeof (ins));
+	memcpy_fromfs (((char *) &ins), &(((char *) arg)[0]), (sizeof (ins)));
 
 	if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
 	  {
 	    printk ("FM Error: Invalid instrument number %d\n", ins.channel);
-	    return RET_ERROR (EINVAL);
+	    return -EINVAL;
 	  }
 
 	pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
@@ -154,9 +144,9 @@
       break;
 
     case SNDCTL_SYNTH_INFO:
-      fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
+      devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
 
-      IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
+      memcpy_tofs (&(((char *) arg)[0]), (&devc->fm_info), (sizeof (devc->fm_info)));
       return 0;
       break;
 
@@ -165,19 +155,19 @@
       break;
 
     case SNDCTL_FM_4OP_ENABLE:
-      if (opl3_enabled)
+      if (devc->model == 2)
 	enter_4op_mode ();
       return 0;
       break;
 
     default:
-      return RET_ERROR (EINVAL);
+      return -EINVAL;
     }
 
 }
 
 int
-opl3_detect (int ioaddr)
+opl3_detect (int ioaddr, sound_os_info * osp)
 {
   /*
    * This function returns 1 if the FM chicp is present at the given I/O port
@@ -193,15 +183,10 @@
   unsigned char   stat1, stat2, signature;
   int             i;
 
-  if (already_initialized)
-    {
-      return 0;			/*
-				 * Do avoid duplicate initializations
-				 */
-    }
+  if (devc != NULL)
+    return 0;
 
-  if (opl3_enabled)
-    ioaddr = left_address;
+  devc->osp = osp;
 
   /* Reset timers 1 and 2 */
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
@@ -209,7 +194,7 @@
   /* Reset the IRQ of the FM chip */
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
 
-  signature = stat1 = INB (ioaddr);	/* Status register */
+  signature = stat1 = inb (ioaddr);	/* Status register */
 
   if ((stat1 & 0xE0) != 0x00)
     {
@@ -232,7 +217,7 @@
   for (i = 0; i < 50; i++)
     tenmicrosec ();
 
-  stat2 = INB (ioaddr);		/*
+  stat2 = inb (ioaddr);		/*
 				 * Read status after timers have expired
 				 */
 
@@ -258,18 +243,13 @@
 
   if (signature == 0x06)	/* OPL2 */
     {
-      opl3_enabled = 0;
+      detected_model = 2;
     }
   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;
-	}
+      detected_model = 3;
 
       /*
        * Detect availability of OPL4 (_experimental_). Works propably
@@ -277,14 +257,37 @@
        * 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);
+      opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0x00);
+      opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
 
-      if ((tmp = INB (ioaddr)) == 0x02)		/* Have a OPL4 */
+      if ((tmp = inb (ioaddr)) == 0x02)		/* Have a OPL4 */
 	{
-	  opl4_enabled = 1;
+	  detected_model = 4;
 	}
-      opl3_command (right_address, OPL3_MODE_REGISTER, 0);
+
+      if (!check_region (ioaddr - 8, 2))	/* OPL4 port is free */
+	{
+	  int             tmp;
+
+	  outb (0x02, ioaddr - 8);	/* Select OPL4 ID register */
+	  tenmicrosec ();
+	  tmp = inb (ioaddr - 7);	/* Read it */
+	  tenmicrosec ();
+
+	  if (tmp == 0x20)	/* OPL4 should return 0x20 here */
+	    {
+	      detected_model = 4;
+
+	      outb (0xF8, ioaddr - 8);	/* Select OPL4 FM mixer control */
+	      tenmicrosec ();
+	      outb (0x1B, ioaddr - 7);	/* Write value */
+	      tenmicrosec ();
+	    }
+	  else
+	    detected_model = 3;
+	}
+
+      opl3_command (ioaddr + 2, OPL3_MODE_REGISTER, 0);
 
     }
 
@@ -306,28 +309,29 @@
 {
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return 0;
 
-  voice_alloc->map[voice] = 0;
+  devc->v_alloc->map[voice] = 0;
 
-  map = &physical_voices[logical_voices[voice]];
+  map = &pv_map[devc->lv_map[voice]];
 
   DEB (printk ("Kill note %d\n", voice));
 
   if (map->voice_mode == 0)
     return 0;
 
-  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, voices[voice].keyon_byte & ~0x20);
+  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, devc->voc[voice].keyon_byte & ~0x20);
 
-  voices[voice].keyon_byte = 0;
-  voices[voice].bender = 0;
-  voices[voice].bender_range = 200;	/*
+  devc->voc[voice].keyon_byte = 0;
+  devc->voc[voice].bender = 0;
+  devc->voc[voice].volume = 64;
+  devc->voc[voice].bender_range = 200;	/*
 					 * 200 cents = 2 semitones
 					 */
-  voices[voice].orig_freq = 0;
-  voices[voice].current_freq = 0;
-  voices[voice].mode = 0;
+  devc->voc[voice].orig_freq = 0;
+  devc->voc[voice].current_freq = 0;
+  devc->voc[voice].mode = 0;
 
   return 0;
 }
@@ -344,9 +348,9 @@
 store_instr (int instr_no, struct sbi_instrument *instr)
 {
 
-  if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
+  if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || devc->model != 2))
     printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
-  memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
+  memcpy ((char *) &(devc->i_map[instr_no]), (char *) instr, sizeof (*instr));
 
   return 0;
 }
@@ -354,13 +358,13 @@
 static int
 opl3_set_instr (int dev, int voice, int instr_no)
 {
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return 0;
 
   if (instr_no < 0 || instr_no >= SBFM_MAXINSTR)
     return 0;
 
-  active_instrument[voice] = &instrmap[instr_no];
+  devc->act_i[voice] = &devc->i_map[instr_no];
   return 0;
 }
 
@@ -374,61 +378,33 @@
  * it saves a lot of log() calculations. (RH)
  */
 char            fm_volume_table[128] =
-{-64, -48, -40, -35, -32, -29, -27, -26,	/*
-						 * 0 -   7
-						 */
- -24, -23, -21, -20, -19, -18, -18, -17,	/*
-						 * 8 -  15
-						 */
- -16, -15, -15, -14, -13, -13, -12, -12,	/*
-						 * 16 -  23
-						 */
- -11, -11, -10, -10, -10, -9, -9, -8,	/*
-					 * 24 -  31
-					 */
- -8, -8, -7, -7, -7, -6, -6, -6,	/*
-					   * 32 -  39
-					 */
- -5, -5, -5, -5, -4, -4, -4, -4,	/*
-					   * 40 -  47
-					 */
- -3, -3, -3, -3, -2, -2, -2, -2,	/*
-					   * 48 -  55
-					 */
- -2, -1, -1, -1, -1, 0, 0, 0,	/*
-				 * 56 -  63
-				 */
- 0, 0, 0, 1, 1, 1, 1, 1,	/*
-				 * 64 -  71
-				 */
- 1, 2, 2, 2, 2, 2, 2, 2,	/*
-				 * 72 -  79
-				 */
- 3, 3, 3, 3, 3, 3, 3, 4,	/*
-				 * 80 -  87
-				 */
- 4, 4, 4, 4, 4, 4, 4, 5,	/*
-				 * 88 -  95
-				 */
- 5, 5, 5, 5, 5, 5, 5, 5,	/*
-				 * 96 - 103
-				 */
- 6, 6, 6, 6, 6, 6, 6, 6,	/*
-				 * 104 - 111
-				 */
- 6, 7, 7, 7, 7, 7, 7, 7,	/*
-				 * 112 - 119
-				 */
- 7, 7, 7, 8, 8, 8, 8, 8};	/*
-
-
-				 * *  * * 120 - 127   */
+{-64, -48, -40, -35, -32, -29, -27, -26,
+ -24, -23, -21, -20, -19, -18, -18, -17,
+ -16, -15, -15, -14, -13, -13, -12, -12,
+ -11, -11, -10, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -6, -6, -6,
+ -5, -5, -5, -5, -4, -4, -4, -4,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8};
 
 static void
-calc_vol (unsigned char *regbyte, int volume)
+calc_vol (unsigned char *regbyte, int volume, int main_vol)
 {
   int             level = (~*regbyte & 0x3f);
 
+  if (main_vol > 127)
+    main_vol = 127;
+
+  volume = (volume * main_vol) / 127;
+
   if (level)
     level += fm_volume_table[volume];
 
@@ -441,58 +417,46 @@
 }
 
 static void
-set_voice_volume (int voice, int volume)
+set_voice_volume (int voice, int volume, int main_vol)
 {
   unsigned char   vol1, vol2, vol3, vol4;
   struct sbi_instrument *instr;
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return;
 
-  map = &physical_voices[logical_voices[voice]];
+  map = &pv_map[devc->lv_map[voice]];
 
-  instr = active_instrument[voice];
+  instr = devc->act_i[voice];
 
   if (!instr)
-    instr = &instrmap[0];
+    instr = &devc->i_map[0];
 
   if (instr->channel < 0)
     return;
 
-  if (voices[voice].mode == 0)
+  if (devc->voc[voice].mode == 0)
     return;
 
-  if (voices[voice].mode == 2)
-    {				/*
-				 * 2 OP voice
-				 */
+  if (devc->voc[voice].mode == 2)
+    {
 
       vol1 = instr->operators[2];
       vol2 = instr->operators[3];
 
       if ((instr->operators[10] & 0x01))
-	{			/*
-				 * Additive synthesis
-				 */
-	  calc_vol (&vol1, volume);
-	  calc_vol (&vol2, volume);
+	{
+	  calc_vol (&vol1, volume, main_vol);
+	  calc_vol (&vol2, volume, main_vol);
 	}
       else
-	{			/*
-				 * FM synthesis
-				 */
-	  calc_vol (&vol2, volume);
+	{
+	  calc_vol (&vol2, volume, main_vol);
 	}
 
-      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[0], vol1);
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);
     }
   else
     {				/*
@@ -506,7 +470,7 @@
       vol4 = instr->operators[OFFS_4OP + 3];
 
       /*
-       * The connection method for 4 OP voices is defined by the rightmost
+       * The connection method for 4 OP devc->voc is defined by the rightmost
        * bits at the offsets 10 and 10+OFFS_4OP
        */
 
@@ -515,30 +479,26 @@
       switch (connection)
 	{
 	case 0:
-	  calc_vol (&vol4, volume);	/*
-					 * Just the OP 4 is carrier
-					 */
+	  calc_vol (&vol4, volume, main_vol);
 	  break;
 
 	case 1:
-	  calc_vol (&vol2, volume);
-	  calc_vol (&vol4, volume);
+	  calc_vol (&vol2, volume, main_vol);
+	  calc_vol (&vol4, volume, main_vol);
 	  break;
 
 	case 2:
-	  calc_vol (&vol1, volume);
-	  calc_vol (&vol4, volume);
+	  calc_vol (&vol1, volume, main_vol);
+	  calc_vol (&vol4, volume, main_vol);
 	  break;
 
 	case 3:
-	  calc_vol (&vol1, volume);
-	  calc_vol (&vol3, volume);
-	  calc_vol (&vol4, volume);
+	  calc_vol (&vol1, volume, main_vol);
+	  calc_vol (&vol3, volume, main_vol);
+	  calc_vol (&vol4, volume, main_vol);
 	  break;
 
-	default:		/*
-				 * Why ??
-				 */ ;
+	default:;
 	}
 
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@@ -556,10 +516,10 @@
   struct sbi_instrument *instr;
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return 0;
 
-  map = &physical_voices[logical_voices[voice]];
+  map = &pv_map[devc->lv_map[voice]];
 
   if (map->voice_mode == 0)
     return 0;
@@ -568,7 +528,7 @@
 				 * Just change the volume
 				 */
     {
-      set_voice_volume (voice, volume);
+      set_voice_volume (voice, volume, devc->voc[voice].volume);
       return 0;
     }
 
@@ -596,10 +556,10 @@
 									 * off
 									 */
 
-  instr = active_instrument[voice];
+  instr = devc->act_i[voice];
 
   if (!instr)
-    instr = &instrmap[0];
+    instr = &devc->i_map[0];
 
   if (instr->channel < 0)
     {
@@ -620,7 +580,7 @@
     {
       int             voice_shift;
 
-      voice_shift = (map->ioaddr == left_address) ? 0 : 3;
+      voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3;
       voice_shift += map->voice_num;
 
       if (instr->key != OPL3_PATCH)	/*
@@ -628,14 +588,14 @@
 					 */
 	{
 	  voice_mode = 2;
-	  connection_mask &= ~(1 << voice_shift);
+	  devc->cmask &= ~(1 << voice_shift);
 	}
       else
 	{
-	  connection_mask |= (1 << voice_shift);
+	  devc->cmask |= (1 << voice_shift);
 	}
 
-      opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
+      opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask);
     }
 
   /*
@@ -715,19 +675,19 @@
       opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
     }
 
-  voices[voice].mode = voice_mode;
+  devc->voc[voice].mode = voice_mode;
 
-  set_voice_volume (voice, volume);
+  set_voice_volume (voice, volume, devc->voc[voice].volume);
 
-  freq = voices[voice].orig_freq = note_to_freq (note) / 1000;
+  freq = devc->voc[voice].orig_freq = note_to_freq (note) / 1000;
 
   /*
    * Since the pitch bender may have been set before playing the note, we
    * have to calculate the bending now.
    */
 
-  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
-  voices[voice].current_freq = freq;
+  freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range);
+  devc->voc[voice].current_freq = freq;
 
   freq_to_fnum (freq, &block, &fnum);
 
@@ -741,7 +701,7 @@
   opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
 
   data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
-  voices[voice].keyon_byte = data;
+  devc->voc[voice].keyon_byte = data;
   opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
   if (voice_mode == 4)
     opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
@@ -801,23 +761,17 @@
    * register. The OPL-3 survives with just two INBs
    */
 
-  OUTB ((unsigned char) (addr & 0xff), io_addr);	/*
-							 * Select register
-							 *
-							 */
+  outb ((unsigned char) (addr & 0xff), io_addr);
 
-  if (!opl3_enabled)
+  if (!devc->model != 2)
     tenmicrosec ();
   else
     for (i = 0; i < 2; i++)
-      INB (io_addr);
+      inb (io_addr);
 
-  OUTB ((unsigned char) (val & 0xff), io_addr + 1);	/*
-							 * Write to register
-							 *
-							 */
+  outb ((unsigned char) (val & 0xff), io_addr + 1);
 
-  if (!opl3_enabled)
+  if (devc->model != 2)
     {
       tenmicrosec ();
       tenmicrosec ();
@@ -825,7 +779,7 @@
     }
   else
     for (i = 0; i < 2; i++)
-      INB (io_addr);
+      inb (io_addr);
 }
 
 static void
@@ -833,35 +787,35 @@
 {
   int             i;
 
-  for (i = 0; i < nr_voices; i++)
+  for (i = 0; i < 18; i++)
+    devc->lv_map[i] = i;
+
+  for (i = 0; i < devc->nr_voice; i++)
     {
-      opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff);
+      opl3_command (pv_map[devc->lv_map[i]].ioaddr,
+		    KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff);
 
-      opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);
+      opl3_command (pv_map[devc->lv_map[i]].ioaddr,
+		    KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff);
 
-      if (physical_voices[logical_voices[i]].voice_mode == 4)
+      if (pv_map[devc->lv_map[i]].voice_mode == 4)
 	{
-	  opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff);
+	  opl3_command (pv_map[devc->lv_map[i]].ioaddr,
+			KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff);
 
-	  opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);
+	  opl3_command (pv_map[devc->lv_map[i]].ioaddr,
+			KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff);
 	}
 
       opl3_kill_note (dev, i, 0, 64);
     }
 
-  if (opl3_enabled)
+  if (devc->model == 2)
     {
-      voice_alloc->max_voice = nr_voices = 18;
+      devc->v_alloc->max_voice = devc->nr_voice = 18;
 
       for (i = 0; i < 18; i++)
-	logical_voices[i] = i;
-
-      for (i = 0; i < 18; i++)
-	physical_voices[i].voice_mode = 2;
+	pv_map[i].voice_mode = 2;
 
     }
 
@@ -872,37 +826,35 @@
 {
   int             i;
 
-  if (!opl3_ok)
-    return RET_ERROR (ENXIO);
-  if (opl3_busy)
-    return RET_ERROR (EBUSY);
-  opl3_busy = 1;
+  if (devc->busy)
+    return -EBUSY;
+  devc->busy = 1;
 
-  voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
-  voice_alloc->timestamp = 0;
+  devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
+  devc->v_alloc->timestamp = 0;
 
   for (i = 0; i < 18; i++)
     {
-      voice_alloc->map[i] = 0;
-      voice_alloc->alloc_times[i] = 0;
+      devc->v_alloc->map[i] = 0;
+      devc->v_alloc->alloc_times[i] = 0;
     }
 
-  connection_mask = 0x00;	/*
-				 * Just 2 OP voices
+  devc->cmask = 0x00;		/*
+				 * Just 2 OP mode
 				 */
-  if (opl3_enabled)
-    opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
+  if (devc->model == 2)
+    opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask);
   return 0;
 }
 
 static void
 opl3_close (int dev)
 {
-  opl3_busy = 0;
-  voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+  devc->busy = 0;
+  devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
 
-  fm_info.nr_drums = 0;
-  fm_info.perc_mode = 0;
+  devc->fm_info.nr_drums = 0;
+  devc->fm_info.perc_mode = 0;
 
   opl3_reset (dev);
 }
@@ -913,7 +865,7 @@
 }
 
 static int
-opl3_load_patch (int dev, int format, snd_rw_buf * addr,
+opl3_load_patch (int dev, int format, const snd_rw_buf * addr,
 		 int offs, int count, int pmgr_flag)
 {
   struct sbi_instrument ins;
@@ -921,15 +873,15 @@
   if (count < sizeof (ins))
     {
       printk ("FM Error: Patch record too short\n");
-      return RET_ERROR (EINVAL);
+      return -EINVAL;
     }
 
-  COPY_FROM_USER (&((char *) &ins)[offs], (char *) addr, offs, sizeof (ins) - offs);
+  memcpy_fromfs ((&((char *) &ins)[offs]), &(((char *) addr)[offs]), (sizeof (ins) - offs));
 
   if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
     {
       printk ("FM Error: Invalid instrument number %d\n", ins.channel);
-      return RET_ERROR (EINVAL);
+      return -EINVAL;
     }
   ins.key = format;
 
@@ -959,10 +911,10 @@
   struct sbi_instrument *instr;
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return;
 
-  map = &physical_voices[logical_voices[voice]];
+  map = &pv_map[devc->lv_map[voice]];
 
   DEB (printk ("Aftertouch %d\n", voice));
 
@@ -973,12 +925,12 @@
    * Adjust the amount of vibrato depending the pressure
    */
 
-  instr = active_instrument[voice];
+  instr = devc->act_i[voice];
 
   if (!instr)
-    instr = &instrmap[0];
+    instr = &devc->i_map[0];
 
-  if (voices[voice].mode == 4)
+  if (devc->voc[voice].mode == 4)
     {
       int             connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
 
@@ -1029,21 +981,21 @@
   int             block, fnum, freq;
   struct physical_voice_info *map;
 
-  map = &physical_voices[logical_voices[voice]];
+  map = &pv_map[devc->lv_map[voice]];
 
   if (map->voice_mode == 0)
     return;
 
-  voices[voice].bender = value;
+  devc->voc[voice].bender = value;
   if (!value)
     return;
-  if (!(voices[voice].keyon_byte & 0x20))
+  if (!(devc->voc[voice].keyon_byte & 0x20))
     return;			/*
 				 * Not keyed on
 				 */
 
-  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
-  voices[voice].current_freq = freq;
+  freq = compute_finetune (devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range);
+  devc->voc[voice].current_freq = freq;
 
   freq_to_fnum (freq, &block, &fnum);
 
@@ -1060,14 +1012,14 @@
 								 * of * f-num
 								 *
 								 */
-  voices[voice].keyon_byte = data;
+  devc->voc[voice].keyon_byte = data;
   opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
 }
 
 static void
 opl3_controller (int dev, int voice, int ctrl_num, int value)
 {
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return;
 
   switch (ctrl_num)
@@ -1077,7 +1029,11 @@
       break;
 
     case CTRL_PITCH_BENDER_RANGE:
-      voices[voice].bender_range = value;
+      devc->voc[voice].bender_range = value;
+      break;
+
+    case CTL_MAIN_VOLUME:
+      devc->voc[voice].volume = value / 128;
       break;
     }
 }
@@ -1085,13 +1041,13 @@
 static int
 opl3_patchmgr (int dev, struct patmgr_info *rec)
 {
-  return RET_ERROR (EINVAL);
+  return -EINVAL;
 }
 
 static void
 opl3_bender (int dev, int voice, int value)
 {
-  if (voice < 0 || voice >= nr_voices)
+  if (voice < 0 || voice >= devc->nr_voice)
     return;
 
   bend_pitch (dev, voice, value - 8192);
@@ -1100,7 +1056,7 @@
 static int
 opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
 {
-  int             i, p, best, first, avail_voices, best_time = 0x7fffffff;
+  int             i, p, best, first, avail, best_time = 0x7fffffff;
   struct sbi_instrument *instr;
   int             is4op;
   int             instr_no;
@@ -1108,13 +1064,13 @@
   if (chn < 0 || chn > 15)
     instr_no = 0;
   else
-    instr_no = chn_info[chn].pgm_num;
+    instr_no = devc->chn_info[chn].pgm_num;
 
-  instr = &instrmap[instr_no];
+  instr = &devc->i_map[instr_no];
   if (instr->channel < 0 ||	/* Instrument not loaded */
-      nr_voices != 12)		/* Not in 4 OP mode */
+      devc->nr_voice != 12)	/* Not in 4 OP mode */
     is4op = 0;
-  else if (nr_voices == 12)	/* 4 OP mode */
+  else if (devc->nr_voice == 12)	/* 4 OP mode */
     is4op = (instr->key == OPL3_PATCH);
   else
     is4op = 0;
@@ -1122,15 +1078,15 @@
   if (is4op)
     {
       first = p = 0;
-      avail_voices = 6;
+      avail = 6;
     }
   else
     {
-      if (nr_voices == 12)	/* 4 OP mode. Use the '2 OP only' voices first */
+      if (devc->nr_voice == 12)	/* 4 OP mode. Use the '2 OP only' operators first */
 	first = p = 6;
       else
 	first = p = 0;
-      avail_voices = nr_voices;
+      avail = devc->nr_voice;
     }
 
   /*
@@ -1138,7 +1094,7 @@
    */
   best = first;
 
-  for (i = 0; i < avail_voices; i++)
+  for (i = 0; i < avail; i++)
     {
       if (alloc->map[p] == 0)
 	{
@@ -1149,7 +1105,7 @@
 	  best_time = alloc->alloc_times[p];
 	  best = p;
 	}
-      p = (p + 1) % avail_voices;
+      p = (p + 1) % avail;
     }
 
   /*
@@ -1158,10 +1114,10 @@
 
   if (best < 0)
     best = 0;
-  if (best > nr_voices)
-    best -= nr_voices;
+  if (best > devc->nr_voice)
+    best -= devc->nr_voice;
 
-  return best;			/* All voices in use. Select the first one. */
+  return best;			/* All devc->voc in use. Select the first one. */
 }
 
 static void
@@ -1173,12 +1129,14 @@
   opl3_set_instr (dev, voice,
 		  info->pgm_num);
 
-  voices[voice].bender = info->bender_value;
+  devc->voc[voice].bender = info->bender_value;
+  devc->voc[voice].volume =
+    info->controllers[CTL_MAIN_VOLUME];
 }
 
 static struct synth_operations opl3_operations =
 {
-  &fm_info,
+  NULL,
   0,
   SYNTH_TYPE_FM,
   FM_TYPE_ADLIB,
@@ -1202,71 +1160,97 @@
 };
 
 long
-opl3_init (long mem_start)
+opl3_init (long mem_start, int ioaddr, sound_os_info * osp)
 {
   int             i;
 
-  PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
-		    SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
-
   if (num_synths >= MAX_SYNTH_DEV)
-    printk ("OPL3 Error: Too many synthesizers\n");
+    {
+      printk ("OPL3 Error: Too many synthesizers\n");
+      return mem_start;
+    }
+
+
+  {
+    caddr_t         ptr;
+
+    ptr = sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (*devc), GFP_KERNEL);
+    if (sound_num_blocks < 1024)
+      sound_num_blocks++;
+    devc = (struct opl_devinfo *) ptr;
+  };
+
+  if (devc == NULL)
+    {
+      printk ("OPL3: Can't allocate memory for the device control structure\n");
+      return mem_start;
+    }
+
+  memset ((char *) devc, 0x00, sizeof (*devc));
+  devc->osp = osp;
+
+  devc->nr_voice = 9;
+  strcpy (devc->fm_info.name, "OPL2-");
+
+  devc->fm_info.device = 0;
+  devc->fm_info.synth_type = SYNTH_TYPE_FM;
+  devc->fm_info.synth_subtype = FM_TYPE_ADLIB;
+  devc->fm_info.perc_mode = 0;
+  devc->fm_info.nr_voices = 9;
+  devc->fm_info.nr_drums = 0;
+  devc->fm_info.instr_bank_size = SBFM_MAXINSTR;
+  devc->fm_info.capabilities = 0;
+  devc->left_io = ioaddr;
+  devc->right_io = ioaddr + 2;
+
+  if (detected_model <= 2)
+    devc->model = 1;
   else
     {
-      synth_devs[num_synths++] = &opl3_operations;
-      voice_alloc = &opl3_operations.alloc;
-      chn_info = &opl3_operations.chn_info[0];
+      devc->model = 2;
+      if (detected_model == 4)
+	devc->is_opl4 = 1;
     }
 
-  fm_model = 0;
-  opl3_ok = 1;
-  if (opl3_enabled)
+  opl3_operations.info = &devc->fm_info;
+
+  synth_devs[num_synths++] = &opl3_operations;
+  devc->v_alloc = &opl3_operations.alloc;
+  devc->chn_info = &opl3_operations.chn_info[0];
+
+  if (devc->model == 2)
     {
-      if (opl4_enabled)
+      if (devc->is_opl4)
 	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;
-      strcpy (fm_info.name, "Yamaha OPL-3");
+      devc->v_alloc->max_voice = devc->nr_voice = 18;
+      devc->fm_info.nr_drums = 0;
+      devc->fm_info.capabilities |= SYNTH_CAP_OPL3;
+      strcpy (devc->fm_info.name, "Yamaha OPL-3");
 
       for (i = 0; i < 18; i++)
-	if (physical_voices[i].ioaddr == USE_LEFT)
-	  physical_voices[i].ioaddr = left_address;
+	if (pv_map[i].ioaddr == USE_LEFT)
+	  pv_map[i].ioaddr = devc->left_io;
 	else
-	  physical_voices[i].ioaddr = right_address;
-
+	  pv_map[i].ioaddr = devc->right_io;
 
-      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);	/*
-									 * Enable
-									 * OPL-3
-									 * mode
-									 */
-      opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);	/*
-									 * Select
-									 * all
-									 * 2-OP
-									 * *
-									 * voices
-									 */
+      opl3_command (devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE);
+      opl3_command (devc->right_io, CONNECTION_SELECT_REGISTER, 0x00);
     }
   else
     {
       printk (" <Yamaha 2-OP FM>");
-      fm_model = 1;
-      voice_alloc->max_voice = nr_voices = 9;
-      fm_info.nr_drums = 0;
+      devc->v_alloc->max_voice = devc->nr_voice = 9;
+      devc->fm_info.nr_drums = 0;
 
       for (i = 0; i < 18; i++)
-	physical_voices[i].ioaddr = left_address;
+	pv_map[i].ioaddr = devc->left_io;
     };
 
-  already_initialized = 1;
   for (i = 0; i < SBFM_MAXINSTR; i++)
-    instrmap[i].channel = -1;
+    devc->i_map[i].channel = -1;
 
   return mem_start;
 }

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