Multimedia Subsystem Driver Notification

After the VxD has successfully processed the CONFIG_START message, the multimedia device loader notifies the multimedia subsystem (MMSYSTEM.DLL) that a device node has successfully started. MMSYSTEM loads each of the associated ring-3 drivers and sends a device arrival notification. The ring-3 drivers query the supporting VxD for configuration information and complete the initialization necessary to support the device. The multimedia subsystem is designed to accommodate device nodes that have multiple function traits, such as music synthesis, digital sound support, hardware compression and/or decompression, and mixer support. When a device node is started, MMSYSTEM locates the registry entries for device node and loads the drivers for each supported class.

Note  The changes and additions to the Window 3.1 multimedia device driver model as described below are specific to Windows 95 Plug and Play device drivers. Multimedia drivers loaded using the Windows 3.1 SYSTEM.INI entries will not experience these changes.

A device node might support four driver classes: wave, midi, aux and mixer. Each class may have multiple drivers. MMSYSTEM loads all drivers for all active classes when the device successfully starts. MMSYSTEM loads each module only once and increments reference counts as necessary (standard LoadLibrary() behavior); therefore, a multimedia ring-3 device driver's DriverProc() receives only one DRV_LOAD message when it is first loaded and only one DRV_FREE message when the last reference to the device is released.

A ring-3 device driver should maintain separate data structures for each device node and if the device driver supports multiple classes it should maintain reference counts for each active class. To assist in this task, Windows 95 introduces new parameters for the xxxx_INIT, xxxx_GETNUMDEVS, xxxx_GETDEVCAPS and xxxx_OPEN messages, and introduces new messages: DRVM_ENABLE, DRVM_DISABLE and DRVM_EXIT.

MMSYSTEM sends the xxxx_INIT, DRVM_ENABLE, DRVM_DISABLE and DRVM_EXIT message to each message procedure of each class of device when the corresponding activity has taken place for the device node.

Below is a description of these messages and the appropriate driver response:

When the driver vendor follows the appropriate handling of these messages it is possible to accomplish any or all of the following:

The code example below is the output wave device message handler from the Windows Sound System ring-3 driver. It demonstrates the appropriate handling of these new and modified messages.

DWORD FAR PASCAL _loadds wodMessage
(
    UINT            uDevId,
    WORD            msg,
    DWORD           dwUser,
    DWORD           dwParam1,
    DWORD           dwParam2
)
{
   NPWAVEALLOC         pClient ;
   PHARDWAREINSTANCE   phwi ;

   // take care of init time messages...

   switch (msg)
   {
      case WODM_INIT:
      {
         DPF( 3, "WODM_INIT" ) ;

         if (gwGlobalStatus)
         {
            DisplayConfigErrors() ;
            return 0L ;
         }
         else
         {
            // dwParam2 == PnP DevNode

            return (AddDevNode( dwParam2 )) ;
         }
      }
      break ;

      case DRVM_ENABLE:
      {
         DPF( 3, "WODM_ENABLE" ) ;

         // dwParam2 == PnP DevNode

         return (EnableDevNode( dwParam2 )) ;

      }
      break ;

      case DRVM_DISABLE:
      {
         DPF( 3, "WODM_DISABLE" ) ;

         // dwParam2 == PnP DevNode

         return (DisableDevNode( dwParam2 )) ;

      }
      break ;

      case DRVM_EXIT:
      {
         DPF( 3, "WODM_EXIT" ) ;

         // dwParam2 == PnP DevNode

         return (RemoveDevNode( dwParam2 )) ;

      }
      break ;

      case WODM_GETNUMDEVS:
      {
         DPF( 3, "WODM_GETNUMDEVS" ) ;

         if (NULL == (phwi = DevNodeToHardwareInstance( dwParam1 )))
            return MAKELONG( 0, MMSYSERR_INVALPARAM ) ;

         if (dwParam1)
         {
            if (phwi -> fEnabled)
               return 1L ;
            else
               return 0L ;
         }
         else
            return 0L ;
      }
      break ;

      case WODM_OPEN:
      {
         DWORD  dn ;

         DPF( 3, "WODM_OPEN" ) ;

         if (uDevId > 1)
            return MMSYSERR_BADDEVICEID ;

         dn = ((LPWAVEOPENDESC) dwParam1) -> dnDevNode ;

         if (NULL ==
               (phwi = DevNodeToHardwareInstance(dn)))
         {
            DPF( 1, "devnode not associated with hardware instance???" ) ;
            return MMSYSERR_BADDEVICEID ;
         }

         if (!phwi -> fEnabled)
            return MMSYSERR_NOTENABLED ;

         return (wodOpen(phwi,
                         dwUser,
                         (LPWAVEOPENDESC) dwParam1,
                         dwParam2 )) ;
      }
      break ;

      case WODM_GETDEVCAPS:
      {
         DPF( 3, "WODM_GETDEVCAPS" ) ;

         if (uDevId > 1)
            return MMSYSERR_BADDEVICEID ;

         if (NULL ==
               (phwi = DevNodeToHardwareInstance( dwParam2 )))
         {
            DPF( 1, "devnode not associated with hardware instance???" ) ;
            return MMSYSERR_BADDEVICEID ;
         }

         if (!phwi -> fEnabled)
            return MMSYSERR_NOTENABLED ;

         wodGetDevCaps( phwi, (MDEVICECAPSEX FAR *) dwParam1 ) ;
         return MMSYSERR_NOERROR ;
      }
      break ;
   }
}
   // Note that the remaining cases for this procedure have
   // been removed from this code example. Please see the 
   // MSSNDSYS.DRV example in the DDK for a complete sample.
 

The procedure of unloading the drivers for a device node is the inverse of the load procedure. That is, the ring-3 drivers are notified and unloaded and then MMDEVLDR issues the CONFIG_STOP message to the virtual device driver.