IOCTL90 Physical Device Driver sample source code

From EDM2
Jump to: navigation, search

By Joseph Nord

This page shows example PDD source code for implementing Ioctl90 API in a device driver. Example code follows for Ioctl90 initialization, message dispatch and callback processing.

  • Last API update 16-Dec-1999.
  • Last document update 09-Aug-2003.

For feeback, contact "joe" at this domain

Example Callback initiated by PDD:

// When a mixer application changes a mixer setting, the
// device driver informs all other mixer application of
// the change by posting event semaphores for each application.
void ioctlmixCallback (PSTREAM pStreamThis)
{
   PSTREAM pStream;
   USHORT  usRC;
   ULONG   ulNumPosts;
   ULONG   ulNumPostsLin;
   ULONG   ulHev;

   // To post an event semaphore, we need a linear address
   // of where the kernel should place the post count.
   usRC = DevHelp_VirtToLin (_SS(),
                             (USHORT)(&ulNumPosts),
                             &ulNumPostsLin);
   if (usRC != 0)
   {
      #ifdef CSDEBUG
      ddprintf (ERROR_MONITOR, "ioctlmixCallback VirtToLin failed\n");
      DebugBreakpoint();
      #endif
      return;
   }

   // Each client mixer application creates its own semaphore.
   // The semaphore must be "shared", but it is only shared between
   // the application and this device driver.

   pStream = streamGetListHead();
   while (pStream != NULL)
   {
      // Only signal callback to mixer applications other than
      // the one that commanded the change to the mixer.
      // It already knows about the state change.
      if (pStream != pStreamThis &&
          pStream->ulCallbackSem != 0)
      {
         ulHev = pStream->ulCallbackSem;

         // To post the sem, must open it from device driver.
         // When post a sem, must also reset it or it will post forever
         DevHelp_OpenEventSem (ulHev);
         usRC = DevHelp_PostEventSem (ulHev);
         #ifdef CSDEBUG
         if (usRC != 0)
         {
            ddprintf (ERROR_MONITOR, "ioctlmixCallback PostEvent failed\n");
            DebugBreakpoint();
         }
         #endif
         DevHelp_ResetEventSem (ulHev, ulNumPostsLin);
         DevHelp_CloseEventSem (ulHev);
      }
      pStream = pStream->pNext;
   }
}

Example Device driver Ioctl90 message dispatch:

//
// Array of pointers to functions - dispatch table
//
USHORT (*ioctlmixFuncs[]) (PSTREAM    pStream,
                           PMIXSTRUCT pMix,
                           USHORT     usDLength) =
{
   ioctlmix_MonoInSet,           // 40 Set functions in 0x40 range
   ioctlmix_Unused,              // 41 ioctlmix_PhoneSet
   ioctlmix_MicSet,              // 42
   ioctlmix_LineSet,             // 43
   ioctlmix_CDSet,               // 44
   ioctlmix_Unused,              // 45 ioctlmix_VideoSet
   ioctlmix_AuxSet,              // 46
   ioctlmix_Unused,              // 47
   ioctlmix_Unused,              // 48
   ioctlmix_Unused,              // 49
   ioctlmix_Unused,              // 4A
   ioctlmix_Unused,              // 4B ioctlmix_BassTrebleSet
   ioctlmix_ThreeDSet,           // 4C
   ioctlmix_StreamVolSet,        // 4D
   ioctlmix_RecordSrcSet,        // 4E
   ioctlmix_RecordGainSet,       // 4F
   ioctlmix_Unused,              // 50
   ioctlmix_Unused,              // 51
   ioctlmix_Unused,              // 52
   ioctlmix_Unused,              // 53
   ioctlmix_Unused,              // 54
   ioctlmix_Unused,              // 55
   ioctlmix_Unused,              // 56
   ioctlmix_Unused,              // 57
   ioctlmix_Unused,              // 58
   ioctlmix_Unused,              // 59
   ioctlmix_Unused,              // 5A
   ioctlmix_Unused,              // 5B
   ioctlmix_Unused,              // 5C
   ioctlmix_Unused,              // 5D
   ioctlmix_Unused,              // 5E
   ioctlmix_Unused,              // 5F
   ioctlmix_MonoInQuery,         // 60 Query functions in 0x40 range
   ioctlmix_Unused,              // 61 ioctlmix_PhoneQuery
   ioctlmix_MicQuery,            // 62
   ioctlmix_LineQuery,           // 63
   ioctlmix_CDQuery,             // 64
   ioctlmix_Unused,              // 65 ioctlmix_VideoQuery
   ioctlmix_AuxQuery,            // 66
   ioctlmix_Unused,              // 67
   ioctlmix_Unused,              // 68
   ioctlmix_Unused,              // 69
   ioctlmix_Unused,              // 6A
   ioctlmix_Unused,              // 6B ioctlmix_BassTrebleQuery
   ioctlmix_ThreeDQuery,         // 6C
   ioctlmix_StreamVolQuery,      // 6D
   ioctlmix_RecordSrcQuery,      // 6E
   ioctlmix_RecordGainQuery,     // 6F
   ioctlmix_Unused,              // 70
   ioctlmix_Unused,              // 71
   ioctlmix_Unused,              // 72
   ioctlmix_Unused,              // 73
   ioctlmix_Unused,              // 74
   ioctlmix_Unused,              // 75
   ioctlmix_Unused,              // 76
   ioctlmix_Unused,              // 77
   ioctlmix_Unused,              // 78
   ioctlmix_Unused,              // 79
   ioctlmix_Unused,              // 7A
   ioctlmix_Unused,              // 7B
   ioctlmix_Unused,              // 7C
   ioctlmix_Unused,              // 7D
   ioctlmix_Unused,              // 7E
   ioctlmix_Unused,              // 7F
   ioctlmix_APILevelQuery,       // 80
   ioctlmix_GetAPIMap,           // 81
   ioctlmix_CallbackReg,         // 82
   ioctlmix_MsgBuf               // 83
};
BYTE MaxIoctlmixFuncs = sizeof(ioctlmixFuncs)/sizeof(ioctlmixFuncs[0])-1;


