Table of Contents
        The FM OPL3 is still used in many chips (mainly for backward
      compatibility). ALSA has a nice OPL3 FM control layer, too. The
      OPL3 API is defined in
      <sound/opl3.h>. 
      
        FM registers can be directly accessed through the direct-FM API,
      defined in <sound/asound_fm.h>. In
      ALSA native mode, FM registers are accessed through
      the Hardware-Dependent Device direct-FM extension API, whereas in
      OSS compatible mode, FM registers can be accessed with the OSS
      direct-FM compatible API in /dev/dmfmX device. 
      
To create the OPL3 component, you have two functions to call. The first one is a constructor for the opl3_t instance.
  struct snd_opl3 *opl3;
  snd_opl3_create(card, lport, rport, OPL3_HW_OPL3_XXX,
                  integrated, &opl3);
          
The first argument is the card pointer, the second one is the left port address, and the third is the right port address. In most cases, the right port is placed at the left port + 2.
The fourth argument is the hardware type.
        When the left and right ports have been already allocated by
      the card driver, pass non-zero to the fifth argument
      (integrated). Otherwise, the opl3 module will
      allocate the specified ports by itself. 
      
        When the accessing the hardware requires special method
        instead of the standard I/O access, you can create opl3 instance
        separately with snd_opl3_new().
        
  struct snd_opl3 *opl3;
  snd_opl3_new(card, OPL3_HW_OPL3_XXX, &opl3);
          
	Then set command,
	private_data and
	private_free for the private
	access function, the private data and the destructor.
	The l_port and r_port are not necessarily set.  Only the
	command must be set properly.  You can retrieve the data
	from the opl3->private_data field.
      
	After creating the opl3 instance via snd_opl3_new(),
	call snd_opl3_init() to initialize the chip to the
	proper state. Note that snd_opl3_create() always
	calls it internally.
      
If the opl3 instance is created successfully, then create a hwdep device for this opl3.
  struct snd_hwdep *opl3hwdep;
  snd_opl3_hwdep_new(opl3, 0, 1, &opl3hwdep);
          
The first argument is the opl3_t instance you created, and the second is the index number, usually 0.
The third argument is the index-offset for the sequencer client assigned to the OPL3 port. When there is an MPU401-UART, give 1 for here (UART always takes 0).