IOCTL90 Physical Device Driver sample source code
From EDM2
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; } } }