// This function services all audio control requests from the ioctl
// interface.
// The parameter 'function' is number of the request. The parameter 'bufP'
// is a pointer to a buffer containing information specific to the request.
// The parameter 'sys_file_num' contains the system file number unique to
// the session issuing the ioctl.
// The function returns information specific to the request in the buffer
// pointed to by 'bufP'. Also, the function returns the value 0 if successful.

USHORT ioctlmixMain (USHORT Function,
                     USHORT SysFileNum,
                     PVOID  pvData,
                     USHORT usDLength)
{
   PSTREAM  pStream;
   USHORT   usRC;

   Function -= 0x40;    // Function numbers start at 0x40.

   if (Function > MaxIoctlmixFuncs)
   {
      usRC = RPBADCMD;
   }
   else
   {
      // get the stream pointer from the system file number
      pStream = streamGetFromSysFileNum (SysFileNum);
      if (pStream == NULL)
      {
         // If open/close logic is working, this error
         // case should never happen.
        #ifdef CSDEBUG
         ddprintf (ERROR_MONITOR,
                    "IOCTL: Main - Stream lookup failed, sysfile %x\n",
                    SysFileNum);
        #endif
         usRC = RPGENFAIL;
      }
      else if (pvData == NULL)
      {
         #ifdef CSDEBUG
         ddprintf (ERROR_MONITOR,
                   "ERR: ioctlmixMain pvData is NULL.\n");
         #endif
         usRC = RPINVPARM;
      }
      else
      {
         usRC = ioctlmixFuncs [Function] (pStream,
                                          (PMIXSTRUCT)pvData,
                                          usDLength);
      }
   }

   return (usRC);
}

Example device driver Ioctl90 initialization:

void ioctlmixInit (void)
{
   unsigned I;

   // Verify that ioctlmixCheckTable has correct number of entries.
   // That is, runtime verify that positions in dispatch table are
   // consistent with header file defines for use by applications.
   if (MaxIoctlmixFuncs != MSGBUF - 0x40)
   {
      #ifdef CSDEBUG
      ddprintf (ERROR_MONITOR,
                "ioctlmixInit Dispatch table size is wrong!!!\n");
      #endif

      ProductionBreakpoint();
   }

   // Ability to support 3D sound effect is not supported
   // on all the hardware configurations.
   if (!mix3DSupported())
   {
      ioctlmixFuncs[THREEDSET-0x40] = ioctlmix_Unused;
      ioctlmixFuncs[THREEDQUERY-0x40] = ioctlmix_Unused;
   }

   // Fill in bSupport table.  Indicate which of the
   // possible 256 IOCTL functions this driver supports.

   for (I = 0; I <= 0xFF; I++)
   {
      if (I >= 0x40 && I - 0x40 <= MaxIoctlmixFuncs)
      {
         // A function is "supported" if it has an entry in dispatch table.
         ioctl90SupportTable[I] = (ioctlmixFuncs[I-0x40] != ioctlmix_Unused);
      }
      else
      {
         // All entries outside our table bounds are not supported.
         ioctl90SupportTable[I] = FALSE;
      }
   }
}