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.

1845 lines
52 KiB

  1. /****************************************************************************
  2. *
  3. * mixerdd.c
  4. *
  5. * Multimedia kernel driver support component
  6. *
  7. * Copyright (c) 1993-1996 Microsoft Corporation
  8. *
  9. * Win32 Driver support for mixer devices including interface to kernel
  10. * driver.
  11. *
  12. ***************************************************************************/
  13. /****************************************************************************
  14. Design :
  15. The win32 mixer driver first initializes itself by reading the mixer
  16. information from the registry.
  17. The mixer configuration information is stored inside the mixer device's
  18. value under the (volatile) devices key for the specific mixer device.
  19. See drvutil.c for a detailed description of the registry structure.
  20. The format of the mixer configuration is defined in ntddmix.h :
  21. MIXER_DD_CONFIGURATION_DATA
  22. No variable data is (for obvious reasons) cached by this driver. It's
  23. assumed the application does this. The driver will request the
  24. information from the kernel driver when requested.
  25. A single overlapped ioctl is left incomplete on the mixer kernel device.
  26. This Ioctl is completed when changes occur. The Ioctl uses overlapped IO.
  27. The overlap routine only runs when an alertable wait (such as in
  28. GetMessage) is executed at which point PostMessage is issued, the
  29. Ioctl requeued and the overlapped routine returns (at which point
  30. the Ioctl could be complete again and another overlapped routine run).
  31. Important note:
  32. The opening of devices is purely for obtaining notifications.
  33. Otherwise applications can call the APIs in a completely unstructured
  34. way by using the mixer API and device numbers instead of handles.
  35. Serialization
  36. The API layer serializes us on each device id.
  37. Control structures
  38. For an individual mixer there is a set of 'global' data and a
  39. handle list for notifications. A critical section is needed to
  40. serialize the notify thread access to this list and opens and
  41. closes.
  42. The global data consists of
  43. An open handle to the kernel device
  44. A notification thread 'handle'
  45. The overlapped structure for callbacks
  46. The critical section
  47. ****************************************************************************/
  48. #include <drvlib.h>
  49. #include <ntddmix.h>
  50. #include <tchar.h>
  51. /*
  52. ** Information about each 'handle'. These are chained together
  53. ** to support notification callbacks. There's no actual need to
  54. ** chain in ones which don't want notification.
  55. */
  56. struct _MIXER_DRIVER_ALLOC;
  57. typedef struct _MM_MIXER_NOTIFY {
  58. struct _MM_MIXER_NOTIFY * Next;
  59. MIXEROPENDESC ClientData;
  60. DWORD fdwOpen;
  61. struct _MIXER_DRIVER_ALLOC * pMixerData;
  62. } MM_MIXER_NOTIFY, *PMM_MIXER_NOTIFY;
  63. /*
  64. ** MIXER_DRIVER_ALLOC is a stucture allocated and initialized when a
  65. ** mixer driver is first used. It is never freed.
  66. **
  67. ** It is used to cache all the mixer configuration information
  68. */
  69. typedef struct _MIXER_DRIVER_ALLOC {
  70. HANDLE hDevice; // Handle of kernel device
  71. DWORD BytesReturned; // Keep DeviceIoControl
  72. // happy.
  73. /*
  74. ** Notification stuff
  75. */
  76. HANDLE hThreadTerm;
  77. OVERLAPPED Ovl;
  78. MIXER_DD_REQUEST_NOTIFY NotificationData;
  79. HANDLE hMxdStartupEvent;
  80. /*
  81. ** Precanned write location
  82. */
  83. OVERLAPPED WriteOvl;
  84. HANDLE TerminateEvent; // Set for termination
  85. /*
  86. ** Custom controls
  87. */
  88. MMRESULT (CALLBACK *
  89. fnCustom)(struct _MIXER_DRIVER_ALLOC *,
  90. LPMIXERCONTROLDETAILS,
  91. DWORD);
  92. /*
  93. ** Manage requestors of notifications
  94. */
  95. CRITICAL_SECTION HandleListCritSec;
  96. PMM_MIXER_NOTIFY NotificationList; // 'Open' handles
  97. /*
  98. ** Configuration data
  99. */
  100. PMIXER_DD_LINE_CONFIGURATION_DATA
  101. pLineConfigurationData; // List of lines
  102. PMIXER_DD_CONTROL_CONFIGURATION_DATA
  103. pControlConfigurationData;// List of controls
  104. PMIXER_DD_CONFIGURATION_DATA
  105. pConfigurationData; // MUST be at the end
  106. } MIXER_DRIVER_ALLOC, *PMIXER_DRIVER_ALLOC;
  107. /*
  108. ** Local functions
  109. */
  110. void MxdFreeMixerData(PMIXER_DRIVER_ALLOC pMixerData);
  111. /*
  112. ** MxdNotifyClients
  113. **
  114. ** Generate notifications when our asynchronous IOCTL completes
  115. */
  116. void MxdNotifyClients(PMIXER_DRIVER_ALLOC pMixerData)
  117. {
  118. PMM_MIXER_NOTIFY pNotify;
  119. EnterCriticalSection(&pMixerData->HandleListCritSec);
  120. #if DBG
  121. /*
  122. ** Check the notification data
  123. */
  124. if (pMixerData->NotificationData.Message ==
  125. MM_MIXM_CONTROL_CHANGE) {
  126. if (pMixerData->NotificationData.Id >
  127. pMixerData->pConfigurationData->NumberOfControls) {
  128. dprintf(("Mixer notify Control out of range - value %lu, no. controls %lu",
  129. pMixerData->NotificationData.Id,
  130. pMixerData->pConfigurationData->NumberOfControls));
  131. DebugBreak();
  132. }
  133. } else {
  134. if (pMixerData->NotificationData.Message ==
  135. MM_MIXM_LINE_CHANGE) {
  136. if (pMixerData->NotificationData.Id >
  137. pMixerData->pConfigurationData->NumberOfLines) {
  138. dprintf(("Mixer notify Line out of range - value %lu, no. controls %lu",
  139. pMixerData->NotificationData.Id,
  140. pMixerData->pConfigurationData->NumberOfLines));
  141. DebugBreak();
  142. }
  143. } else {
  144. dprintf(("Mixer notify message id invalid - value %lu",
  145. pMixerData->NotificationData.Message));
  146. DebugBreak();
  147. }
  148. }
  149. #endif // DBG
  150. /*
  151. ** Dispatch each requestor for notification
  152. */
  153. for (pNotify = pMixerData->NotificationList;
  154. pNotify != NULL;
  155. pNotify = pNotify->Next) {
  156. DriverCallback(pNotify->ClientData.dwCallback,
  157. (DWORD)HIWORD(pNotify->fdwOpen & CALLBACK_TYPEMASK),
  158. (HDRVR)pNotify->ClientData.hmx,
  159. pMixerData->NotificationData.Message,
  160. pNotify->ClientData.dwInstance,
  161. pMixerData->NotificationData.Id,
  162. 0L);
  163. }
  164. LeaveCriticalSection(&pMixerData->HandleListCritSec);
  165. }
  166. /*
  167. ** MxdNotifyThread
  168. */
  169. DWORD MxdNotifyThread(PMIXER_DRIVER_ALLOC pMixerData)
  170. {
  171. HANDLE Events[2];
  172. HANDLE hStartupEvent;
  173. Events[0] = pMixerData->Ovl.hEvent;
  174. Events[1] = pMixerData->TerminateEvent;
  175. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  176. /*
  177. ** Loop dispatching our Ioctl
  178. */
  179. for (;;) {
  180. /*
  181. ** Call DeviceIoControl to start our callback chain
  182. ** Actually there's nothing much we can do if this fails
  183. ** - it may fail later as well.
  184. */
  185. while (!DeviceIoControl(pMixerData->hDevice,
  186. IOCTL_MIX_REQUEST_NOTIFY,
  187. (PVOID)&pMixerData->NotificationData,
  188. sizeof(pMixerData->NotificationData),
  189. (PVOID)&pMixerData->NotificationData,
  190. sizeof(pMixerData->NotificationData),
  191. &pMixerData->BytesReturned,
  192. &pMixerData->Ovl) &&
  193. GetLastError() != ERROR_IO_PENDING) {
  194. dprintf1(("DeviceIoControl for mixer failed!"));
  195. Sleep(300);
  196. }
  197. if (pMixerData->hMxdStartupEvent != NULL)
  198. {
  199. if (FALSE == SetEvent (pMixerData->hMxdStartupEvent)) dprintf(("MxdNotifyThread: Could not set startup event"));
  200. if (FALSE == CloseHandle (pMixerData->hMxdStartupEvent)) dprintf(("MxdNotifyThread: Count not close startup event handle"));
  201. pMixerData->hMxdStartupEvent = NULL;
  202. }
  203. /*
  204. ** Wait for something to change or to be asked to terminate
  205. */
  206. if (WaitForMultipleObjects(
  207. 2,
  208. Events,
  209. FALSE,
  210. INFINITE) == WAIT_OBJECT_0 + 1) {
  211. /*
  212. ** Termination event set
  213. */
  214. return 0;
  215. }
  216. /*
  217. ** Call drivercallback for all open handles
  218. */
  219. MxdNotifyClients(pMixerData);
  220. /*
  221. ** Don't do things in too much of a rush - this is
  222. ** sort of equivalent to a Yield() in Win16
  223. */
  224. Sleep(0);
  225. }
  226. }
  227. /*
  228. ** Free our notification thread
  229. */
  230. void MxdFreeMixerThread(PMIXER_DRIVER_ALLOC pMixerData)
  231. {
  232. /*
  233. ** Close down our thread if it's started.
  234. */
  235. if (pMixerData->hThreadTerm) {
  236. /*
  237. ** Tell the thread to finish
  238. */
  239. SetEvent(pMixerData->TerminateEvent);
  240. WaitForSingleObject(pMixerData->hThreadTerm, INFINITE);
  241. CloseHandle(pMixerData->hThreadTerm);
  242. pMixerData->hThreadTerm = NULL;
  243. }
  244. /*
  245. ** Note that if the IOCTL is still outstanding then the IO subsystem
  246. ** still has a reference to this event object so it can be safely
  247. ** set when the IOCTL completes - even though we won't hear about it.
  248. */
  249. if (pMixerData->Ovl.hEvent != NULL) {
  250. CloseHandle(pMixerData->Ovl.hEvent);
  251. pMixerData->Ovl.hEvent = NULL;
  252. }
  253. if (pMixerData->TerminateEvent != NULL) {
  254. CloseHandle(pMixerData->TerminateEvent);
  255. pMixerData->TerminateEvent = NULL;
  256. }
  257. if (pMixerData->hMxdStartupEvent != NULL) {
  258. CloseHandle(pMixerData->hMxdStartupEvent);
  259. pMixerData->hMxdStartupEvent = NULL;
  260. }
  261. }
  262. /*
  263. ** MxdFreeMixerData
  264. */
  265. void MxdFreeMixerData(PMIXER_DRIVER_ALLOC pMixerData)
  266. {
  267. MxdFreeMixerThread(pMixerData);
  268. if (pMixerData->hDevice != NULL &&
  269. pMixerData->hDevice != INVALID_HANDLE_VALUE) {
  270. CloseHandle(pMixerData->hDevice);
  271. }
  272. DeleteCriticalSection(&pMixerData->HandleListCritSec);
  273. if (pMixerData->pConfigurationData) {
  274. HeapFree(hHeap, 0, (LPVOID)pMixerData->pConfigurationData);
  275. }
  276. HeapFree(hHeap, 0, (LPVOID)pMixerData);
  277. }
  278. /*
  279. ** Find number of control items for a control
  280. */
  281. UINT NumberOfControlItems(PMIXER_DRIVER_ALLOC pMixerData, UINT ControlId)
  282. {
  283. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  284. UINT cChannels, cMultipleItems;
  285. pControlData = &pMixerData->pControlConfigurationData[ControlId];
  286. if (pControlData->fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE) {
  287. cMultipleItems = pControlData->cMultipleItems;
  288. } else {
  289. cMultipleItems = 1;
  290. }
  291. if (pControlData->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) {
  292. cChannels = 1;
  293. } else {
  294. cChannels = pMixerData->pLineConfigurationData[
  295. pControlData->LineID].cChannels;
  296. }
  297. return cChannels * cMultipleItems;
  298. }
  299. /*
  300. ** Get the text data for a control with multiple elements
  301. */
  302. PMIXER_DD_CONTROL_LISTTEXT
  303. GetControlText(
  304. PMIXER_DRIVER_ALLOC pMixerData,
  305. UINT ControlId,
  306. UINT MemberId
  307. )
  308. {
  309. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  310. pControlData = &pMixerData->pControlConfigurationData[ControlId];
  311. if (pControlData->TextDataOffset == 0) {
  312. return NULL;
  313. }
  314. return (PMIXER_DD_CONTROL_LISTTEXT)((PBYTE)pMixerData->pConfigurationData +
  315. pControlData->TextDataOffset) +
  316. MemberId;
  317. }
  318. #if DBG
  319. /*
  320. ** Check the configuration data dumped in the registry by the kernel
  321. ** driver
  322. */
  323. void ValidateMixerConfigurationData(PMIXER_DRIVER_ALLOC pMixerData,
  324. DWORD ConfigurationDataSize)
  325. {
  326. /*
  327. ** Validate the data
  328. */
  329. UINT i;
  330. DWORD ExpectedConfigurationDataSize;
  331. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  332. PMIXER_DD_LINE_CONFIGURATION_DATA pLineData;
  333. UINT cControls;
  334. UINT cSources;
  335. UINT cControlsInLine;
  336. UINT cLines;
  337. if (ConfigurationDataSize != pMixerData->pConfigurationData->cbSize) {
  338. dprintf(("Configuration data size wrong"));
  339. }
  340. ExpectedConfigurationDataSize =
  341. sizeof(MIXER_DD_CONFIGURATION_DATA) +
  342. pMixerData->pConfigurationData->NumberOfLines *
  343. sizeof(MIXER_DD_LINE_CONFIGURATION_DATA) +
  344. pMixerData->pConfigurationData->NumberOfControls *
  345. sizeof(MIXER_DD_CONTROL_CONFIGURATION_DATA);
  346. /*
  347. ** Check the controls data
  348. */
  349. for (i = 0, cLines = 0, cControlsInLine = 0,
  350. pControlData = pMixerData->pControlConfigurationData;
  351. i < pMixerData->pConfigurationData->NumberOfControls;
  352. i++, pControlData++) {
  353. PMIXER_DD_CONTROL_LISTTEXT pListText;
  354. ULONG ListTextOffset;
  355. if (ConfigurationDataSize < ExpectedConfigurationDataSize) {
  356. dprintf(("Configuration data size too small on control %u - was %u, expected at least %u",
  357. i, ConfigurationDataSize, ExpectedConfigurationDataSize));
  358. }
  359. /*
  360. ** Check line id - should be the same as the previous or one
  361. ** greater - can't have a line with 0 controls!
  362. */
  363. if ((DWORD)pControlData->LineID >=
  364. pMixerData->pConfigurationData->NumberOfLines) {
  365. dprintf(("Invalid line ID - Number of lines %u, this line %u",
  366. (UINT)pMixerData->pConfigurationData->NumberOfLines,
  367. (UINT)pControlData->LineID));
  368. }
  369. if (cLines == (UINT)pControlData->LineID) {
  370. cControlsInLine++;
  371. }
  372. if (cLines != (UINT)pControlData->LineID ||
  373. i == pMixerData->pConfigurationData->NumberOfControls
  374. ) {
  375. if (cControlsInLine !=
  376. pMixerData->pLineConfigurationData[cLines].cControls) {
  377. dprintf(("Wrong number of controls for line %u, expected %u, got %u",
  378. cLines,
  379. (UINT)pMixerData->pLineConfigurationData[cLines].cControls,
  380. cControlsInLine));
  381. }
  382. cLines++;
  383. cControlsInLine = 1;
  384. }
  385. pListText = GetControlText(pMixerData, i, 0);
  386. if (pListText != NULL) {
  387. ListTextOffset =
  388. (ULONG)((PBYTE)pListText - (PBYTE)pMixerData->pConfigurationData);
  389. if (ListTextOffset != ExpectedConfigurationDataSize) {
  390. dprintf(("Control Text Data Offset wrong - expected %u, was %u",
  391. ExpectedConfigurationDataSize, ListTextOffset));
  392. } else {
  393. UINT j;
  394. /*
  395. ** Check embedded control ids in listtext data
  396. */
  397. for (j = 0; j < NumberOfControlItems(pMixerData, i); j++) {
  398. if (GetControlText(pMixerData, i, j)->ControlId != i) {
  399. dprintf(("Text data control id wrong - expected %u, was %u",
  400. i,
  401. GetControlText(pMixerData, i, j)->ControlId));
  402. }
  403. }
  404. ExpectedConfigurationDataSize +=
  405. sizeof(MIXER_DD_CONTROL_LISTTEXT) *
  406. NumberOfControlItems(pMixerData, i);
  407. }
  408. }
  409. }
  410. /*
  411. ** Check the sources vs destinations and number of controls and
  412. ** Lines
  413. */
  414. if (pMixerData->pConfigurationData->DeviceCaps.cDestinations >
  415. pMixerData->pConfigurationData->NumberOfLines) {
  416. dprintf(("Too many destinations! - %u Destinations, %u Lines",
  417. pMixerData->pConfigurationData->DeviceCaps.cDestinations,
  418. pMixerData->pConfigurationData->NumberOfLines));
  419. }
  420. for (i = 0, cControls = 0, cSources = 0,
  421. pLineData = pMixerData->pLineConfigurationData;
  422. i < pMixerData->pConfigurationData->NumberOfLines;
  423. i++, pLineData++) {
  424. #if 0
  425. /*
  426. ** The destinations come FIRST
  427. */
  428. if ((pLineData->fdwLine & MIXERLINE_LINEF_SOURCE) &&
  429. i < pMixerData->pConfigurationData->DeviceCaps.cDestinations ||
  430. !(pLineData->fdwLine & MIXERLINE_LINEF_SOURCE) &&
  431. i >= pMixerData->pConfigurationData->DeviceCaps.cDestinations) {
  432. dprintf(("Destination line too large! - %u Destinations, %u Lines Id",
  433. pMixerData->pConfigurationData->DeviceCaps.cDestinations,
  434. i));
  435. }
  436. #endif
  437. cControls += pLineData->cControls;
  438. }
  439. /*
  440. ** Check number of controls
  441. */
  442. if (cControls != pMixerData->pConfigurationData->NumberOfControls) {
  443. dprintf(("Wrong number of controls! - expected %u, found %u",
  444. pMixerData->pConfigurationData->NumberOfControls,
  445. cControls));
  446. }
  447. /*
  448. ** End of registry data validation
  449. */
  450. }
  451. #endif // DBG
  452. /*
  453. ** MxdInitDevice
  454. **
  455. ** Allocate fixed stuff for a mixer device
  456. */
  457. MMRESULT MxdInitDevice(
  458. UINT DeviceId,
  459. PMIXER_DRIVER_ALLOC *ppMixerData
  460. )
  461. {
  462. DWORD ConfigurationDataSize;
  463. PMIXER_DRIVER_ALLOC pMixerData;
  464. MMRESULT mmRet;
  465. DWORD BytesReturned;
  466. /*
  467. ** Allocate space for the configuration data and read it
  468. */
  469. pMixerData =
  470. (PMIXER_DRIVER_ALLOC)HeapAlloc(hHeap, 0, sizeof(MIXER_DRIVER_ALLOC));
  471. if (pMixerData == NULL) {
  472. return MMSYSERR_NOMEM;
  473. }
  474. ZeroMemory((PVOID)pMixerData, sizeof(*pMixerData));
  475. InitializeCriticalSection(&pMixerData->HandleListCritSec);
  476. /*
  477. ** See if we can actually open the thing
  478. */
  479. mmRet = sndOpenDev(MIXER_DEVICE,
  480. DeviceId,
  481. &pMixerData->hDevice,
  482. GENERIC_READ | GENERIC_WRITE);
  483. if (mmRet != MMSYSERR_NOERROR) {
  484. MxdFreeMixerData(pMixerData);
  485. return mmRet;
  486. }
  487. /*
  488. ** Load the configuration data from the registry
  489. */
  490. DeviceIoControl(pMixerData->hDevice,
  491. IOCTL_MIX_GET_CONFIGURATION,
  492. NULL,
  493. 0,
  494. (PVOID)&ConfigurationDataSize,
  495. sizeof(ConfigurationDataSize),
  496. &BytesReturned,
  497. NULL);
  498. if (BytesReturned != sizeof(ConfigurationDataSize)) {
  499. dprintf(("Mixer config not available"));
  500. MxdFreeMixerData(pMixerData);
  501. return (MMRESULT)sndTranslateStatus();
  502. }
  503. WinAssert(ConfigurationDataSize >= sizeof(MIXER_DD_CONFIGURATION_DATA));
  504. pMixerData->pConfigurationData = HeapAlloc(hHeap, 0, ConfigurationDataSize);
  505. if (pMixerData->pConfigurationData == NULL) {
  506. MxdFreeMixerData(pMixerData);
  507. return MMSYSERR_NOMEM;
  508. }
  509. if (!DeviceIoControl(pMixerData->hDevice,
  510. IOCTL_MIX_GET_CONFIGURATION,
  511. NULL,
  512. 0,
  513. (PVOID)pMixerData->pConfigurationData,
  514. ConfigurationDataSize,
  515. &BytesReturned,
  516. NULL) ||
  517. BytesReturned != ConfigurationDataSize) {
  518. dprintf(("Wrong size for mixer Config"));
  519. MxdFreeMixerData(pMixerData);
  520. return (MMRESULT)sndTranslateStatus();
  521. }
  522. pMixerData->pLineConfigurationData =
  523. (PMIXER_DD_LINE_CONFIGURATION_DATA)&pMixerData->pConfigurationData[1];
  524. pMixerData->pControlConfigurationData =
  525. (PMIXER_DD_CONTROL_CONFIGURATION_DATA)
  526. &pMixerData->pLineConfigurationData[
  527. pMixerData->pConfigurationData->NumberOfLines];
  528. #if DBG
  529. /*
  530. ** Check the kernel driver dumped correct stuff in the registry
  531. */
  532. ValidateMixerConfigurationData(pMixerData,
  533. ConfigurationDataSize);
  534. #endif // DBG
  535. *ppMixerData = pMixerData;
  536. return MMSYSERR_NOERROR;
  537. }
  538. /*
  539. ** Create the notification thread
  540. */
  541. BOOL MxdCreateThread(PMIXER_DRIVER_ALLOC pMixerData)
  542. {
  543. MMRESULT mmRet;
  544. /*
  545. ** Create notification event (we wouldn't need any of this if we
  546. ** had overlapped routines for ioctls)
  547. */
  548. pMixerData->Ovl.hEvent =
  549. CreateEvent(NULL, TRUE, FALSE, NULL); // Manual reset
  550. if (pMixerData->Ovl.hEvent == NULL) {
  551. MxdFreeMixerThread(pMixerData);
  552. return FALSE;
  553. }
  554. pMixerData->TerminateEvent =
  555. CreateEvent(NULL, FALSE, FALSE, NULL);
  556. if (pMixerData->TerminateEvent == NULL) {
  557. MxdFreeMixerThread(pMixerData);
  558. return FALSE;
  559. }
  560. pMixerData->hMxdStartupEvent = CreateEvent (NULL, // no security attribs
  561. FALSE, // auto-reset
  562. FALSE, // non signaled
  563. NULL);
  564. if (pMixerData->hMxdStartupEvent == NULL) {
  565. MxdFreeMixerThread(pMixerData);
  566. return FALSE;
  567. }
  568. /*
  569. ** Create the thread
  570. */
  571. mmRet = mmTaskCreate((LPTASKCALLBACK)MxdNotifyThread,
  572. &pMixerData->hThreadTerm,
  573. (DWORD_PTR)pMixerData);
  574. if (mmRet != MMSYSERR_NOERROR) {
  575. MxdFreeMixerThread(pMixerData);
  576. return FALSE;
  577. }
  578. WaitForSingleObjectEx(pMixerData->hMxdStartupEvent, INFINITE, FALSE);
  579. return TRUE;
  580. }
  581. /*
  582. ** MxdOpen
  583. **
  584. ** Allocates device data structure
  585. */
  586. MMRESULT MxdOpen(
  587. PMIXER_DRIVER_ALLOC pMixerData,
  588. PDWORD_PTR dwDrvUser,
  589. PMIXEROPENDESC pmxod,
  590. DWORD fdwOpen
  591. )
  592. {
  593. PMM_MIXER_NOTIFY pNotify;
  594. pNotify = (PMM_MIXER_NOTIFY)HeapAlloc(hHeap, 0, sizeof(MM_MIXER_NOTIFY));
  595. if (pNotify == NULL) {
  596. return MMSYSERR_NOMEM;
  597. }
  598. /*
  599. ** We're done - fill in the structure and return the data
  600. */
  601. pNotify->ClientData = *pmxod; // Whom and how to notify
  602. pNotify->fdwOpen = fdwOpen;
  603. pNotify->pMixerData = pMixerData;
  604. /*
  605. ** Start getting notifications (even though nothing's changed?)
  606. */
  607. if ((fdwOpen & CALLBACK_TYPEMASK) != CALLBACK_NULL) {
  608. EnterCriticalSection(&mmDrvCritSec);
  609. if (pMixerData->NotificationList == NULL) {
  610. if (!MxdCreateThread(pMixerData)) {
  611. LeaveCriticalSection(&mmDrvCritSec);
  612. return MMSYSERR_NOMEM;
  613. }
  614. }
  615. /*
  616. ** Add to the list - ONLY if they want notification
  617. */
  618. EnterCriticalSection(&pMixerData->HandleListCritSec);
  619. pNotify->Next = pMixerData->NotificationList;
  620. pMixerData->NotificationList = pNotify;
  621. LeaveCriticalSection(&pMixerData->HandleListCritSec);
  622. LeaveCriticalSection(&mmDrvCritSec);
  623. }
  624. /*
  625. ** Return our handle to the user. Note - they may start getting floods
  626. ** of notifications before they even return - but this won't confuse
  627. ** single-thread applications.
  628. */
  629. *dwDrvUser = (DWORD_PTR)pNotify;
  630. return MMSYSERR_NOERROR;
  631. }
  632. /*
  633. ** Close a user handle
  634. */
  635. MMRESULT MxdClose(PMM_MIXER_NOTIFY pNotify)
  636. {
  637. PMM_MIXER_NOTIFY *pSearch;
  638. /*
  639. ** Remove it from the list
  640. */
  641. EnterCriticalSection(&mmDrvCritSec);
  642. EnterCriticalSection(&pNotify->pMixerData->HandleListCritSec);
  643. for (pSearch = &pNotify->pMixerData->NotificationList;
  644. *pSearch != NULL && *pSearch != pNotify;
  645. pSearch = &(*pSearch)->Next) {}
  646. if (*pSearch != NULL) {
  647. /*
  648. ** After this the notify loop in the notification thread
  649. ** will not find this notification in this list so won't
  650. ** make any more notifications for this device
  651. */
  652. *pSearch = (*pSearch)->Next;
  653. WinAssert ((pNotify->fdwOpen & CALLBACK_TYPEMASK) !=
  654. CALLBACK_NULL);
  655. LeaveCriticalSection(&pNotify->pMixerData->HandleListCritSec);
  656. /*
  657. ** See if all requestors for notification have gone away
  658. **
  659. ** If they have no more can be created because we're holding
  660. ** on to mmDrvCritSec which is held when when add stuff
  661. ** to the list and create the thread.
  662. **
  663. ** Thus it's safe to wait for the thread to finish in its
  664. ** own time.
  665. */
  666. if (pNotify->pMixerData->NotificationList == NULL) {
  667. MxdFreeMixerThread(pNotify->pMixerData);
  668. }
  669. } else {
  670. LeaveCriticalSection(&pNotify->pMixerData->HandleListCritSec);
  671. }
  672. LeaveCriticalSection(&mmDrvCritSec);
  673. HeapFree(hHeap, 0, (LPVOID)pNotify);
  674. return MMSYSERR_NOERROR;
  675. }
  676. /*
  677. ** MxdCreateControlInfo
  678. **
  679. ** Expand the control info for the caller from our compacted form to
  680. ** a MIXERCONTROL structure.
  681. */
  682. DWORD
  683. MxdCreateControlInfo(
  684. PMIXER_DRIVER_ALLOC pMixerData,
  685. DWORD dwControlId,
  686. LPMIXERCONTROL pmxctrl
  687. )
  688. {
  689. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  690. pControlData = &pMixerData->pControlConfigurationData[dwControlId];
  691. pmxctrl->cbStruct = sizeof(MIXERCONTROL);
  692. pmxctrl->dwControlID = dwControlId;
  693. pmxctrl->dwControlType = pControlData->dwControlType;
  694. pmxctrl->cMultipleItems = (DWORD)pControlData->cMultipleItems;
  695. pmxctrl->fdwControl = pControlData->fdwControl;
  696. InternalLoadString(pControlData->ShortNameStringId,
  697. pmxctrl->szShortName,
  698. sizeof(pmxctrl->szShortName) / sizeof(TCHAR));
  699. InternalLoadString(pControlData->LongNameStringId,
  700. pmxctrl->szName,
  701. sizeof(pmxctrl->szName) / sizeof(TCHAR));
  702. CopyMemory(&pmxctrl->Bounds, &pControlData->Bounds,
  703. sizeof(*pmxctrl) - FIELD_OFFSET(MIXERCONTROL, Bounds));
  704. #if 0
  705. /*
  706. ** Go and ask the kernel about the flags state
  707. */
  708. if (!DeviceIoControl(pMixerData->hDevice,
  709. IOCTL_MIX_GET_CONTROL_FLAGS,
  710. NULL,
  711. 0,
  712. (PVOID)&pmxctrl->fdwControl,
  713. sizeof(pmxl->fdwControl),
  714. &pMixerData->BytesReturned,
  715. NULL) {
  716. ugh!
  717. }
  718. #endif
  719. return (DWORD)pControlData->LineID;
  720. }
  721. /*
  722. ** Expand the line info for the caller from our compacted form to
  723. ** a MIXERLINE structure - getting the variable flags from the kernel
  724. ** mode driver at the same time.
  725. */
  726. MMRESULT MxdCreateLineInfo(
  727. PMIXER_DRIVER_ALLOC pMixerData,
  728. DWORD dwLineId,
  729. LPMIXERLINE pmxl
  730. )
  731. {
  732. PMIXER_DD_LINE_CONFIGURATION_DATA pConfigData;
  733. /*
  734. ** Find our compressed data for this line
  735. */
  736. pConfigData = &pMixerData->pLineConfigurationData[dwLineId];
  737. pmxl->cbStruct = sizeof(MIXERLINE);
  738. pmxl->dwDestination = (DWORD)pConfigData->Destination;
  739. pmxl->dwSource = (DWORD)pConfigData->Source;
  740. pmxl->dwLineID = dwLineId;
  741. /*
  742. ** Go and ask the kernel about the line state and user field
  743. */
  744. if (!DeviceIoControl(pMixerData->hDevice,
  745. IOCTL_MIX_GET_LINE_DATA,
  746. (PVOID)&dwLineId,
  747. sizeof(dwLineId),
  748. (PVOID)&pmxl->fdwLine,
  749. sizeof(pmxl->fdwLine),
  750. &pMixerData->BytesReturned,
  751. NULL)) {
  752. return (MMRESULT)sndTranslateStatus();
  753. }
  754. pmxl->dwUser = pConfigData->dwUser;
  755. pmxl->dwComponentType = pConfigData->dwComponentType;
  756. pmxl->cChannels = (DWORD)pConfigData->cChannels;
  757. pmxl->cConnections = (DWORD)pConfigData->cConnections;
  758. pmxl->cControls = (DWORD)pConfigData->cControls;
  759. InternalLoadString(pConfigData->ShortNameStringId,
  760. pmxl->szShortName,
  761. sizeof(pmxl->szShortName) / sizeof(TCHAR));
  762. InternalLoadString(pConfigData->LongNameStringId,
  763. pmxl->szName,
  764. sizeof(pmxl->szName) / sizeof(TCHAR));
  765. /*
  766. ** Target data
  767. */
  768. pmxl->Target.dwType = (DWORD)pConfigData->Type;
  769. if (pmxl->Target.dwType != MIXERLINE_TARGETTYPE_UNDEFINED) {
  770. pmxl->Target.dwDeviceID = 0;
  771. pmxl->Target.wPid = pConfigData->wPid;
  772. pmxl->Target.wMid = pMixerData->pConfigurationData->DeviceCaps.wMid;
  773. pmxl->Target.vDriverVersion = pMixerData->pConfigurationData->DeviceCaps.vDriverVersion;
  774. }
  775. InternalLoadString(pConfigData->PnameStringId,
  776. pmxl->Target.szPname,
  777. sizeof(pmxl->Target.szPname) / sizeof(TCHAR));
  778. return MMSYSERR_NOERROR;
  779. }
  780. /*************************************************************************
  781. Query and setting APIs
  782. *************************************************************************/
  783. MMRESULT MxdGetDevCaps(
  784. PMIXER_DRIVER_ALLOC pMixerData,
  785. LPMIXERCAPS pmxcaps,
  786. DWORD cbmxcaps
  787. )
  788. {
  789. MIXERCAPS mxCaps;
  790. mxCaps.wMid = pMixerData->pConfigurationData->DeviceCaps.wMid;
  791. mxCaps.wPid = pMixerData->pConfigurationData->DeviceCaps.wPid;
  792. mxCaps.vDriverVersion = pMixerData->pConfigurationData->DeviceCaps.vDriverVersion;
  793. mxCaps.fdwSupport = pMixerData->pConfigurationData->DeviceCaps.fdwSupport;
  794. mxCaps.cDestinations = pMixerData->pConfigurationData->DeviceCaps.cDestinations;
  795. InternalLoadString(pMixerData->pConfigurationData->DeviceCaps.PnameStringId,
  796. mxCaps.szPname,
  797. sizeof(mxCaps.szPname) / sizeof(mxCaps.szPname[0]));
  798. CopyMemory((PVOID)pmxcaps,
  799. (PVOID)&mxCaps,
  800. min(cbmxcaps, sizeof(MIXERCAPS)));
  801. return MMSYSERR_NOERROR;
  802. }
  803. DWORD MxdGetLineInfo
  804. (
  805. PMIXER_DRIVER_ALLOC pMixerData,
  806. LPMIXERLINE pmxl,
  807. DWORD fdwInfo
  808. )
  809. {
  810. /*
  811. ** determine what line to get the information for. a mixer driver
  812. ** MUST support the following four queries:
  813. **
  814. ** MIXER_GETLINEINFOF_DESTINATION
  815. ** MIXER_GETLINEINFOF_SOURCE
  816. ** MIXER_GETLINEINFOF_LINEID
  817. ** MIXER_GETLINEINFOF_COMPONENTTYPE
  818. **
  819. **
  820. ** others (no others are defined for V1.00 of MSMIXMGR) can optionally
  821. ** be supported. if this mixer driver does NOT support a query, then
  822. ** MMSYSERR_NOTSUPPORTED must be returned.
  823. */
  824. switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK)
  825. {
  826. /*
  827. ** MIXER_GETLINEINFOF_DESTINATION
  828. **
  829. ** this query specifies that the caller is interested in the
  830. ** line information for MIXERLINE.dwDestination. this index can
  831. ** range from 0 to MIXERCAPS.cDestinations - 1.
  832. **
  833. ** valid elements of MIXERLINE:
  834. ** cbStruct
  835. ** dwDestination
  836. **
  837. ** all other MIXERLINE elements are undefined.
  838. */
  839. case MIXER_GETLINEINFOF_DESTINATION:
  840. /*
  841. ** Our lines our ordered so that the destination lines
  842. ** come first
  843. */
  844. if (pmxl->dwDestination >=
  845. pMixerData->pConfigurationData->DeviceCaps.cDestinations)
  846. {
  847. dprintf1(("MxdGetLineInfo: caller specified an invalid destination."));
  848. return (MIXERR_INVALLINE);
  849. }
  850. return MxdCreateLineInfo(pMixerData, pmxl->dwDestination, pmxl);
  851. /*
  852. ** MIXER_GETLINEINFOF_SOURCE
  853. **
  854. ** this query specifies that the caller is interested in the
  855. ** line information for MIXERLINE.dwSource associated with
  856. ** MIXERLINE.dwDestination.
  857. **
  858. ** valid elements of MIXERLINE:
  859. ** cbStruct
  860. ** dwDestination
  861. ** dwSource
  862. **
  863. ** all other MIXERLINE elements are undefined.
  864. */
  865. case MIXER_GETLINEINFOF_SOURCE:
  866. dprintf3(("---MxdGetLineInfo: by source"));
  867. /*
  868. ** Search for the right destination and source by stepping
  869. ** through all the lines
  870. */
  871. {
  872. UINT i;
  873. PMIXER_DD_LINE_CONFIGURATION_DATA pLineData;
  874. for (i = pMixerData->pConfigurationData->DeviceCaps.cDestinations,
  875. pLineData = pMixerData->pLineConfigurationData + i;
  876. i < pMixerData->pConfigurationData->NumberOfLines;
  877. i++, pLineData++) {
  878. if (pmxl->dwDestination == (DWORD)pLineData->Destination &&
  879. pmxl->dwSource == (DWORD)pLineData->Source) {
  880. return MxdCreateLineInfo(pMixerData, i, pmxl);
  881. }
  882. }
  883. }
  884. return MIXERR_INVALLINE;
  885. /*
  886. ** MIXER_GETLINEINFOF_LINEID
  887. **
  888. ** this query specifies that the caller is interested in the
  889. ** line information for MIXERLINE.dwLineID. the dwLineID is
  890. ** completely mixer driver dependent, so this driver must validate
  891. ** the ID.
  892. **
  893. ** valid elements of MIXERLINE:
  894. ** cbStruct
  895. ** dwLineID
  896. **
  897. ** all other MIXERLINE elements are undefined.
  898. */
  899. case MIXER_GETLINEINFOF_LINEID:
  900. dprintf3(("MxdGetLineInfo: by lineid"));
  901. if (pmxl->dwLineID >
  902. pMixerData->pConfigurationData->NumberOfLines)
  903. {
  904. dprintf1(("MxdGetLineInfo: caller specified an invalid line id."));
  905. return MIXERR_INVALLINE;
  906. }
  907. return MxdCreateLineInfo(pMixerData, pmxl->dwLineID, pmxl);
  908. /*
  909. ** MIXER_GETLINEINFOF_COMPONENTTYPE
  910. **
  911. ** this query specifies that the caller is interested in the
  912. ** line information for MIXERLINE.dwComponentType
  913. **
  914. ** valid elements of MIXERLINE:
  915. ** cbStruct
  916. ** dwComponentType
  917. **
  918. ** all other MIXERLINE elements are undefined.
  919. */
  920. case MIXER_GETLINEINFOF_COMPONENTTYPE:
  921. dprintf3(("MxdGetLineInfo: by componenttype"));
  922. /*
  923. ** Walk all lines until we find the one with the right
  924. ** component type.
  925. **
  926. */
  927. {
  928. UINT i;
  929. PMIXER_DD_LINE_CONFIGURATION_DATA pLineData;
  930. for (i = 0, pLineData = pMixerData->pLineConfigurationData;
  931. i < pMixerData->pConfigurationData->NumberOfLines;
  932. i++, pLineData++) {
  933. if (pmxl->dwComponentType ==
  934. pLineData->dwComponentType) {
  935. return MxdCreateLineInfo(pMixerData, i, pmxl);
  936. }
  937. }
  938. }
  939. return MIXERR_INVALLINE;
  940. /*
  941. ** MIXER_GETLINEINFOF_TARGETTYPE
  942. **
  943. ** this query specifies that the caller is interested in the
  944. ** line information for MIXERLINE.Target.
  945. **
  946. ** valid elements of MIXERLINE:
  947. ** cbStruct
  948. ** Target.dwType
  949. ** Target.wMid
  950. ** Target.wPid
  951. ** Target.vDriverVersion
  952. ** Target.szPname
  953. **
  954. ** all other MIXERLINE elements are undefined.
  955. */
  956. case MIXER_GETLINEINFOF_TARGETTYPE:
  957. {
  958. /*
  959. ** Check Manufacturer id and driver version against
  960. ** the mixer driver caps
  961. */
  962. if (pMixerData->pConfigurationData->DeviceCaps.wMid != pmxl->Target.wMid)
  963. return (MIXERR_INVALLINE);
  964. if (pMixerData->pConfigurationData->DeviceCaps.vDriverVersion != pmxl->Target.vDriverVersion)
  965. return MIXERR_INVALLINE;
  966. /*
  967. ** Walk all lines until we find one with the right target
  968. ** device info.
  969. */
  970. {
  971. UINT i;
  972. PMIXER_DD_LINE_CONFIGURATION_DATA pLineData;
  973. for (i = 0, pLineData = pMixerData->pLineConfigurationData;
  974. i < pMixerData->pConfigurationData->NumberOfLines;
  975. i++, pLineData++) {
  976. if (pmxl->Target.wPid == pLineData->wPid &&
  977. pmxl->Target.dwType == (DWORD)pLineData->Type) {
  978. MIXERLINE mxl;
  979. MMRESULT mmRet;
  980. /*
  981. ** Get the data to expand the product name
  982. */
  983. mmRet = MxdCreateLineInfo(pMixerData, i, &mxl);
  984. if (mmRet != MMSYSERR_NOERROR) {
  985. return mmRet;
  986. }
  987. /*
  988. ** Check product name
  989. */
  990. if (_tcsnicmp(mxl.Target.szPname, pmxl->Target.szPname,
  991. sizeof(mxl.Target.szPname)) == 0) {
  992. *pmxl = mxl;
  993. return MMSYSERR_NOERROR;
  994. }
  995. }
  996. }
  997. }
  998. /*
  999. ** No line compared
  1000. */
  1001. return MIXERR_INVALLINE;
  1002. }
  1003. /*
  1004. ** if the query type is not something this driver understands, then
  1005. ** return MMSYSERR_NOTSUPPORTED.
  1006. */
  1007. default:
  1008. return (MMSYSERR_NOTSUPPORTED);
  1009. }
  1010. }
  1011. DWORD MxdGetLineControls(
  1012. PMIXER_DRIVER_ALLOC pMixerData,
  1013. LPMIXERLINECONTROLS pmxlc,
  1014. DWORD fdwControl
  1015. )
  1016. {
  1017. LPMIXERCONTROL pmxctrl;
  1018. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  1019. UINT i;
  1020. pmxctrl = pmxlc->pamxctrl;
  1021. /*
  1022. ** Determine for which control(s) to get the information.
  1023. ** A mixer driver MUST support the following three queries:
  1024. **
  1025. ** MIXER_GETLINECONTROLSF_ALL
  1026. ** MIXER_GETLINECONTROLSF_ONEBYID
  1027. ** MIXER_GETLINECONTROLSF_ONEBYTYPE
  1028. **
  1029. ** Others (no others are defined for V1.00 of MSMIXMGR) can optionally
  1030. ** be supported. If this mixer driver does NOT support a query, then
  1031. ** MMSYSERR_NOTSUPPORTED must be returned.
  1032. */
  1033. switch (fdwControl & MIXER_GETLINECONTROLSF_QUERYMASK)
  1034. {
  1035. /*
  1036. ** MIXER_GETLINECONTROLSF_ALL
  1037. **
  1038. ** This query specifies that the caller is interested in ALL
  1039. ** controls for a line.
  1040. **
  1041. ** Valid elements of MIXERLINECONTROLS:
  1042. ** cbStruct
  1043. ** dwLineID
  1044. ** cControls
  1045. ** cbmxctrl
  1046. ** pamxctrl
  1047. **
  1048. ** All other MIXERLINECONTROLS elements are undefined.
  1049. */
  1050. case MIXER_GETLINECONTROLSF_ALL:
  1051. dprintf3(("MxdGetLineControls: all"));
  1052. /*
  1053. ** Check Line ID
  1054. */
  1055. if (pmxlc->dwLineID >=
  1056. pMixerData->pConfigurationData->NumberOfLines) {
  1057. dprintf1(("MxdGetLineControls: caller specified an invalid dwLineID."));
  1058. return MIXERR_INVALLINE;
  1059. }
  1060. /*
  1061. ** Check the number of controls requested
  1062. */
  1063. if (pMixerData->pLineConfigurationData[pmxlc->dwLineID].cControls
  1064. != pmxlc->cControls) {
  1065. dprintf1(("MxdGetLineControls: caller specified an invalid dwLineID."));
  1066. return MMSYSERR_INVALPARAM;
  1067. }
  1068. /*
  1069. ** Find the control data for this control
  1070. */
  1071. for (i = 0, pControlData = pMixerData->pControlConfigurationData;
  1072. i < pMixerData->pConfigurationData->NumberOfControls;
  1073. i++, pControlData++) {
  1074. if ((DWORD)pControlData->LineID == pmxlc->dwLineID) {
  1075. MxdCreateControlInfo(pMixerData, i, pmxctrl);
  1076. /*
  1077. ** This is going to be confusing!
  1078. */
  1079. pmxctrl = (LPMIXERCONTROL)((PBYTE)pmxctrl + pmxlc->cbmxctrl);
  1080. }
  1081. }
  1082. /*
  1083. ** Tell the what's valid
  1084. */
  1085. pmxlc->cbmxctrl = sizeof(MIXERCONTROL);
  1086. return MMSYSERR_NOERROR;
  1087. /*
  1088. ** MIXER_GETLINECONTROLSF_ONEBYID
  1089. **
  1090. ** This query specifies that the caller is interested in ONE
  1091. ** control specified by dwControlID.
  1092. **
  1093. ** valid elements of MIXERLINECONTROLS:
  1094. ** cbStruct
  1095. ** dwControlID
  1096. ** cbmxctrl
  1097. ** pamxctrl
  1098. **
  1099. ** all other MIXERLINECONTROLS elements are undefined.
  1100. */
  1101. case MIXER_GETLINECONTROLSF_ONEBYID:
  1102. dprintf3(("MxdGetLineControls: by id"));
  1103. /*
  1104. ** Make sure the control ID they gave us is OK.
  1105. */
  1106. if (pmxlc->dwControlID >=
  1107. pMixerData->pConfigurationData->NumberOfControls) {
  1108. return MIXERR_INVALCONTROL;
  1109. }
  1110. {
  1111. MIXERCONTROL mxctrl;
  1112. DWORD dwLineID;
  1113. dwLineID = MxdCreateControlInfo(pMixerData,
  1114. pmxlc->dwControlID,
  1115. &mxctrl);
  1116. if (mxctrl.fdwControl & MIXERCONTROL_CONTROLF_DISABLED) {
  1117. return MIXERR_INVALCONTROL;
  1118. }
  1119. pmxlc->cbmxctrl = sizeof(MIXERCONTROL);
  1120. /*
  1121. ** Set the line ID (what a hack!!)
  1122. */
  1123. pmxlc->dwLineID = dwLineID;
  1124. CopyMemory(pmxctrl, &mxctrl, sizeof(MIXERCONTROL));
  1125. }
  1126. return MMSYSERR_NOERROR;
  1127. /*
  1128. ** MIXER_GETLINECONTROLSF_ONEBYTYPE
  1129. **
  1130. ** This query specifies that the caller is interested in the
  1131. ** FIRST control of type dwControlType on dwLineID.
  1132. **
  1133. ** Valid elements of MIXERLINECONTROLS:
  1134. ** cbStruct
  1135. ** dwLineID
  1136. ** dwControlType
  1137. ** cbmxctrl
  1138. ** pamxctrl
  1139. **
  1140. ** all other MIXERLINECONTROLS elements are undefined.
  1141. */
  1142. case MIXER_GETLINECONTROLSF_ONEBYTYPE:
  1143. dprintf3(("MxdGetLineControls: by type"));
  1144. if (pmxlc->dwLineID > pMixerData->pConfigurationData->NumberOfControls)
  1145. {
  1146. dprintf1(("MxdGetLineControls: caller specified an invalid dwLineID."));
  1147. return MIXERR_INVALLINE;
  1148. }
  1149. /*
  1150. ** Find the control data for this control
  1151. */
  1152. for (i = 0, pControlData = pMixerData->pControlConfigurationData;
  1153. i < pMixerData->pConfigurationData->NumberOfControls;
  1154. i++, pControlData++) {
  1155. if ((DWORD)pControlData->LineID == pmxlc->dwLineID &&
  1156. (DWORD)pControlData->dwControlType == pmxlc->dwControlType) {
  1157. MxdCreateControlInfo(pMixerData, i, pmxctrl);
  1158. /*
  1159. ** Tell them what's valid
  1160. */
  1161. pmxlc->cbmxctrl = sizeof(MIXERCONTROL);
  1162. return MMSYSERR_NOERROR;
  1163. }
  1164. }
  1165. return MIXERR_INVALCONTROL;
  1166. /*
  1167. ** If the query type is not something this driver understands,
  1168. ** then return MMSYSERR_NOTSUPPORTED.
  1169. */
  1170. default:
  1171. return MMSYSERR_NOTSUPPORTED;
  1172. }
  1173. }
  1174. /*
  1175. ** Check MIXERCONTROLDETAILS info
  1176. **
  1177. ** Returns number of items if OK or (UINT)-1 otherwise
  1178. */
  1179. UINT MxdValidateMixerControlData(
  1180. PMIXER_DRIVER_ALLOC pMixerData,
  1181. LPMIXERCONTROLDETAILS pmxcd
  1182. )
  1183. {
  1184. UINT NumberOfItems;
  1185. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  1186. pControlData = &pMixerData->pControlConfigurationData[pmxcd->dwControlID];
  1187. /*
  1188. ** Work out how many items are being requested and validate
  1189. ** the number requested.
  1190. */
  1191. if (pmxcd->cChannels != 1 &&
  1192. pmxcd->cChannels !=
  1193. pMixerData->pLineConfigurationData[
  1194. pControlData->LineID].cChannels) {
  1195. return (UINT)-1;
  1196. }
  1197. NumberOfItems = pmxcd->cChannels;
  1198. if (pmxcd->cMultipleItems != pControlData->cMultipleItems) {
  1199. return (UINT)-1;
  1200. }
  1201. if (pControlData->fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE) {
  1202. NumberOfItems *= pmxcd->cMultipleItems;
  1203. }
  1204. //
  1205. // Having made the following rule the APPs don't keep it !!!
  1206. //
  1207. #if 0
  1208. else {
  1209. if (pmxcd->cMultipleItems != 0) {
  1210. return (UINT)-1;
  1211. }
  1212. }
  1213. #endif
  1214. return NumberOfItems;
  1215. }
  1216. MMRESULT MxdGetControlDetails
  1217. (
  1218. PMIXER_DRIVER_ALLOC pMixerData,
  1219. LPMIXERCONTROLDETAILS pmxcd,
  1220. DWORD fdwDetails
  1221. )
  1222. {
  1223. UINT NumberOfItems;
  1224. if (pmxcd->dwControlID >= pMixerData->pConfigurationData->NumberOfControls)
  1225. {
  1226. return MIXERR_INVALCONTROL;
  1227. }
  1228. NumberOfItems = MxdValidateMixerControlData(pMixerData, pmxcd);
  1229. if (NumberOfItems == (UINT)-1) {
  1230. return MIXERR_INVALVALUE;
  1231. }
  1232. /*
  1233. ** Check for LISTTEXT
  1234. */
  1235. switch (MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails) {
  1236. case MIXER_GETCONTROLDETAILSF_VALUE:
  1237. {
  1238. if (!DeviceIoControl(pMixerData->hDevice,
  1239. IOCTL_MIX_GET_CONTROL_DATA,
  1240. &pmxcd->dwControlID,
  1241. sizeof(MIXER_DD_READ_DATA),
  1242. (PVOID)pmxcd->paDetails,
  1243. pmxcd->cbDetails * NumberOfItems,
  1244. &pMixerData->BytesReturned,
  1245. NULL)) {
  1246. return sndTranslateStatus();
  1247. }
  1248. return MMSYSERR_NOERROR;
  1249. }
  1250. case MIXER_GETCONTROLDETAILSF_LISTTEXT:
  1251. {
  1252. PMIXER_DD_CONTROL_CONFIGURATION_DATA pControlData;
  1253. /*
  1254. ** Validate the control id and channel
  1255. */
  1256. pControlData = &pMixerData->pControlConfigurationData[pmxcd->dwControlID];
  1257. {
  1258. UINT i;
  1259. LPMIXERCONTROLDETAILS_LISTTEXT pmxListText;
  1260. for (i = 0,
  1261. pmxListText = (LPMIXERCONTROLDETAILS_LISTTEXT)
  1262. pmxcd->paDetails;
  1263. i < NumberOfItems;
  1264. i++,
  1265. pmxListText = (LPMIXERCONTROLDETAILS_LISTTEXT)
  1266. ((PBYTE)pmxListText + pmxcd->cbDetails))
  1267. {
  1268. PMIXER_DD_CONTROL_LISTTEXT pListText;
  1269. pListText =
  1270. GetControlText(pMixerData, pmxcd->dwControlID, i);
  1271. if (pListText == NULL) {
  1272. return MMSYSERR_INVALPARAM;
  1273. }
  1274. pmxListText->dwParam1 = pListText->dwParam1;
  1275. pmxListText->dwParam2 = pListText->dwParam2;
  1276. InternalLoadString(pListText->SubControlTextStringId,
  1277. pmxListText->szName,
  1278. sizeof(pmxListText->szName) / sizeof(TCHAR));
  1279. }
  1280. }
  1281. return MMSYSERR_NOERROR;
  1282. }
  1283. default:
  1284. return MMSYSERR_NOTSUPPORTED;
  1285. }
  1286. }
  1287. MMRESULT
  1288. MxdSetControlDetails
  1289. (
  1290. PMIXER_DRIVER_ALLOC pMixerData,
  1291. LPMIXERCONTROLDETAILS pmxcd,
  1292. DWORD fdwDetails
  1293. )
  1294. {
  1295. UINT NumberOfItems;
  1296. if (pmxcd->dwControlID >= pMixerData->pConfigurationData->NumberOfControls)
  1297. {
  1298. return MIXERR_INVALCONTROL;
  1299. }
  1300. NumberOfItems = MxdValidateMixerControlData(pMixerData, pmxcd);
  1301. if (NumberOfItems == (UINT)-1) {
  1302. return MIXERR_INVALVALUE;
  1303. }
  1304. /*
  1305. ** Check for custom controls
  1306. */
  1307. switch (MIXER_SETCONTROLDETAILSF_QUERYMASK & fdwDetails) {
  1308. /*
  1309. ** Non-custom - just call the kernel driver to set the
  1310. ** details.
  1311. */
  1312. case MIXER_SETCONTROLDETAILSF_VALUE:
  1313. {
  1314. /*
  1315. ** Sneaky hack to pass the control id in.
  1316. ** DeviceIoControl wouldn't work because all the 'input'
  1317. ** has to be in a single structure so we'd need to
  1318. ** concatenate our data which would be a real pain.
  1319. */
  1320. pMixerData->WriteOvl.Offset = pmxcd->dwControlID;
  1321. if (!WriteFile(pMixerData->hDevice,
  1322. (PVOID)pmxcd->paDetails,
  1323. pmxcd->cbDetails * NumberOfItems,
  1324. &pMixerData->BytesReturned,
  1325. &pMixerData->WriteOvl)) {
  1326. return (MMRESULT)sndTranslateStatus();
  1327. }
  1328. /*
  1329. ** Check data length returned
  1330. */
  1331. // ???
  1332. return MMSYSERR_NOERROR;
  1333. }
  1334. case MIXER_SETCONTROLDETAILSF_CUSTOM:
  1335. {
  1336. /*
  1337. ** Call the custom dialog and then set the data into the
  1338. ** control
  1339. */
  1340. if (pMixerData->fnCustom) {
  1341. MMRESULT mmr;
  1342. mmr = (*pMixerData->fnCustom)(pMixerData,
  1343. pmxcd,
  1344. fdwDetails);
  1345. if (mmr != MMSYSERR_NOERROR) {
  1346. return mmr;
  1347. }
  1348. }
  1349. return
  1350. MxdSetControlDetails(
  1351. pMixerData,
  1352. pmxcd,
  1353. fdwDetails ^
  1354. (MIXER_SETCONTROLDETAILSF_CUSTOM ^
  1355. MIXER_SETCONTROLDETAILSF_VALUE));
  1356. }
  1357. default:
  1358. return MMSYSERR_NOTSUPPORTED;
  1359. }
  1360. }
  1361. /****************************************************************************
  1362. **
  1363. ** DWORD mxdMessage
  1364. **
  1365. ** Description:
  1366. **
  1367. **
  1368. ** Arguments:
  1369. ** UINT uDevId:
  1370. **
  1371. ** UINT uMsg:
  1372. **
  1373. ** DWORD dwUser:
  1374. **
  1375. ** DWORD dwParam1:
  1376. **
  1377. ** DWORD dwParam2:
  1378. **
  1379. ** Return (DWORD):
  1380. **
  1381. **
  1382. *****************************************************************************/
  1383. DWORD APIENTRY mxdMessage
  1384. (
  1385. UINT uDevId,
  1386. UINT uMsg,
  1387. DWORD_PTR dwUser,
  1388. DWORD_PTR dwParam1,
  1389. DWORD_PTR dwParam2
  1390. )
  1391. {
  1392. PMIXER_DRIVER_ALLOC pmxdi;
  1393. DWORD dw;
  1394. /*
  1395. ** See if this device is initialized
  1396. */
  1397. if (uMsg != MXDM_INIT &&
  1398. uMsg != MXDM_GETNUMDEVS) {
  1399. if (!sndFindDeviceInstanceData(MIXER_DEVICE,
  1400. uDevId,
  1401. (PVOID *)&pmxdi)) {
  1402. return MMSYSERR_BADDEVICEID;
  1403. }
  1404. if (pmxdi == NULL) {
  1405. if (MxdInitDevice(uDevId, &pmxdi) !=
  1406. MMSYSERR_NOERROR) {
  1407. return MMSYSERR_BADDEVICEID;
  1408. }
  1409. /*
  1410. ** Set the instance data so we find it next time.
  1411. */
  1412. sndSetDeviceInstanceData(MIXER_DEVICE, uDevId, (PVOID)pmxdi);
  1413. }
  1414. }
  1415. switch (uMsg)
  1416. {
  1417. case MXDM_INIT:
  1418. return (0L);
  1419. case MXDM_GETNUMDEVS:
  1420. return sndGetNumDevs(MIXER_DEVICE);
  1421. case MXDM_GETDEVCAPS:
  1422. dw = MxdGetDevCaps(pmxdi, (LPMIXERCAPS)dwParam1, (DWORD)dwParam2);
  1423. return (dw);
  1424. case MXDM_OPEN:
  1425. dw = MxdOpen(pmxdi, (PDWORD_PTR)dwUser, (LPMIXEROPENDESC)dwParam1, (DWORD)dwParam2);
  1426. return (dw);
  1427. case MXDM_CLOSE:
  1428. dw = MxdClose((PMM_MIXER_NOTIFY)dwUser);
  1429. return (dw);
  1430. case MXDM_GETLINEINFO:
  1431. dw = MxdGetLineInfo(pmxdi, (LPMIXERLINE)dwParam1, (DWORD)dwParam2);
  1432. return (dw);
  1433. case MXDM_GETLINECONTROLS:
  1434. dw = MxdGetLineControls(pmxdi, (LPMIXERLINECONTROLS)dwParam1, (DWORD)dwParam2);
  1435. return (dw);
  1436. case MXDM_GETCONTROLDETAILS:
  1437. dw = MxdGetControlDetails(pmxdi, (LPMIXERCONTROLDETAILS)dwParam1, (DWORD)dwParam2);
  1438. return (dw);
  1439. case MXDM_SETCONTROLDETAILS:
  1440. dw = MxdSetControlDetails(pmxdi, (LPMIXERCONTROLDETAILS)dwParam1, (DWORD)dwParam2);
  1441. return (dw);
  1442. }
  1443. return (MMSYSERR_NOTSUPPORTED);
  1444. } // mxdMessage()
  1445.