Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

988 lines
30 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: mixer.c
  4. //
  5. // Description:
  6. // Contains the kernel mode portion of the mixer line driver.
  7. //
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // D. Baumberger
  12. //
  13. // History: Date Author Comment
  14. //
  15. //@@END_MSINTERNAL
  16. //
  17. //---------------------------------------------------------------------------
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "wdmdrv.h"
  28. #include "mixer.h"
  29. #ifndef UNDER_NT
  30. extern volatile BYTE cPendingOpens;
  31. extern volatile BYTE fExiting;
  32. #else
  33. HANDLE serializemixerapi=NULL;
  34. SECURITY_ATTRIBUTES mutexsecurity;
  35. SECURITY_DESCRIPTOR mutexdescriptor;
  36. #endif
  37. LPMIXERINSTANCE pMixerDeviceList = NULL;
  38. #ifdef UNDER_NT
  39. #define MXDM_GETHARDWAREEVENTDATA 0xffffffff
  40. HANDLE mixercallbackevent=NULL;
  41. HANDLE mixerhardwarecallbackevent=NULL;
  42. HANDLE mixercallbackthread=NULL;
  43. DWORD mixerthreadid=0;
  44. ULONG localindex=0;
  45. extern PCALLBACKS gpCallbacks;
  46. extern DWORD sndTranslateStatus();
  47. #pragma data_seg()
  48. #define StoreCallback(Type,Id) {\
  49. if (gpCallbacks) {\
  50. gpCallbacks->Callbacks[gpCallbacks->GlobalIndex%CALLBACKARRAYSIZE].dwCallbackType = Type;\
  51. gpCallbacks->Callbacks[gpCallbacks->GlobalIndex%CALLBACKARRAYSIZE].dwID = Id;\
  52. gpCallbacks->GlobalIndex++;\
  53. }\
  54. };
  55. ULONG GetGlobalCallbackIndex()
  56. {
  57. if (gpCallbacks != NULL) {
  58. return(gpCallbacks->GlobalIndex);
  59. }
  60. return (0);
  61. }
  62. BOOLEAN
  63. CallbacksExist
  64. (
  65. ULONG localindex,
  66. DWORD *Type,
  67. DWORD *Id
  68. )
  69. {
  70. if (gpCallbacks == NULL) {
  71. return (FALSE);
  72. }
  73. if (localindex < gpCallbacks->GlobalIndex) {
  74. *Type = gpCallbacks->Callbacks[localindex%CALLBACKARRAYSIZE].dwCallbackType;
  75. *Id = gpCallbacks->Callbacks[localindex%CALLBACKARRAYSIZE].dwID;
  76. return (TRUE);
  77. }
  78. else {
  79. return (FALSE);
  80. }
  81. }
  82. ///////////////////////////////////////////////////////////////////////
  83. //
  84. // MIXERCOMPLETE
  85. //
  86. // Receives the callbacks from the kernel and calls all the clients.
  87. //
  88. //
  89. #define MIXER_CONTROL_CALLBACK 0x01
  90. #define MIXER_LINE_CALLBACK 0x02
  91. VOID MIXERCOMPLETE
  92. (
  93. ULONG index,
  94. DWORD dwID,
  95. DWORD dwCallbackType
  96. )
  97. {
  98. LPMIXERINSTANCE lpInstance;
  99. LPMIXERINSTANCE deletelpInstance=NULL;
  100. // We have to syncronize the access to the instance list with the mixer
  101. // close code that removes elements from this list, and with the mixer
  102. // open code that adds elements to this list. The easiest way to do
  103. // this is to use our global mixer api serialization mutex.
  104. WaitForSingleObject(serializemixerapi,INFINITE);
  105. // DPF( (2, "<----" ) );
  106. for (lpInstance = pMixerDeviceList;
  107. lpInstance != NULL;
  108. lpInstance = lpInstance->Next
  109. ) {
  110. ISVALIDMIXERINSTANCE(lpInstance);
  111. if (deletelpInstance!=NULL) {
  112. #ifdef DEBUG
  113. deletelpInstance->dwSig=0;
  114. #endif
  115. GlobalFreePtr( deletelpInstance );
  116. deletelpInstance=NULL;
  117. }
  118. // Wait until the index is at the first callback data
  119. // for this instance before allowing any callbacks. If
  120. // we are at the first callback data then allow all
  121. // future callbacks.
  122. if (lpInstance->firstcallbackindex) {
  123. if (index<lpInstance->firstcallbackindex) {
  124. continue;
  125. }
  126. else {
  127. lpInstance->firstcallbackindex=0;
  128. }
  129. }
  130. InterlockedIncrement(&lpInstance->referencecount);
  131. if( dwCallbackType == MIXER_CONTROL_CALLBACK ) {
  132. /*
  133. DPF( (2, "MIXER_CONTROL_CALLBACK(%lX,%lX,%lX,%lX)",
  134. dwID,
  135. lpInstance->OpenDesc_dwCallback,
  136. lpInstance->OpenDesc_hmx,
  137. lpInstance->OpenDesc_dwInstance
  138. )
  139. );
  140. */
  141. ReleaseMutex(serializemixerapi);
  142. DriverCallback( lpInstance->OpenDesc_dwCallback,
  143. DCB_FUNCTION,
  144. lpInstance->OpenDesc_hmx,
  145. MM_MIXM_CONTROL_CHANGE,
  146. lpInstance->OpenDesc_dwInstance,
  147. dwID,
  148. 0L
  149. );
  150. WaitForSingleObject(serializemixerapi,INFINITE);
  151. } else if( dwCallbackType == MIXER_LINE_CALLBACK ) {
  152. /*
  153. DPF( (2, "MIXER_LINE_CALLBACK(%lX,%lX,%lX,%lX)",
  154. dwID,
  155. lpInstance->OpenDesc_dwCallback,
  156. lpInstance->OpenDesc_hmx,
  157. lpInstance->OpenDesc_dwInstance
  158. )
  159. );
  160. */
  161. ReleaseMutex(serializemixerapi);
  162. DriverCallback( lpInstance->OpenDesc_dwCallback,
  163. DCB_FUNCTION,
  164. lpInstance->OpenDesc_hmx,
  165. MM_MIXM_LINE_CHANGE,
  166. lpInstance->OpenDesc_dwInstance,
  167. dwID,
  168. 0L
  169. );
  170. WaitForSingleObject(serializemixerapi,INFINITE);
  171. } else {
  172. //
  173. // The callback wasn't one that is recognized. Just
  174. // return and abort the loop
  175. //
  176. // DPF( (2, "Invalid Mixer Callback -- %d!", dwCallbackType) );
  177. if (InterlockedDecrement(&lpInstance->referencecount)<0) {
  178. deletelpInstance=lpInstance;
  179. }
  180. DPFASSERT(0);
  181. break;
  182. }
  183. if (InterlockedDecrement(&lpInstance->referencecount)<0) {
  184. deletelpInstance=lpInstance;
  185. }
  186. }
  187. // DPF( (2, "---->" ) );
  188. if (deletelpInstance!=NULL) {
  189. #ifdef DEBUG
  190. deletelpInstance->dwSig=0;
  191. #endif
  192. GlobalFreePtr( deletelpInstance );
  193. deletelpInstance=NULL;
  194. }
  195. ReleaseMutex(serializemixerapi);
  196. }
  197. DWORD
  198. WINAPI
  199. MixerCallbackThread(
  200. LPVOID lpParamNotUsed
  201. )
  202. {
  203. MMRESULT status=MMSYSERR_NOERROR;
  204. DWORD dwID;
  205. WORD wCallbackType;
  206. HANDLE callbackevents[2];
  207. DWORD index;
  208. DWORD Type, Id;
  209. // Setup the handles array.
  210. callbackevents[0]=mixerhardwarecallbackevent;
  211. callbackevents[1]=mixercallbackevent;
  212. if (!SetThreadPriority(mixercallbackthread,THREAD_PRIORITY_TIME_CRITICAL)) {
  213. status=GetLastError();
  214. }
  215. while (1) {
  216. // Block until a callback may be needed.
  217. index=WaitForMultipleObjects(2,callbackevents,FALSE,INFINITE);
  218. // Did hardware event happen? If so get the new data.
  219. if (index==0) {
  220. mxdMessage(0,MXDM_GETHARDWAREEVENTDATA,0,0,0);
  221. }
  222. // Scan through all new callbacks - looking for any that
  223. // we need to make for this process.
  224. while (CallbacksExist(localindex,&Type, &Id)) {
  225. DPF(DL_TRACE|FA_EVENT, ("Thrd id %d, lindex %d, gindex %d, dwid %d, cbtype %d ",
  226. mixerthreadid,
  227. localindex,
  228. gpCallbacks->GlobalIndex,
  229. Id,
  230. Type
  231. ));
  232. MIXERCOMPLETE(localindex, Id, Type);
  233. localindex++;
  234. }
  235. }
  236. return ERROR_SUCCESS;
  237. }
  238. MMRESULT SetupMixerCallbacks(VOID)
  239. {
  240. MMRESULT status=MMSYSERR_NOERROR;
  241. // First get a handle to a named global callback event so that
  242. // the callback threads can block.
  243. if (NULL==mixercallbackevent) {
  244. // First assume event exists and try to open it.
  245. // This will succeed in all cases except the very first
  246. // time it is run.
  247. mixercallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\mixercallback");
  248. if (NULL==mixercallbackevent) {
  249. // Didn't exist, so now create it.
  250. SECURITY_ATTRIBUTES SecurityAttributes;
  251. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  252. // First build the required security descriptor.
  253. pSecurityDescriptor=BuildSecurityDescriptor(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
  254. if(pSecurityDescriptor==NULL) {
  255. status= sndTranslateStatus();
  256. return status;
  257. }
  258. //
  259. // Create an event such that all processes have access to it.
  260. //
  261. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  262. SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  263. SecurityAttributes.bInheritHandle = FALSE;
  264. mixercallbackevent=CreateEvent(&SecurityAttributes, TRUE, FALSE, L"Global\\mixercallback");
  265. // Now free the security descriptor memory we allocated.
  266. DestroySecurityDescriptor(pSecurityDescriptor);
  267. if (NULL==mixercallbackevent) {
  268. // Handle the race condition that exists when 2
  269. // threads both try to Create and only the first succeeds.
  270. mixercallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\mixercallback");
  271. if (NULL==mixercallbackevent) {
  272. status= sndTranslateStatus();
  273. return status;
  274. }
  275. }
  276. }
  277. }
  278. // Now get a handle to the global hardware callback event.
  279. if (NULL==mixerhardwarecallbackevent) {
  280. // First assume event exists and try to open it.
  281. // This will succeed in all cases except the very first
  282. // time it is run.
  283. mixerhardwarecallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\hardwaremixercallback");
  284. if (NULL==mixerhardwarecallbackevent) {
  285. // Didn't exist, so now create it.
  286. SECURITY_ATTRIBUTES SecurityAttributes;
  287. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  288. // First build the required security descriptor.
  289. pSecurityDescriptor=BuildSecurityDescriptor(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
  290. if(pSecurityDescriptor==NULL) {
  291. status= sndTranslateStatus();
  292. return status;
  293. }
  294. //
  295. // Create an event such that all processes have access to it.
  296. //
  297. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  298. SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  299. SecurityAttributes.bInheritHandle = FALSE;
  300. // Note that this event releases only 1 thread at a time
  301. // whereas the other callback event releases them all!
  302. mixerhardwarecallbackevent=CreateEvent(&SecurityAttributes, FALSE, FALSE, L"Global\\hardwaremixercallback");
  303. // Now free the security descriptor memory we allocated.
  304. DestroySecurityDescriptor(pSecurityDescriptor);
  305. if (NULL==mixerhardwarecallbackevent) {
  306. // Handle the race condition that exists when 2
  307. // threads both try to Create and only the first succeeds.
  308. mixerhardwarecallbackevent=OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, L"Global\\hardwaremixercallback");
  309. if (NULL==mixerhardwarecallbackevent) {
  310. status= sndTranslateStatus();
  311. return status;
  312. }
  313. }
  314. }
  315. }
  316. // Now create a thread in this process for making the
  317. // callbacks if not already done.
  318. if ( NULL == mixercallbackthread ) {
  319. mixercallbackthread=CreateThread(NULL, 0, MixerCallbackThread, NULL, CREATE_SUSPENDED, &mixerthreadid);
  320. if ( NULL == mixercallbackthread ) {
  321. status= sndTranslateStatus();
  322. return status;
  323. } else {
  324. // if we successfully created the thread, we can now activate it.
  325. if( ResumeThread(mixercallbackthread) == -1 ) {
  326. status= sndTranslateStatus();
  327. return status;
  328. }
  329. }
  330. }
  331. return status;
  332. }
  333. #endif // UNDER_NT
  334. //--------------------------------------------------------------------------
  335. // LPDEVICEINFO AllocMixerDeviceInfo
  336. //--------------------------------------------------------------------------
  337. LPDEVICEINFO GlobalAllocMixerDeviceInfo(LPWSTR DeviceInterface, UINT id, DWORD_PTR dwKernelInstance)
  338. {
  339. LPDEVICEINFO pDeviceInfo;
  340. pDeviceInfo = GlobalAllocDeviceInfo(DeviceInterface);
  341. if (pDeviceInfo)
  342. {
  343. pDeviceInfo->dwInstance = dwKernelInstance;
  344. pDeviceInfo->DeviceNumber = id;
  345. pDeviceInfo->DeviceType = MixerDevice;
  346. pDeviceInfo->dwCallbackType = 0;
  347. pDeviceInfo->ControlCallbackCount=0;
  348. #ifndef UNDER_NT
  349. pDeviceInfo->dwFormat = ANSI_TAG;
  350. #else
  351. pDeviceInfo->dwFormat = UNICODE_TAG;
  352. #endif // !UNDER_NT
  353. }
  354. return pDeviceInfo;
  355. }
  356. ///////////////////////////////////////////////////////////////////////
  357. //
  358. // mxdMessage
  359. //
  360. //
  361. DWORD FAR PASCAL _loadds mxdMessage
  362. (
  363. UINT id, // The device Id the message is for
  364. UINT msg, // The message to perform
  365. DWORD_PTR dwUser, // The instance data.
  366. DWORD_PTR dwParam1, // Message specific parameter 1
  367. DWORD_PTR dwParam2 // Message specific parmaeter 2
  368. )
  369. {
  370. MMRESULT mmr;
  371. ULONG initialcallbackindex;
  372. if (NULL==serializemixerapi)
  373. {
  374. //
  375. // To synchronize between this routine and the MixerCallbackThread we
  376. // want a process specific mutex. Thus, we create one the first time
  377. // through.
  378. //
  379. serializemixerapi=CreateMutex(NULL,FALSE,NULL);
  380. if (NULL==serializemixerapi)
  381. {
  382. MMRRETURN( MMSYSERR_NOMEM );
  383. }
  384. }
  385. WaitForSingleObject(serializemixerapi,INFINITE);
  386. initialcallbackindex=GetGlobalCallbackIndex();
  387. switch (msg)
  388. {
  389. ///////////////////////////////////////////////////////////////
  390. case MXDM_INIT:
  391. ///////////////////////////////////////////////////////////////
  392. mmr=wdmaudAddRemoveDevNode( MixerDevice, (LPCWSTR)dwParam2, TRUE);
  393. break;
  394. ///////////////////////////////////////////////////////////////
  395. case DRVM_EXIT:
  396. ///////////////////////////////////////////////////////////////
  397. mmr=wdmaudAddRemoveDevNode( MixerDevice, (LPCWSTR)dwParam2, FALSE);
  398. break;
  399. ///////////////////////////////////////////////////////////////
  400. case MXDM_GETNUMDEVS:
  401. ///////////////////////////////////////////////////////////////
  402. DPF(DL_TRACE|FA_MIXER, ("MIXM_GETNUMDEVS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  403. mmr=wdmaudGetNumDevs(MixerDevice, (LPCWSTR)dwParam1);
  404. break;
  405. ///////////////////////////////////////////////////////////////
  406. case MXDM_GETDEVCAPS:
  407. ///////////////////////////////////////////////////////////////
  408. {
  409. LPDEVICEINFO pDeviceInfo;
  410. DPF(DL_TRACE|FA_MIXER, ("MIXM_GETDEVCAPS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  411. pDeviceInfo = GlobalAllocMixerDeviceInfo((LPWSTR)dwParam2, id, 0);
  412. if (pDeviceInfo) {
  413. mmr = wdmaudGetDevCaps(pDeviceInfo, (MDEVICECAPSEX FAR*)dwParam1);
  414. GlobalFreeDeviceInfo(pDeviceInfo);
  415. }
  416. else {
  417. mmr = MMSYSERR_NOMEM;
  418. }
  419. }
  420. break;
  421. ///////////////////////////////////////////////////////////////
  422. case MXDM_OPEN:
  423. ///////////////////////////////////////////////////////////////
  424. {
  425. LPMIXEROPENDESC pMixerOpenDesc = (LPMIXEROPENDESC)dwParam1;
  426. LPMIXERINSTANCE pMixerInstance;
  427. DPF(DL_TRACE|FA_MIXER, ("MIXM_OPEN(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  428. pMixerInstance = (LPMIXERINSTANCE) GlobalAllocPtr(
  429. GPTR | GMEM_SHARE,
  430. sizeof( MIXERINSTANCE ) + (sizeof(WCHAR)*lstrlenW((LPWSTR)pMixerOpenDesc->dnDevNode)));
  431. if( pMixerInstance == NULL ) {
  432. mmr=MMSYSERR_NOMEM;
  433. break;
  434. }
  435. pMixerInstance->referencecount=0;
  436. #ifdef DEBUG
  437. pMixerInstance->dwSig=MIXERINSTANCE_SIGNATURE;
  438. #endif
  439. if (mixercallbackthread==NULL) {
  440. localindex=GetGlobalCallbackIndex();
  441. }
  442. pMixerInstance->firstcallbackindex=GetGlobalCallbackIndex();
  443. if (mixercallbackthread==NULL) {
  444. if ((mmr=SetupMixerCallbacks())!=MMSYSERR_NOERROR) {
  445. GlobalFreePtr( pMixerInstance );
  446. break;
  447. }
  448. }
  449. // We allocate a DEVICEINFO and MIXEROPENDESC with GlobalAlloc so
  450. // that on Win98 it is in system global memory. This is necessary
  451. // because the following IOCTL is async on Win98. This isn't really
  452. // necessary on NT 5, but in the interest of common sources we do it
  453. // this way even on NT 5.
  454. pMixerOpenDesc = GlobalAllocPtr(GPTR, sizeof(*pMixerOpenDesc));
  455. if (pMixerOpenDesc) {
  456. LPDEVICEINFO pDeviceInfo;
  457. // Copy the input MIXEROPENDESC to our globally allocated MIXEROPENDESC
  458. *pMixerOpenDesc = *((LPMIXEROPENDESC)dwParam1);
  459. pDeviceInfo = GlobalAllocMixerDeviceInfo((LPWSTR)pMixerOpenDesc->dnDevNode, id, 0);
  460. if (pDeviceInfo) {
  461. pDeviceInfo->dwFlags = (DWORD)dwParam2;
  462. pDeviceInfo->HardwareCallbackEventHandle=0;
  463. if (mixerhardwarecallbackevent) {
  464. pDeviceInfo->HardwareCallbackEventHandle=mixerhardwarecallbackevent;
  465. }
  466. pDeviceInfo->mmr = MMSYSERR_ERROR;
  467. mmr = wdmaudIoControl(pDeviceInfo,
  468. 0,
  469. NULL,
  470. IOCTL_WDMAUD_MIXER_OPEN);
  471. EXTRACTERROR(mmr,pDeviceInfo);
  472. if (MMSYSERR_NOERROR == mmr) {
  473. // Fill in the MixerInstance structure
  474. pMixerInstance->Next = NULL;
  475. pMixerInstance->OpenDesc_hmx = (HDRVR)pMixerOpenDesc->hmx;
  476. pMixerInstance->OpenDesc_dwCallback = pMixerOpenDesc->dwCallback;
  477. pMixerInstance->OpenDesc_dwInstance = pMixerOpenDesc->dwInstance;
  478. pMixerInstance->OpenFlags = (DWORD)dwParam2;
  479. lstrcpyW(pMixerInstance->wstrDeviceInterface, (LPWSTR)pMixerOpenDesc->dnDevNode);
  480. pMixerInstance->dwKernelInstance = pDeviceInfo->dwInstance;
  481. }
  482. GlobalFreeDeviceInfo(pDeviceInfo);
  483. pDeviceInfo = NULL;
  484. }
  485. else {
  486. mmr = MMSYSERR_NOMEM;
  487. }
  488. GlobalFreePtr(pMixerOpenDesc);
  489. pMixerOpenDesc = NULL;
  490. }
  491. else {
  492. mmr = MMSYSERR_NOMEM;
  493. }
  494. if( mmr == MMSYSERR_NOERROR ) {
  495. pMixerInstance->Next = pMixerDeviceList;
  496. pMixerDeviceList = pMixerInstance;
  497. *((PDWORD_PTR) dwUser) = (DWORD_PTR) pMixerInstance;
  498. // Sanity check that we put a valid mixer instance structure in the list.
  499. ISVALIDMIXERINSTANCE(pMixerInstance);
  500. }
  501. else {
  502. #ifdef DEBUG
  503. pMixerInstance->dwSig=0;
  504. #endif
  505. GlobalFreePtr( pMixerInstance );
  506. }
  507. }
  508. break;
  509. ///////////////////////////////////////////////////////////////
  510. case MXDM_CLOSE:
  511. ///////////////////////////////////////////////////////////////
  512. {
  513. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  514. LPDEVICEINFO pDeviceInfo;
  515. DPF(DL_TRACE|FA_MIXER, ("MIXM_CLOSE(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  516. if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR)
  517. break;
  518. pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
  519. if (pDeviceInfo) {
  520. mxdRemoveClient( pInstance );
  521. pDeviceInfo->mmr = MMSYSERR_ERROR;
  522. mmr = wdmaudIoControl(
  523. pDeviceInfo,
  524. 0,
  525. NULL,
  526. IOCTL_WDMAUD_MIXER_CLOSE
  527. );
  528. EXTRACTERROR(mmr,pDeviceInfo);
  529. GlobalFreeDeviceInfo(pDeviceInfo);
  530. }
  531. else {
  532. mmr = MMSYSERR_NOMEM;
  533. }
  534. }
  535. break;
  536. ///////////////////////////////////////////////////////////////
  537. case MXDM_GETLINEINFO:
  538. ///////////////////////////////////////////////////////////////
  539. {
  540. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  541. LPDEVICEINFO pDeviceInfo;
  542. DPF(DL_TRACE|FA_MIXER, ("MIXM_GETLINEINFO(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  543. if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR)
  544. break;
  545. pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
  546. if (pDeviceInfo) {
  547. pDeviceInfo->dwFlags = (DWORD)dwParam2;
  548. pDeviceInfo->mmr = MMSYSERR_ERROR;
  549. mmr = wdmaudIoControl(
  550. pDeviceInfo,
  551. ((LPMIXERLINE) dwParam1)->cbStruct,
  552. (LPVOID) dwParam1,
  553. IOCTL_WDMAUD_MIXER_GETLINEINFO
  554. );
  555. EXTRACTERROR(mmr,pDeviceInfo);
  556. GlobalFreeDeviceInfo(pDeviceInfo);
  557. }
  558. else {
  559. mmr = MMSYSERR_NOMEM;
  560. }
  561. }
  562. break;
  563. ///////////////////////////////////////////////////////////////
  564. case MXDM_GETLINECONTROLS:
  565. ///////////////////////////////////////////////////////////////
  566. {
  567. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  568. LPDEVICEINFO pDeviceInfo;
  569. DPF(DL_TRACE|FA_MIXER, ("MIXM_GETLINECONTROLS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  570. if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR)
  571. break;
  572. pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
  573. if (pDeviceInfo) {
  574. pDeviceInfo->dwFlags = (DWORD)dwParam2;
  575. pDeviceInfo->mmr = MMSYSERR_ERROR;
  576. mmr = wdmaudIoControl(
  577. pDeviceInfo,
  578. ((LPMIXERLINECONTROLS) dwParam1)->cbStruct,
  579. (LPVOID) dwParam1,
  580. IOCTL_WDMAUD_MIXER_GETLINECONTROLS
  581. );
  582. EXTRACTERROR(mmr,pDeviceInfo);
  583. GlobalFreeDeviceInfo(pDeviceInfo);
  584. }
  585. else {
  586. mmr = MMSYSERR_NOMEM;
  587. }
  588. }
  589. break;
  590. ///////////////////////////////////////////////////////////////
  591. case MXDM_GETCONTROLDETAILS:
  592. ///////////////////////////////////////////////////////////////
  593. {
  594. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  595. LPDEVICEINFO pDeviceInfo;
  596. DPF(DL_TRACE|FA_MIXER, ("MIXM_GETCONTROLDETAILS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  597. if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR)
  598. break;
  599. pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
  600. if (pDeviceInfo) {
  601. pDeviceInfo->dwFlags = (DWORD)dwParam2;
  602. pDeviceInfo->mmr = MMSYSERR_ERROR;
  603. mmr = wdmaudIoControl(
  604. pDeviceInfo,
  605. ((LPMIXERCONTROLDETAILS) dwParam1)->cbStruct,
  606. (LPVOID) dwParam1,
  607. IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS
  608. );
  609. EXTRACTERROR(mmr,pDeviceInfo);
  610. GlobalFreeDeviceInfo(pDeviceInfo);
  611. }
  612. else {
  613. mmr = MMSYSERR_NOMEM;
  614. }
  615. }
  616. break;
  617. ///////////////////////////////////////////////////////////////
  618. case MXDM_SETCONTROLDETAILS:
  619. ///////////////////////////////////////////////////////////////
  620. {
  621. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  622. LPDEVICEINFO pDeviceInfo;
  623. DPF(DL_TRACE|FA_MIXER, ("MIXM_SETCONTROLDETAILS(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  624. if( (mmr=IsValidMixerInstance(pInstance)) != MMSYSERR_NOERROR)
  625. break;
  626. pDeviceInfo = GlobalAllocMixerDeviceInfo(pInstance->wstrDeviceInterface, id, pInstance->dwKernelInstance);
  627. if (pDeviceInfo) {
  628. pDeviceInfo->dwFlags = (DWORD)dwParam2;
  629. pDeviceInfo->mmr = MMSYSERR_ERROR;
  630. pDeviceInfo->dwCallbackType=0;
  631. mmr = wdmaudIoControl(
  632. pDeviceInfo,
  633. ((LPMIXERCONTROLDETAILS) dwParam1)->cbStruct,
  634. (LPVOID) dwParam1,
  635. IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS
  636. );
  637. EXTRACTERROR(mmr,pDeviceInfo);
  638. if (pDeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) {
  639. LONG j;
  640. for (j=0; j<pDeviceInfo->ControlCallbackCount; j++) {
  641. StoreCallback(MIXER_CONTROL_CALLBACK,
  642. (pDeviceInfo->dwID)[j]);
  643. }
  644. }
  645. if (pDeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) {
  646. StoreCallback(MIXER_LINE_CALLBACK,
  647. pDeviceInfo->dwLineID);
  648. }
  649. GlobalFreeDeviceInfo(pDeviceInfo);
  650. }
  651. else {
  652. mmr = MMSYSERR_NOMEM;
  653. }
  654. }
  655. // Map invalid error codes to valid ones.
  656. switch (mmr) {
  657. case MMSYSERR_ERROR:
  658. mmr = MMSYSERR_NOMEM;
  659. break;
  660. default:
  661. break;
  662. }
  663. break;
  664. #ifdef UNDER_NT
  665. ///////////////////////////////////////////////////////////////
  666. case MXDM_GETHARDWAREEVENTDATA:
  667. ///////////////////////////////////////////////////////////////
  668. {
  669. LPMIXERINSTANCE pInstance = (LPMIXERINSTANCE)dwUser;
  670. LPDEVICEINFO pDeviceInfo;
  671. DPF(DL_TRACE|FA_MIXER, ("MXDM_GETHARDWAREEVENTDATA(%d,%lx,%lx,%lx)", id, dwUser, dwParam1, dwParam2) );
  672. DPFASSERT( dwUser==0 && dwParam1==0 && dwParam2==0 );
  673. if (dwUser!=0 || dwParam1!=0 || dwParam2!=0) {
  674. mmr=MMSYSERR_INVALPARAM;
  675. break;
  676. }
  677. pDeviceInfo = GlobalAllocMixerDeviceInfo(L" ", 0, 0);
  678. if (pDeviceInfo) {
  679. pDeviceInfo->dwCallbackType=1;
  680. // WorkItem: Hey, this loop continually calls the driver and doesn't error out!!!!! Shouldn't it?
  681. while(pDeviceInfo->dwCallbackType) {
  682. pDeviceInfo->dwFlags = 0;
  683. pDeviceInfo->mmr = MMSYSERR_ERROR;
  684. pDeviceInfo->dwCallbackType=0;
  685. mmr = wdmaudIoControl(
  686. pDeviceInfo,
  687. 0,
  688. NULL,
  689. IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA
  690. );
  691. EXTRACTERROR(mmr,pDeviceInfo);
  692. if (pDeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) {
  693. LONG j;
  694. for (j=0; j<pDeviceInfo->ControlCallbackCount; j++) {
  695. StoreCallback(MIXER_CONTROL_CALLBACK,
  696. (pDeviceInfo->dwID)[j]);
  697. }
  698. }
  699. if (pDeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) {
  700. StoreCallback(MIXER_LINE_CALLBACK,
  701. pDeviceInfo->dwLineID);
  702. }
  703. }
  704. mmr = pDeviceInfo->mmr; // WorkItem: Why isn't this inside the loop?
  705. GlobalFreeDeviceInfo(pDeviceInfo);
  706. }
  707. else {
  708. mmr = MMSYSERR_NOMEM;
  709. }
  710. }
  711. break;
  712. #endif
  713. ///////////////////////////////////////////////////////////////
  714. default:
  715. ///////////////////////////////////////////////////////////////
  716. mmr=MMSYSERR_NOTSUPPORTED;
  717. break;
  718. }
  719. //#if 0
  720. #ifdef UNDER_NT
  721. ReleaseMutex(serializemixerapi);
  722. // Now check if any callbacks were logged while we were
  723. // running. If so, make them.
  724. if (GetGlobalCallbackIndex()!=initialcallbackindex) {
  725. if (mixercallbackevent!=NULL) {
  726. PulseEvent(mixercallbackevent);
  727. }
  728. }
  729. #endif
  730. MMRRETURN( mmr );
  731. } // mxdMessage()
  732. ///////////////////////////////////////////////////////////////////////
  733. //
  734. // mxdRemoveClient
  735. //
  736. //
  737. VOID
  738. mxdRemoveClient(
  739. LPMIXERINSTANCE lpInstance
  740. )
  741. {
  742. LPMIXERINSTANCE lp, lpPrevious;
  743. lpPrevious = (LPMIXERINSTANCE)&pMixerDeviceList;
  744. for(lp = pMixerDeviceList; lp != NULL; lp = lp->Next) {
  745. ISVALIDMIXERINSTANCE(lp);
  746. if(lp == lpInstance) {
  747. lpPrevious->Next = lp->Next;
  748. #ifdef UNDER_NT
  749. if (InterlockedDecrement(&lpInstance->referencecount)<0) {
  750. // The instance is not in use by a callback. So OK to free it.
  751. #ifdef DEBUG
  752. lpInstance->dwSig=0;
  753. #endif
  754. GlobalFreePtr( lpInstance );
  755. }
  756. // This instance is in use by a callback, so do not free it now.
  757. // We are already setup so the callback will free it, since we have
  758. // changed the referencecount so it will not be zero after the callback
  759. // code decrements it. That will prompt the callback code to release
  760. // the instance memory.
  761. #else
  762. GlobalFreePtr( lpInstance );
  763. #endif
  764. break;
  765. }
  766. lpPrevious = lp;
  767. }
  768. }