IOCTL90 Physical Device Driver sample source code

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.

For feeback, contact "joe" at this domain
 * Last API update 16-Dec-1999.
 * Last document update 09-Aug-2003.

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; }  } } 