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.

2406 lines
70 KiB

  1. /****************************************************************************
  2. *
  3. * wdmaud32.c
  4. *
  5. * 32-bit specific interfaces for WDMAUD
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * 5-12-97 - Noel Cross (NoelC)
  11. *
  12. ***************************************************************************/
  13. #include "wdmdrv.h"
  14. HANDLE ghCallbacks = NULL;
  15. PCALLBACKS gpCallbacks = NULL;
  16. HANDLE ghDevice = NULL;
  17. HANDLE ghMemoryDeviceInterfacePath = NULL;
  18. HANDLE ghMemorySize = NULL;
  19. DWORD gdwSize = 0;
  20. LPWSTR gpszDeviceInterfacePath = NULL;
  21. BOOL wdmaudCritSecInit;
  22. CRITICAL_SECTION wdmaudCritSec;
  23. static TCHAR gszMemoryPathSize[] = TEXT("WDMAUD_Path_Size");
  24. static TCHAR gszMemoryInterfacePath[] = TEXT("WDMAUD_Device_Interface_Path");
  25. static TCHAR gszCallbacks[] = TEXT("Global\\WDMAUD_Callbacks");
  26. extern HANDLE mixercallbackevent;
  27. extern HANDLE mixerhardwarecallbackevent;
  28. extern HANDLE mixercallbackthread;
  29. DWORD waveThread(LPDEVICEINFO DeviceInfo);
  30. DWORD midThread(LPDEVICEINFO DeviceInfo);
  31. DWORD sndTranslateStatus();
  32. typedef struct _SETUPAPIDLINFO {
  33. HINSTANCE hInstSetupAPI;
  34. BOOL (WINAPI *pfnDestroyDeviceInfoList)(HDEVINFO);
  35. BOOL (WINAPI *pfnGetDeviceInterfaceDetailW)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA_W, DWORD, PDWORD, PSP_DEVINFO_DATA);
  36. BOOL (WINAPI *pfnEnumDeviceInterfaces)(HDEVINFO, PSP_DEVINFO_DATA, CONST GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA);
  37. HDEVINFO (WINAPI *pfnGetClassDevsW)(CONST GUID*, PCWSTR, HWND, DWORD);
  38. } SETUPAPIDLINFO;
  39. SETUPAPIDLINFO saInfo = {NULL, NULL, NULL, NULL};
  40. /****************************************************************************
  41. Dynalinking setupapi
  42. ****************************************************************************/
  43. BOOL Init_SetupAPI();
  44. BOOL End_SetupAPI();
  45. BOOL dl_SetupDiDestroyDeviceInfoList
  46. (
  47. HDEVINFO DeviceInfoSet
  48. );
  49. BOOL dl_SetupDiGetDeviceInterfaceDetail
  50. (
  51. HDEVINFO DeviceInfoSet,
  52. PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  53. PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
  54. DWORD DeviceInterfaceDetailDataSize,
  55. PDWORD RequiredSize,
  56. PSP_DEVINFO_DATA DeviceInfoData
  57. );
  58. BOOL dl_SetupDiEnumDeviceInterfaces
  59. (
  60. HDEVINFO DeviceInfoSet,
  61. PSP_DEVINFO_DATA DeviceInfoData,
  62. CONST GUID *InterfaceClassGuid,
  63. DWORD MemberIndex,
  64. PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  65. );
  66. HDEVINFO dl_SetupDiGetClassDevs
  67. (
  68. CONST GUID *ClassGuid,
  69. PCWSTR Enumerator,
  70. HWND hwndParent,
  71. DWORD Flags
  72. );
  73. /****************************************************************************
  74. Setting up SetupAPI Dynalink...
  75. ****************************************************************************/
  76. BOOL Init_SetupAPI
  77. (
  78. void
  79. )
  80. {
  81. if (NULL != saInfo.hInstSetupAPI)
  82. {
  83. return TRUE;
  84. }
  85. DPF(DL_TRACE|FA_SETUP, ("Loading SetupAPI!!!") );
  86. saInfo.hInstSetupAPI = LoadLibrary(TEXT("setupapi.dll"));
  87. if (NULL == saInfo.hInstSetupAPI)
  88. {
  89. return FALSE;
  90. }
  91. saInfo.pfnDestroyDeviceInfoList = (LPVOID)GetProcAddress(saInfo.hInstSetupAPI, "SetupDiDestroyDeviceInfoList");
  92. saInfo.pfnGetDeviceInterfaceDetailW = (LPVOID)GetProcAddress(saInfo.hInstSetupAPI, "SetupDiGetDeviceInterfaceDetailW");
  93. saInfo.pfnEnumDeviceInterfaces = (LPVOID)GetProcAddress(saInfo.hInstSetupAPI, "SetupDiEnumDeviceInterfaces");
  94. saInfo.pfnGetClassDevsW = (LPVOID)GetProcAddress(saInfo.hInstSetupAPI, "SetupDiGetClassDevsW");
  95. if ((NULL == saInfo.pfnDestroyDeviceInfoList) ||
  96. (NULL == saInfo.pfnGetDeviceInterfaceDetailW) ||
  97. (NULL == saInfo.pfnEnumDeviceInterfaces) ||
  98. (NULL == saInfo.pfnGetClassDevsW))
  99. {
  100. FreeLibrary(saInfo.hInstSetupAPI);
  101. ZeroMemory(&saInfo, sizeof(saInfo));
  102. return FALSE;
  103. }
  104. return TRUE;
  105. }
  106. BOOL End_SetupAPI
  107. (
  108. void
  109. )
  110. {
  111. HINSTANCE hInst;
  112. hInst = saInfo.hInstSetupAPI;
  113. if (NULL == hInst)
  114. {
  115. DPF(DL_WARNING|FA_SETUP, ("SetupAPI not dynalinked") );
  116. return FALSE;
  117. }
  118. ZeroMemory(&saInfo, sizeof(saInfo));
  119. FreeLibrary(hInst);
  120. return TRUE;
  121. }
  122. BOOL dl_SetupDiDestroyDeviceInfoList
  123. (
  124. HDEVINFO DeviceInfoSet
  125. )
  126. {
  127. if (NULL == saInfo.hInstSetupAPI)
  128. {
  129. DPF(DL_WARNING|FA_SETUP, ("SetupAPI not dynalinked") );
  130. return FALSE;
  131. }
  132. return (saInfo.pfnDestroyDeviceInfoList)(DeviceInfoSet);
  133. }
  134. BOOL dl_SetupDiGetDeviceInterfaceDetail
  135. (
  136. HDEVINFO DeviceInfoSet,
  137. PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
  138. PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
  139. DWORD DeviceInterfaceDetailDataSize,
  140. PDWORD RequiredSize,
  141. PSP_DEVINFO_DATA DeviceInfoData
  142. )
  143. {
  144. if (NULL == saInfo.hInstSetupAPI)
  145. {
  146. DPF(DL_WARNING|FA_SETUP, ("SetupAPI not dynalinked") );
  147. return FALSE;
  148. }
  149. return (saInfo.pfnGetDeviceInterfaceDetailW)(
  150. DeviceInfoSet,
  151. DeviceInterfaceData,
  152. DeviceInterfaceDetailData,
  153. DeviceInterfaceDetailDataSize,
  154. RequiredSize,
  155. DeviceInfoData);
  156. }
  157. BOOL dl_SetupDiEnumDeviceInterfaces
  158. (
  159. HDEVINFO DeviceInfoSet,
  160. PSP_DEVINFO_DATA DeviceInfoData,
  161. CONST GUID *InterfaceClassGuid,
  162. DWORD MemberIndex,
  163. PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
  164. )
  165. {
  166. if (NULL == saInfo.hInstSetupAPI)
  167. {
  168. DPF(DL_WARNING|FA_SETUP, ("SetupAPI not dynalinked") );
  169. return FALSE;
  170. }
  171. return (saInfo.pfnEnumDeviceInterfaces)(
  172. DeviceInfoSet,
  173. DeviceInfoData,
  174. InterfaceClassGuid,
  175. MemberIndex,
  176. DeviceInterfaceData);
  177. }
  178. HDEVINFO dl_SetupDiGetClassDevs
  179. (
  180. CONST GUID *ClassGuid,
  181. PCWSTR Enumerator,
  182. HWND hwndParent,
  183. DWORD Flags
  184. )
  185. {
  186. if (NULL == saInfo.hInstSetupAPI)
  187. {
  188. DPF(DL_WARNING|FA_SETUP, ("SetupAPI not dynalinked") );
  189. return FALSE;
  190. }
  191. return (saInfo.pfnGetClassDevsW)(
  192. ClassGuid,
  193. Enumerator,
  194. hwndParent,
  195. Flags);
  196. }
  197. PSECURITY_DESCRIPTOR BuildSecurityDescriptor(DWORD AccessMask)
  198. {
  199. PSECURITY_DESCRIPTOR pSd;
  200. PSID pSidSystem;
  201. PSID pSidEveryone;
  202. PACL pDacl;
  203. ULONG cbDacl;
  204. BOOL fSuccess;
  205. BOOL f;
  206. SID_IDENTIFIER_AUTHORITY AuthorityNt = SECURITY_NT_AUTHORITY;
  207. SID_IDENTIFIER_AUTHORITY AuthorityWorld = SECURITY_WORLD_SID_AUTHORITY;
  208. fSuccess = FALSE;
  209. pSd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
  210. if (pSd)
  211. {
  212. if (InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION))
  213. {
  214. if (AllocateAndInitializeSid(&AuthorityNt, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSystem))
  215. {
  216. DPFASSERT(IsValidSid(pSidSystem));
  217. if (AllocateAndInitializeSid(&AuthorityWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidEveryone))
  218. {
  219. DPFASSERT(IsValidSid(pSidEveryone));
  220. cbDacl = sizeof(ACL) +
  221. 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  222. GetLengthSid(pSidSystem) +
  223. GetLengthSid(pSidEveryone);
  224. pDacl = HeapAlloc(GetProcessHeap(), 0, cbDacl);
  225. if (pDacl) {
  226. if (InitializeAcl(pDacl, cbDacl, ACL_REVISION))
  227. {
  228. if (AddAccessAllowedAce(pDacl, ACL_REVISION, GENERIC_ALL, pSidSystem))
  229. {
  230. if (AddAccessAllowedAce(pDacl, ACL_REVISION, AccessMask, pSidEveryone))
  231. {
  232. if (SetSecurityDescriptorDacl(pSd, TRUE, pDacl, FALSE))
  233. {
  234. fSuccess = TRUE;
  235. } else {
  236. DPF(DL_WARNING|FA_SETUP, ("BuildSD: SetSecurityDescriptorDacl failed"));
  237. }
  238. } else {
  239. DPF(DL_WARNING|FA_SETUP, ("BuildSD: AddAccessAlloweAce for Everyone failed"));
  240. }
  241. } else {
  242. DPF(DL_WARNING|FA_SETUP, ("BuildSD: AddAccessAllowedAce for System failed"));
  243. }
  244. } else {
  245. DPF(DL_WARNING|FA_SETUP, ("BuildSD: InitializeAcl failed"));
  246. }
  247. if (!fSuccess) {
  248. f = HeapFree(GetProcessHeap(), 0, pDacl);
  249. DPFASSERT(f);
  250. }
  251. }
  252. FreeSid(pSidEveryone);
  253. } else {
  254. DPF(DL_WARNING|FA_SETUP, ("BuildSD: AllocateAndInitizeSid failed for Everyone"));
  255. }
  256. FreeSid(pSidSystem);
  257. } else {
  258. DPF(DL_WARNING|FA_SETUP, ("BuildSD: AllocateAndInitizeSid failed for System"));
  259. }
  260. } else {
  261. DPF(DL_WARNING|FA_SETUP, ("BuildSD: InitializeSecurityDescriptor failed"));
  262. }
  263. if (!fSuccess) {
  264. f = HeapFree(GetProcessHeap(), 0, pSd);
  265. DPFASSERT(f);
  266. }
  267. }
  268. return fSuccess ? pSd : NULL;
  269. }
  270. void DestroySecurityDescriptor(PSECURITY_DESCRIPTOR pSd)
  271. {
  272. PACL pDacl;
  273. BOOL fDaclPresent;
  274. BOOL fDaclDefaulted;
  275. BOOL f;
  276. if (GetSecurityDescriptorDacl(pSd, &fDaclPresent, &pDacl, &fDaclDefaulted))
  277. {
  278. if (fDaclPresent)
  279. {
  280. f = HeapFree(GetProcessHeap(), 0, pDacl);
  281. DPFASSERT(f);
  282. }
  283. } else {
  284. DPF(DL_WARNING|FA_SETUP, ("DestroySD: GetSecurityDescriptorDacl failed"));
  285. }
  286. f = HeapFree(GetProcessHeap(), 0, pSd);
  287. DPFASSERT(f);
  288. return;
  289. }
  290. /**************************************************************************
  291. @doc EXTERNAL
  292. @api BOOL | DllEntryPoint | This procedure is called whenever a
  293. process attaches or detaches from the DLL.
  294. @rdesc The return value is TRUE if the initialisation completed ok,
  295. FALSE if not.
  296. **************************************************************************/
  297. BOOL WINAPI DllEntryPoint
  298. (
  299. HINSTANCE hinstDLL,
  300. DWORD fdwReason,
  301. LPVOID lpvReserved
  302. )
  303. {
  304. BOOL bRet;
  305. if (fdwReason == DLL_PROCESS_ATTACH)
  306. {
  307. DisableThreadLibraryCalls(hinstDLL);
  308. bRet = LibMain((HANDLE)hinstDLL, 0, NULL);
  309. }
  310. else
  311. {
  312. if (fdwReason == DLL_PROCESS_DETACH)
  313. {
  314. DPF(DL_TRACE|FA_ALL, ("Ending") );
  315. DrvEnd();
  316. }
  317. bRet = TRUE;
  318. }
  319. return bRet;
  320. }
  321. /**************************************************************************
  322. @doc EXTERNAL
  323. @api BOOL | DrvInit | Driver initialization takes place here.
  324. @rdesc The return value is TRUE if the initialisation completed ok,
  325. FALSE if not.
  326. **************************************************************************/
  327. BOOL DrvInit()
  328. {
  329. if (NULL == ghDevice)
  330. {
  331. ghDevice = wdmaOpenKernelDevice();
  332. if (ghDevice == INVALID_HANDLE_VALUE)
  333. {
  334. ghDevice = NULL;
  335. return 0L;
  336. }
  337. }
  338. if (gpCallbacks == NULL) {
  339. if ((gpCallbacks = wdmaGetCallbacks()) == NULL) {
  340. gpCallbacks = wdmaCreateCallbacks();
  341. }
  342. }
  343. try
  344. {
  345. wdmaudCritSecInit = FALSE;
  346. InitializeCriticalSection(&wdmaudCritSec);
  347. }
  348. except(EXCEPTION_EXECUTE_HANDLER)
  349. {
  350. return 0L;
  351. }
  352. wdmaudCritSecInit = TRUE;
  353. return ( 1L ) ;
  354. }
  355. PCALLBACKS wdmaGetCallbacks
  356. (
  357. )
  358. {
  359. PCALLBACKS pCallbacks = NULL;
  360. if (gpCallbacks == NULL) {
  361. ghCallbacks = OpenFileMapping(
  362. FILE_MAP_READ|FILE_MAP_WRITE,
  363. FALSE,
  364. gszCallbacks);
  365. if(ghCallbacks != NULL) {
  366. pCallbacks = MapViewOfFile(
  367. ghCallbacks,
  368. FILE_MAP_READ|FILE_MAP_WRITE,
  369. 0,
  370. 0,
  371. sizeof(CALLBACKS));
  372. if (pCallbacks == NULL) {
  373. CloseHandle(ghCallbacks);
  374. ghCallbacks = NULL;
  375. }
  376. }
  377. }
  378. return (pCallbacks);
  379. }
  380. PCALLBACKS wdmaCreateCallbacks
  381. (
  382. )
  383. {
  384. SECURITY_ATTRIBUTES saCallbacks;
  385. PSECURITY_DESCRIPTOR pSdCallbacks;
  386. PCALLBACKS pCallbacks = NULL;
  387. pSdCallbacks = BuildSecurityDescriptor(FILE_MAP_READ|FILE_MAP_WRITE);
  388. if (pSdCallbacks == NULL) {
  389. return (NULL);
  390. }
  391. saCallbacks.nLength = sizeof(SECURITY_ATTRIBUTES);
  392. saCallbacks.lpSecurityDescriptor = pSdCallbacks;
  393. saCallbacks.bInheritHandle = FALSE;
  394. ghCallbacks = CreateFileMapping(
  395. GetCurrentProcess(),
  396. &saCallbacks,
  397. PAGE_READWRITE,
  398. 0,
  399. sizeof(CALLBACKS),
  400. gszCallbacks);
  401. DestroySecurityDescriptor(pSdCallbacks);
  402. if (ghCallbacks == NULL) {
  403. return (NULL);
  404. }
  405. pCallbacks = (PCALLBACKS) MapViewOfFile(
  406. ghCallbacks,
  407. FILE_MAP_READ|FILE_MAP_WRITE,
  408. 0,
  409. 0,
  410. sizeof(CALLBACKS));
  411. if (pCallbacks == NULL) {
  412. CloseHandle(ghCallbacks);
  413. ghCallbacks = NULL;
  414. return (NULL);
  415. }
  416. pCallbacks->GlobalIndex = 0;
  417. return (pCallbacks);
  418. }
  419. BOOL wdmaSetGlobalDeviceInterfaceSizeandPath
  420. (
  421. LPWSTR pszInterfacePath,
  422. DWORD dwSize
  423. )
  424. {
  425. SECURITY_ATTRIBUTES saPath;
  426. SECURITY_ATTRIBUTES saSize;
  427. PSECURITY_DESCRIPTOR pSdPath;
  428. PSECURITY_DESCRIPTOR pSdSize;
  429. LPWSTR pszMappedDeviceInterfacePath = NULL;
  430. PDWORD pdwMappedSize = NULL;
  431. if (!pszInterfacePath || (dwSize == 0) )
  432. {
  433. return FALSE;
  434. }
  435. pSdPath = BuildSecurityDescriptor(FILE_MAP_READ);
  436. if (NULL == pSdPath)
  437. {
  438. return FALSE;
  439. }
  440. saPath.nLength = sizeof(SECURITY_ATTRIBUTES);
  441. saPath.lpSecurityDescriptor = pSdPath;
  442. saPath.bInheritHandle = FALSE;
  443. //
  444. // Do the path name first and then do the size
  445. //
  446. ghMemoryDeviceInterfacePath = CreateFileMapping(
  447. GetCurrentProcess(),
  448. &saPath,
  449. PAGE_READWRITE,
  450. 0,
  451. dwSize,
  452. gszMemoryInterfacePath);
  453. DestroySecurityDescriptor(pSdPath);
  454. if(NULL == ghMemoryDeviceInterfacePath)
  455. {
  456. // Hmm... for whatever reason we can't create this global memory
  457. // object. Return of size of 0.
  458. return FALSE;
  459. }
  460. pszMappedDeviceInterfacePath = MapViewOfFile(
  461. ghMemoryDeviceInterfacePath,
  462. FILE_MAP_WRITE,
  463. 0,
  464. 0,
  465. dwSize);
  466. if(NULL == pszMappedDeviceInterfacePath)
  467. {
  468. CloseHandle(ghMemoryDeviceInterfacePath);
  469. ghMemoryDeviceInterfacePath = NULL;
  470. return FALSE;
  471. }
  472. // This is the data we need stored
  473. lstrcpyW(pszMappedDeviceInterfacePath, pszInterfacePath);
  474. // Close just the view of the file. We still have the file mapping handle which will
  475. // will be freed in DrvEnd
  476. UnmapViewOfFile(pszMappedDeviceInterfacePath);
  477. //
  478. // Now lets store the size
  479. //
  480. pSdSize = BuildSecurityDescriptor(FILE_MAP_READ);
  481. if (NULL == pSdSize)
  482. {
  483. CloseHandle(ghMemorySize);
  484. return FALSE;
  485. }
  486. saSize.nLength = sizeof(SECURITY_ATTRIBUTES);
  487. saSize.lpSecurityDescriptor = pSdSize;
  488. saSize.bInheritHandle = FALSE;
  489. ghMemorySize = CreateFileMapping(
  490. GetCurrentProcess(),
  491. &saSize,
  492. PAGE_READWRITE,
  493. 0,
  494. sizeof(DWORD),
  495. gszMemoryPathSize);
  496. DestroySecurityDescriptor(pSdSize);
  497. if(NULL == ghMemorySize)
  498. {
  499. // Hmm... for whatever reason we can't create this global memory
  500. // object. Return of size of 0.
  501. CloseHandle(ghMemoryDeviceInterfacePath);
  502. ghMemoryDeviceInterfacePath = NULL;
  503. DPF(DL_WARNING|FA_SETUP, ("Failed to create FileMapping for Path Size"));
  504. return FALSE;
  505. }
  506. pdwMappedSize = MapViewOfFile(
  507. ghMemorySize,
  508. FILE_MAP_WRITE,
  509. 0,
  510. 0,
  511. sizeof(DWORD));
  512. if(NULL == pdwMappedSize)
  513. {
  514. CloseHandle(ghMemorySize);
  515. ghMemorySize = NULL;
  516. CloseHandle(ghMemoryDeviceInterfacePath);
  517. ghMemoryDeviceInterfacePath = NULL;
  518. DPF(DL_WARNING|FA_SETUP, ("Failed to create MappedView for Path Size"));
  519. return FALSE;
  520. }
  521. // This is the data we need stored
  522. *pdwMappedSize = dwSize;
  523. // Close just the view of the file. We still have the file mapping handle which will
  524. // will be freed in DrvEnd
  525. UnmapViewOfFile(pdwMappedSize);
  526. return TRUE;
  527. } // wdmaGetGlobalDeviceInterfacePath()
  528. LPWSTR wdmaGetGlobalDeviceInterfaceViaSetupAPI()
  529. {
  530. LPWSTR pszInterfacePath = NULL;
  531. HDEVINFO hDeviceInfoSet = NULL;
  532. SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
  533. PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetailData = NULL;
  534. BOOL fResult;
  535. DWORD dwSize;
  536. GUID guidWDMAUD = KSCATEGORY_WDMAUD;
  537. //
  538. // Because setupapi is such a pig, we must dynaload it in order to keep it from slowing
  539. // down all processes.
  540. //
  541. if (!Init_SetupAPI())
  542. return NULL;
  543. //
  544. // Open the device information set
  545. //
  546. hDeviceInfoSet = dl_SetupDiGetClassDevs
  547. (
  548. &guidWDMAUD,
  549. NULL,
  550. NULL,
  551. DIGCF_PRESENT | DIGCF_INTERFACEDEVICE
  552. );
  553. if((!hDeviceInfoSet) || (INVALID_HANDLE_VALUE == hDeviceInfoSet))
  554. {
  555. DPF(DL_WARNING|FA_SETUP, ("Can't open device info set (%lu)", GetLastError()) );
  556. fResult = FALSE;
  557. }
  558. else
  559. {
  560. fResult = TRUE;
  561. }
  562. if (fResult)
  563. {
  564. //
  565. // Get the first interface in the set
  566. //
  567. DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
  568. fResult = dl_SetupDiEnumDeviceInterfaces
  569. (
  570. hDeviceInfoSet,
  571. NULL,
  572. &guidWDMAUD,
  573. 0,
  574. &DeviceInterfaceData
  575. );
  576. if(!fResult)
  577. {
  578. DPF(DL_WARNING|FA_SETUP, ("No interfaces matching KSCATEGORY_WDMAUD exist") );
  579. }
  580. }
  581. //
  582. // Get the interface's path
  583. //
  584. if (fResult)
  585. {
  586. fResult = dl_SetupDiGetDeviceInterfaceDetail
  587. (
  588. hDeviceInfoSet,
  589. &DeviceInterfaceData,
  590. NULL,
  591. 0,
  592. &dwSize,
  593. NULL
  594. );
  595. //
  596. // because SetupApi reverses their logic here
  597. //
  598. if(fResult || ERROR_INSUFFICIENT_BUFFER != GetLastError())
  599. {
  600. DPF(DL_WARNING|FA_SETUP, ("Can't get interface detail size (%lu)", GetLastError()));
  601. fResult = FALSE;
  602. }
  603. else
  604. {
  605. fResult = TRUE;
  606. }
  607. if (fResult)
  608. {
  609. pDeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) GlobalAllocPtr( GPTR, dwSize );
  610. if (NULL == pDeviceInterfaceDetailData)
  611. {
  612. fResult = FALSE;
  613. }
  614. }
  615. if (fResult)
  616. {
  617. pDeviceInterfaceDetailData->cbSize = sizeof(*pDeviceInterfaceDetailData);
  618. fResult = dl_SetupDiGetDeviceInterfaceDetail
  619. (
  620. hDeviceInfoSet,
  621. &DeviceInterfaceData,
  622. pDeviceInterfaceDetailData,
  623. dwSize,
  624. NULL,
  625. NULL
  626. );
  627. if (!fResult)
  628. {
  629. GlobalFreePtr(pDeviceInterfaceDetailData);
  630. DPF(DL_WARNING|FA_SETUP, ("Can't get device interface detail (%lu)", GetLastError()) );
  631. }
  632. }
  633. //
  634. // If we get the pathname, return it but also store it in a file mapping so that
  635. // other processes can get this information without having to load setupapi.
  636. //
  637. if (fResult)
  638. {
  639. DPFASSERT(gpszDeviceInterfacePath == NULL);
  640. gpszDeviceInterfacePath = (LPWSTR) GlobalAllocPtr( GPTR, sizeof(WCHAR)*(lstrlenW(pDeviceInterfaceDetailData->DevicePath) + 1));
  641. if (NULL == gpszDeviceInterfacePath)
  642. {
  643. fResult = FALSE;
  644. }
  645. else
  646. {
  647. lstrcpyW(gpszDeviceInterfacePath, pDeviceInterfaceDetailData->DevicePath);
  648. }
  649. fResult = wdmaSetGlobalDeviceInterfaceSizeandPath(pDeviceInterfaceDetailData->DevicePath, sizeof(WCHAR)*(lstrlenW(pDeviceInterfaceDetailData->DevicePath) + 1));
  650. GlobalFreePtr(pDeviceInterfaceDetailData);
  651. }
  652. }
  653. if((hDeviceInfoSet) && (INVALID_HANDLE_VALUE != hDeviceInfoSet))
  654. {
  655. dl_SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
  656. }
  657. End_SetupAPI();
  658. return gpszDeviceInterfacePath;
  659. }
  660. LPWSTR wdmaGetGlobalDeviceInterfacePath
  661. (
  662. DWORD dwSize
  663. )
  664. {
  665. LPWSTR pszMappedDeviceInterfacePath = NULL;
  666. HANDLE hMemory;
  667. if (NULL == gpszDeviceInterfacePath)
  668. {
  669. hMemory = OpenFileMapping(
  670. FILE_MAP_READ,
  671. FALSE,
  672. gszMemoryInterfacePath);
  673. if(NULL == hMemory)
  674. {
  675. // Hmm... for whatever reason we can't create this global memory
  676. // object. Return of size of 0.
  677. DPF(DL_WARNING|FA_SETUP, ("Failed to OpenFileMapping for Interface Path"));
  678. return NULL;
  679. }
  680. pszMappedDeviceInterfacePath = MapViewOfFile(
  681. hMemory,
  682. FILE_MAP_READ,
  683. 0,
  684. 0,
  685. dwSize);
  686. if(NULL == pszMappedDeviceInterfacePath)
  687. {
  688. CloseHandle(hMemory);
  689. DPF(DL_WARNING|FA_SETUP, ("Failed to MapViewOfFile for Interface Path"));
  690. return NULL;
  691. }
  692. gpszDeviceInterfacePath = (LPWSTR) GlobalAllocPtr( GPTR, dwSize );
  693. if (gpszDeviceInterfacePath)
  694. {
  695. // This is the data we needed
  696. lstrcpyW(gpszDeviceInterfacePath, pszMappedDeviceInterfacePath);
  697. }
  698. // Close everything down now
  699. UnmapViewOfFile(pszMappedDeviceInterfacePath);
  700. CloseHandle(hMemory);
  701. }
  702. DPF(DL_TRACE|FA_SETUP, ("Path is: %ls",gpszDeviceInterfacePath));
  703. return (gpszDeviceInterfacePath);
  704. } // wdmaGetGlobalDeviceInterfacePath()
  705. DWORD wdmaGetGlobalDeviceInterfaceSize
  706. (
  707. void
  708. )
  709. {
  710. PDWORD pdwMappedSize;
  711. HANDLE hMemory;
  712. if (0 == gdwSize)
  713. {
  714. hMemory = OpenFileMapping(
  715. FILE_MAP_READ,
  716. FALSE,
  717. gszMemoryPathSize);
  718. if(NULL == hMemory)
  719. {
  720. // Hmm... for whatever reason we can't create this global memory
  721. // object. Return of size of 0.
  722. DPF(DL_WARNING|FA_SETUP, ("Failed to OpenFileMapping for Path Size"));
  723. return 0;
  724. }
  725. pdwMappedSize = MapViewOfFile(
  726. hMemory,
  727. FILE_MAP_READ,
  728. 0,
  729. 0,
  730. sizeof(DWORD));
  731. if(NULL == pdwMappedSize)
  732. {
  733. DPF(DL_WARNING|FA_SETUP, ("Failed to MapViewOfFile for Path Size"));
  734. return 0;
  735. }
  736. // This is the data we needed
  737. gdwSize = *pdwMappedSize;
  738. DPF(DL_TRACE|FA_SETUP, ("Path Size is: %d",gdwSize));
  739. // Unmap the view but close the global handle in DrvEnd
  740. UnmapViewOfFile(pdwMappedSize);
  741. }
  742. return (gdwSize);
  743. } // wdmaGetGlobalDeviceInterfaceSize()
  744. LPWSTR wdmaGetGlobalDeviceInterface()
  745. {
  746. LPWSTR pszInterfacePath = NULL;
  747. DWORD dwSize;
  748. dwSize = wdmaGetGlobalDeviceInterfaceSize();
  749. if (dwSize)
  750. {
  751. pszInterfacePath = wdmaGetGlobalDeviceInterfacePath(dwSize);
  752. }
  753. return pszInterfacePath;
  754. }
  755. LPWSTR wdmaGetDeviceInterface()
  756. {
  757. LPWSTR pszInterfacePath = NULL;
  758. //
  759. // Need to check if this already exists
  760. //
  761. pszInterfacePath = wdmaGetGlobalDeviceInterface();
  762. if (!pszInterfacePath)
  763. {
  764. //
  765. // We haven't found it yet so get ready to call setupapi.
  766. //
  767. pszInterfacePath = wdmaGetGlobalDeviceInterfaceViaSetupAPI();
  768. }
  769. return pszInterfacePath;
  770. }
  771. HANDLE wdmaOpenKernelDevice()
  772. {
  773. HANDLE hDevice = INVALID_HANDLE_VALUE;
  774. LPWSTR pszInterfacePath = NULL;
  775. pszInterfacePath = wdmaGetDeviceInterface();
  776. if (pszInterfacePath)
  777. {
  778. // Open the interface
  779. hDevice =
  780. CreateFile
  781. (
  782. pszInterfacePath,
  783. GENERIC_READ | GENERIC_WRITE,
  784. 0,
  785. NULL,
  786. OPEN_EXISTING,
  787. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  788. NULL
  789. );
  790. if((!hDevice) || (INVALID_HANDLE_VALUE == hDevice))
  791. {
  792. DPF(DL_WARNING|FA_SETUP, ("CreateFile failed to open %S with error %lu", pszInterfacePath, GetLastError()) );
  793. }
  794. }
  795. else
  796. {
  797. DPF(DL_WARNING|FA_SETUP, ("wdmaOpenKernelDevice failed with NULL pathname" ));
  798. }
  799. return hDevice;
  800. }
  801. /**************************************************************************
  802. @doc EXTERNAL
  803. @api void | DrvEnd | Driver cleanup takes place here.
  804. @rdesc The return value is TRUE if the initialisation completed ok,
  805. FALSE if not.
  806. **************************************************************************/
  807. VOID DrvEnd()
  808. {
  809. if (gpszDeviceInterfacePath)
  810. {
  811. GlobalFreePtr(gpszDeviceInterfacePath);
  812. gpszDeviceInterfacePath = NULL;
  813. }
  814. if (NULL != ghDevice)
  815. {
  816. CloseHandle(ghDevice);
  817. ghDevice = NULL;
  818. }
  819. if (NULL != ghMemoryDeviceInterfacePath)
  820. {
  821. CloseHandle(ghMemoryDeviceInterfacePath);
  822. ghMemoryDeviceInterfacePath = NULL;
  823. }
  824. if (NULL != ghMemorySize)
  825. {
  826. CloseHandle(ghMemorySize);
  827. ghMemorySize = NULL;
  828. }
  829. if (NULL != gpCallbacks)
  830. {
  831. UnmapViewOfFile(gpCallbacks);
  832. gpCallbacks = NULL;
  833. }
  834. if (NULL != ghCallbacks)
  835. {
  836. CloseHandle(ghCallbacks);
  837. ghCallbacks = NULL;
  838. }
  839. if (wdmaudCritSecInit)
  840. {
  841. wdmaudCritSecInit=FALSE;
  842. DeleteCriticalSection(&wdmaudCritSec);
  843. }
  844. if( NULL != mixercallbackevent )
  845. {
  846. DPF(DL_WARNING|FA_ALL,("freeing mixercallbackevent") );
  847. CloseHandle(mixercallbackevent);
  848. mixercallbackevent=NULL;
  849. }
  850. if( NULL != mixerhardwarecallbackevent )
  851. {
  852. DPF(DL_WARNING|FA_ALL,("freeing mixerhardwarecallbackevent") );
  853. CloseHandle(mixerhardwarecallbackevent);
  854. mixerhardwarecallbackevent=NULL;
  855. }
  856. if( NULL != mixercallbackthread )
  857. {
  858. DPF(DL_WARNING|FA_ALL,("freeing mixercallbackthread") );
  859. CloseHandle(mixercallbackthread);
  860. mixercallbackthread=NULL;
  861. }
  862. return;
  863. }
  864. /****************************************************************************
  865. * @doc INTERNAL
  866. *
  867. * @api DWORD | wdmaudGetDevCaps | This function returns the device capabilities
  868. * of a WDM driver.
  869. *
  870. * @parm DWORD | id | Device id
  871. *
  872. * @parm UINT | DeviceType | type of device
  873. *
  874. * @parm LPBYTE | lpCaps | Far pointer to a WAVEOUTCAPS structure to
  875. * receive the information.
  876. *
  877. * @parm DWORD | dwSize | Size of the WAVEOUTCAPS structure.
  878. *
  879. * @rdesc MMSYS.. return code
  880. ***************************************************************************/
  881. MMRESULT FAR wdmaudGetDevCaps
  882. (
  883. LPDEVICEINFO DeviceInfo,
  884. MDEVICECAPSEX FAR* pdc
  885. )
  886. {
  887. if (pdc->cbSize == 0)
  888. return MMSYSERR_NOERROR;
  889. //
  890. // Make sure that we don't take the critical section
  891. // in wdmaudIoControl
  892. //
  893. DeviceInfo->OpenDone = 0;
  894. //
  895. // Inject a tag into the devcaps to signify that it is
  896. // Unicode
  897. //
  898. ((LPWAVEOUTCAPS)pdc->pCaps)->wMid = UNICODE_TAG;
  899. return wdmaudIoControl(DeviceInfo,
  900. pdc->cbSize,
  901. pdc->pCaps,
  902. IOCTL_WDMAUD_GET_CAPABILITIES);
  903. }
  904. /**************************************************************************
  905. @doc EXTERNAL
  906. @api void | wdmaudIoControl | Proxies requests for information
  907. to and from wdmaud.sys. This routine is synchronous.
  908. @rdesc The return value is TRUE if the initialisation completed ok,
  909. FALSE if not.
  910. **************************************************************************/
  911. /*
  912. Note: wdmaudIoControl calls wdmaud.sys through the DeviceIoControl routine. Take note that if wdmaud.sys
  913. returns an error, like STATUS_INVALID_PARAMETER or STATUS_INSUFFICIENT_RESOURCES the
  914. output buffer will not get filled! DeviceIoControl will only fill that buffer on STATUS_SUCCESS.
  915. Why is this important to know? Well, wdmaud.sys takes advantage of this in order to return specific error
  916. codes. In other words, in order for wdmaud.sys to return MIXERR_INVALCONTROL it returns
  917. STATUS_SUCCESS with the mmr value of the DeviceInfo structure set to MIXERR_INVALCONTROL.
  918. */
  919. MMRESULT FAR wdmaudIoControl
  920. (
  921. LPDEVICEINFO DeviceInfo,
  922. DWORD dwSize,
  923. PVOID pData,
  924. ULONG IoCode
  925. )
  926. {
  927. BOOL fResult;
  928. MMRESULT mmr;
  929. OVERLAPPED ov;
  930. ULONG cbDeviceInfo;
  931. ULONG cbReturned;
  932. if (NULL == ghDevice)
  933. {
  934. MMRRETURN( MMSYSERR_NOTENABLED );
  935. }
  936. RtlZeroMemory( &ov, sizeof( OVERLAPPED ) );
  937. if (NULL == (ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL )))
  938. MMRRETURN( MMSYSERR_NOMEM );
  939. //
  940. // Only take the critical section if there is an open
  941. // wave handle. This is to ensure that the lpWaveQueue
  942. // is not modified during the ioctl. Without this
  943. // protection the copy at the end of the DeviceIoControl
  944. // could copy an old DeviceInfo that is not in sync
  945. // with the current DeviceInfo.
  946. //
  947. if ( (DeviceInfo->DeviceType != MixerDevice) &&
  948. (DeviceInfo->DeviceType != AuxDevice) &&
  949. (DeviceInfo->OpenDone == 1) )
  950. CRITENTER ;
  951. //
  952. // Wrap the data buffer around the device context.
  953. //
  954. DeviceInfo->DataBuffer = pData;
  955. DeviceInfo->DataBufferSize = dwSize;
  956. //
  957. // Since we are not letting the OS do the user-to-kernel
  958. // space mapping, we will have to do the mapping ourselves
  959. // for writes to data buffers in wdmaud.sys.
  960. //
  961. cbDeviceInfo = sizeof(*DeviceInfo) +
  962. (lstrlenW(DeviceInfo->wstrDeviceInterface) * sizeof(WCHAR));
  963. fResult =
  964. DeviceIoControl( ghDevice,
  965. IoCode,
  966. DeviceInfo,
  967. cbDeviceInfo,
  968. DeviceInfo,
  969. sizeof(*DeviceInfo),
  970. &cbReturned,
  971. &ov );
  972. if (!fResult)
  973. {
  974. if (ERROR_IO_PENDING == GetLastError())
  975. {
  976. WaitForSingleObject( ov.hEvent, INFINITE );
  977. }
  978. mmr = sndTranslateStatus();
  979. }
  980. else
  981. {
  982. mmr = MMSYSERR_NOERROR;
  983. }
  984. if ( (DeviceInfo->DeviceType != MixerDevice) &&
  985. (DeviceInfo->DeviceType != AuxDevice) &&
  986. (DeviceInfo->OpenDone == 1) )
  987. CRITLEAVE ;
  988. CloseHandle( ov.hEvent );
  989. MMRRETURN( mmr );
  990. }
  991. /****************************************************************************
  992. * @doc INTERNAL
  993. *
  994. * @api void | sndTranslateStatus | This function translates an NT status
  995. * code into a multimedia error code as far as possible.
  996. *
  997. * @parm NTSTATUS | Status | The NT base operating system return status.
  998. *
  999. * @rdesc The multimedia error code.
  1000. ***************************************************************************/
  1001. DWORD sndTranslateStatus()
  1002. {
  1003. #if DBG
  1004. UINT n;
  1005. switch (n=GetLastError()) {
  1006. #else
  1007. switch (GetLastError()) {
  1008. #endif
  1009. case NO_ERROR:
  1010. case ERROR_IO_PENDING:
  1011. return MMSYSERR_NOERROR;
  1012. case ERROR_BUSY:
  1013. return MMSYSERR_ALLOCATED;
  1014. case ERROR_NOT_SUPPORTED:
  1015. case ERROR_INVALID_FUNCTION:
  1016. return MMSYSERR_NOTSUPPORTED;
  1017. case ERROR_NOT_ENOUGH_MEMORY:
  1018. case ERROR_NO_SYSTEM_RESOURCES:
  1019. return MMSYSERR_NOMEM;
  1020. case ERROR_ACCESS_DENIED:
  1021. return MMSYSERR_BADDEVICEID;
  1022. case ERROR_INSUFFICIENT_BUFFER:
  1023. case ERROR_INVALID_PARAMETER:
  1024. case ERROR_INVALID_USER_BUFFER:
  1025. return MMSYSERR_INVALPARAM;
  1026. case ERROR_NOT_READY:
  1027. case ERROR_GEN_FAILURE:
  1028. return MMSYSERR_ERROR;
  1029. case ERROR_FILE_NOT_FOUND:
  1030. return MMSYSERR_NODRIVER;
  1031. default:
  1032. DPF(DL_WARNING|FA_DEVICEIO, ("sndTranslateStatus: LastError = %d", n));
  1033. return MMSYSERR_ERROR;
  1034. }
  1035. }
  1036. /****************************************************************************
  1037. * @doc INTERNAL
  1038. *
  1039. * @api MMRESULT | wdmaudSubmitWaveHeader | Pass a new buffer to the Auxiliary
  1040. * thread for a wave device.
  1041. *
  1042. * @parm LPWAVEALLOC | DeviceInfo | The data associated with the logical wave
  1043. * device.
  1044. *
  1045. * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
  1046. *
  1047. * @rdesc A MMSYS... type return code for the application.
  1048. *
  1049. * @comm The buffer flags are set and the buffer is passed to the auxiliary
  1050. * device task for processing.
  1051. ***************************************************************************/
  1052. MMRESULT wdmaudSubmitWaveHeader
  1053. (
  1054. LPDEVICEINFO DeviceInfo,
  1055. LPWAVEHDR pHdr
  1056. )
  1057. {
  1058. LPDEVICEINFO WaveHeaderDeviceInfo;
  1059. PWAVEPREPAREDATA pWavePrepareData;
  1060. ULONG cbRead;
  1061. ULONG cbWritten;
  1062. ULONG cbDeviceInfo;
  1063. BOOL fResult;
  1064. MMRESULT mmr;
  1065. if (NULL == ghDevice)
  1066. {
  1067. MMRRETURN( MMSYSERR_NOTENABLED );
  1068. }
  1069. WaveHeaderDeviceInfo = GlobalAllocDeviceInfo(DeviceInfo->wstrDeviceInterface);
  1070. if (!WaveHeaderDeviceInfo)
  1071. {
  1072. MMRRETURN( MMSYSERR_NOMEM );
  1073. }
  1074. //
  1075. // Catch the case when an application doesn't prepare headers correctly
  1076. //
  1077. if (!pHdr->reserved)
  1078. {
  1079. //
  1080. // This should never happen! wdmaudSubmitWaveHeader is called from
  1081. // waveWrite which is called from handling the WIDM_ADDBUFFER and
  1082. // WODM_WRITE messages. On both of these messages, we check that
  1083. // the header has been prepared!
  1084. //
  1085. DPF(DL_ERROR|FA_SYNC,("Unprepared header!") );
  1086. GlobalFreeDeviceInfo( WaveHeaderDeviceInfo );
  1087. return MMSYSERR_INVALPARAM;
  1088. }
  1089. //
  1090. // Free later in the callback routine
  1091. //
  1092. pWavePrepareData = (PWAVEPREPAREDATA)pHdr->reserved;
  1093. pWavePrepareData->pdi = WaveHeaderDeviceInfo;
  1094. cbDeviceInfo = sizeof(*WaveHeaderDeviceInfo) +
  1095. (lstrlenW(WaveHeaderDeviceInfo->wstrDeviceInterface) * sizeof(WCHAR));
  1096. //
  1097. // Fill the wave header's deviceinfo structure
  1098. //
  1099. WaveHeaderDeviceInfo->DeviceType = DeviceInfo->DeviceType;
  1100. WaveHeaderDeviceInfo->DeviceNumber = DeviceInfo->DeviceNumber;
  1101. WaveHeaderDeviceInfo->DeviceHandle = DeviceInfo->DeviceHandle;
  1102. WaveHeaderDeviceInfo->DataBuffer = pHdr;
  1103. WaveHeaderDeviceInfo->DataBufferSize = sizeof( WAVEHDR );
  1104. if (WaveInDevice == DeviceInfo->DeviceType)
  1105. {
  1106. fResult = DeviceIoControl(ghDevice, IOCTL_WDMAUD_WAVE_IN_READ_PIN,
  1107. WaveHeaderDeviceInfo, cbDeviceInfo,
  1108. WaveHeaderDeviceInfo, sizeof(*WaveHeaderDeviceInfo),
  1109. &cbWritten, pWavePrepareData->pOverlapped);
  1110. }
  1111. else // WaveOutDevice
  1112. {
  1113. fResult = DeviceIoControl(ghDevice, IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN,
  1114. WaveHeaderDeviceInfo, cbDeviceInfo,
  1115. WaveHeaderDeviceInfo, sizeof(*WaveHeaderDeviceInfo),
  1116. &cbRead, pWavePrepareData->pOverlapped);
  1117. }
  1118. mmr = sndTranslateStatus();
  1119. if (MMSYSERR_NOERROR == mmr)
  1120. {
  1121. mmr = wdmaudCreateCompletionThread ( DeviceInfo );
  1122. }
  1123. return mmr;
  1124. }
  1125. /****************************************************************************
  1126. * @doc INTERNAL
  1127. *
  1128. * @api DWORD | wdmaudSubmitMidiOutHeader | Synchronously process a midi output
  1129. * buffer.
  1130. *
  1131. * @rdesc A MMSYS... type return code for the application.
  1132. ***************************************************************************/
  1133. MMRESULT FAR wdmaudSubmitMidiOutHeader
  1134. (
  1135. LPDEVICEINFO DeviceInfo,
  1136. LPMIDIHDR pHdr
  1137. )
  1138. {
  1139. BOOL fResult;
  1140. MMRESULT mmr;
  1141. OVERLAPPED ov;
  1142. ULONG cbReturned;
  1143. ULONG cbDeviceInfo;
  1144. if (NULL == ghDevice)
  1145. {
  1146. MMRRETURN( MMSYSERR_NOTENABLED );
  1147. }
  1148. RtlZeroMemory( &ov, sizeof( OVERLAPPED ) );
  1149. if (NULL == (ov.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL )))
  1150. return FALSE;
  1151. cbDeviceInfo = sizeof(*DeviceInfo) +
  1152. (lstrlenW(DeviceInfo->wstrDeviceInterface) * sizeof(WCHAR));
  1153. //
  1154. // Wrap the data buffer around the device context.
  1155. //
  1156. DeviceInfo->DataBuffer = pHdr;
  1157. DeviceInfo->DataBufferSize = sizeof( MIDIHDR );
  1158. //
  1159. // Since we are not letting the OS do the user-to-kernel
  1160. // space mapping, we will have to do the mapping ourselves
  1161. // for writes to data buffers in wdmaud.sys.
  1162. //
  1163. fResult =
  1164. DeviceIoControl( ghDevice,
  1165. IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA,
  1166. DeviceInfo, cbDeviceInfo,
  1167. DeviceInfo, sizeof(*DeviceInfo),
  1168. &cbReturned,
  1169. &ov );
  1170. if (!fResult)
  1171. {
  1172. if (ERROR_IO_PENDING == GetLastError())
  1173. {
  1174. WaitForSingleObject( ov.hEvent, INFINITE );
  1175. mmr = MMSYSERR_NOERROR;
  1176. }
  1177. else
  1178. {
  1179. mmr = sndTranslateStatus();
  1180. }
  1181. }
  1182. else
  1183. {
  1184. mmr = MMSYSERR_NOERROR;
  1185. }
  1186. CloseHandle( ov.hEvent );
  1187. MMRRETURN( mmr );
  1188. }
  1189. /****************************************************************************
  1190. * @doc INTERNAL
  1191. *
  1192. * @api MMRESULT | wdmaudGetMidiData | Pass a buffer down to
  1193. * wdmaud.sys to be filled in with KSMUSICFORMAT data.
  1194. *
  1195. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical
  1196. * device.
  1197. *
  1198. * @rdesc A MMSYS... type return code for the application.
  1199. ***************************************************************************/
  1200. MMRESULT wdmaudGetMidiData
  1201. (
  1202. LPDEVICEINFO DeviceInfo,
  1203. LPMIDIDATALISTENTRY pOldMidiDataListEntry
  1204. )
  1205. {
  1206. LPDEVICEINFO MidiDataDeviceInfo;
  1207. ULONG cbWritten;
  1208. ULONG cbDeviceInfo;
  1209. LPMIDIDATALISTENTRY pMidiDataListEntry;
  1210. LPMIDIDATALISTENTRY pTemp;
  1211. MMRESULT mmr;
  1212. if (NULL == ghDevice)
  1213. {
  1214. MMRRETURN( MMSYSERR_NOTENABLED );
  1215. }
  1216. //
  1217. // Don't need to allocate another buffer and create another
  1218. // event if we can reuse the old one
  1219. //
  1220. if (pOldMidiDataListEntry)
  1221. {
  1222. //
  1223. // Make sure to pull it off the front of the queue
  1224. // before adding again
  1225. //
  1226. CRITENTER ;
  1227. DeviceInfo->DeviceState->lpMidiDataQueue = DeviceInfo->DeviceState->lpMidiDataQueue->lpNext;
  1228. CRITLEAVE ;
  1229. pMidiDataListEntry = pOldMidiDataListEntry;
  1230. // RtlZeroMemory( &pMidiDataListEntry->MidiData, sizeof(MIDIDATA) );
  1231. // ResetEvent( ((LPOVERLAPPED)(pMidiDataListEntry->pOverlapped))->hEvent );
  1232. }
  1233. else
  1234. {
  1235. //
  1236. // Allocate a buffer to receive the music data
  1237. //
  1238. pMidiDataListEntry = (LPMIDIDATALISTENTRY) GlobalAllocPtr( GPTR, sizeof(MIDIDATALISTENTRY));
  1239. if (NULL == pMidiDataListEntry)
  1240. {
  1241. MMRRETURN( MMSYSERR_NOMEM );
  1242. }
  1243. #ifdef DEBUG
  1244. pMidiDataListEntry->dwSig=MIDIDATALISTENTRY_SIGNATURE;
  1245. #endif
  1246. pMidiDataListEntry->MidiDataDeviceInfo = GlobalAllocDeviceInfo(DeviceInfo->wstrDeviceInterface);
  1247. if (!pMidiDataListEntry->MidiDataDeviceInfo)
  1248. {
  1249. GlobalFreePtr(pMidiDataListEntry);
  1250. MMRRETURN( MMSYSERR_NOMEM );
  1251. }
  1252. //
  1253. // Initialize music data structure
  1254. //
  1255. pMidiDataListEntry->pOverlapped =
  1256. (LPOVERLAPPED)HeapAlloc( GetProcessHeap(), 0, sizeof( OVERLAPPED ));
  1257. if (NULL == pMidiDataListEntry->pOverlapped)
  1258. {
  1259. GlobalFreePtr(pMidiDataListEntry->MidiDataDeviceInfo );
  1260. GlobalFreePtr(pMidiDataListEntry);
  1261. MMRRETURN( MMSYSERR_NOMEM );
  1262. }
  1263. RtlZeroMemory( pMidiDataListEntry->pOverlapped, sizeof( OVERLAPPED ) );
  1264. if (NULL == ( ((LPOVERLAPPED)(pMidiDataListEntry->pOverlapped))->hEvent =
  1265. CreateEvent( NULL, FALSE, FALSE, NULL )))
  1266. {
  1267. HeapFree( GetProcessHeap(), 0, pMidiDataListEntry->pOverlapped);
  1268. GlobalFreePtr(pMidiDataListEntry->MidiDataDeviceInfo );
  1269. GlobalFreePtr(pMidiDataListEntry);
  1270. MMRRETURN( MMSYSERR_NOMEM );
  1271. }
  1272. }
  1273. //
  1274. // Cauterize the next pointer for new and old list entries
  1275. //
  1276. pMidiDataListEntry->lpNext = NULL;
  1277. //
  1278. // Add music data structure to a queue
  1279. //
  1280. CRITENTER ;
  1281. if (!DeviceInfo->DeviceState->lpMidiDataQueue)
  1282. {
  1283. DeviceInfo->DeviceState->lpMidiDataQueue = pMidiDataListEntry;
  1284. pTemp = NULL;
  1285. #ifdef UNDER_NT
  1286. if( (DeviceInfo->DeviceState->hevtQueue) &&
  1287. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTHREE) &&
  1288. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTWO) )
  1289. {
  1290. DPF(DL_TRACE|FA_MIDI,("SetEvent on hevtQueue") );
  1291. SetEvent( DeviceInfo->DeviceState->hevtQueue );
  1292. }
  1293. #endif
  1294. }
  1295. else
  1296. {
  1297. for (pTemp = DeviceInfo->DeviceState->lpMidiDataQueue;
  1298. pTemp->lpNext != NULL;
  1299. pTemp = pTemp->lpNext);
  1300. pTemp->lpNext = pMidiDataListEntry;
  1301. }
  1302. CRITLEAVE ;
  1303. DPF(DL_TRACE|FA_MIDI, ("MidiData submitted: pMidiDataListEntry = 0x%08lx", pMidiDataListEntry) );
  1304. MidiDataDeviceInfo = pMidiDataListEntry->MidiDataDeviceInfo;
  1305. cbDeviceInfo = sizeof(*MidiDataDeviceInfo) +
  1306. (lstrlenW(MidiDataDeviceInfo->wstrDeviceInterface) * sizeof(WCHAR));
  1307. //
  1308. // Wrap the data buffer around the device context.
  1309. //
  1310. MidiDataDeviceInfo->DeviceType = DeviceInfo->DeviceType;
  1311. MidiDataDeviceInfo->DeviceNumber = DeviceInfo->DeviceNumber;
  1312. MidiDataDeviceInfo->DataBuffer = &pMidiDataListEntry->MidiData;
  1313. MidiDataDeviceInfo->DataBufferSize = sizeof( MIDIDATA );
  1314. //
  1315. // Send this buffer down to wdmaud.sys to fill in data
  1316. //
  1317. DeviceIoControl(ghDevice, IOCTL_WDMAUD_MIDI_IN_READ_PIN,
  1318. MidiDataDeviceInfo, cbDeviceInfo,
  1319. MidiDataDeviceInfo, sizeof(*MidiDataDeviceInfo),
  1320. &cbWritten, pMidiDataListEntry->pOverlapped);
  1321. mmr = sndTranslateStatus();
  1322. //
  1323. // Make sure that the completion thread is running
  1324. //
  1325. if (MMSYSERR_NOERROR == mmr)
  1326. {
  1327. mmr = wdmaudCreateCompletionThread ( DeviceInfo );
  1328. }
  1329. else
  1330. {
  1331. // Unlink...
  1332. CloseHandle( ((LPOVERLAPPED)(pMidiDataListEntry->pOverlapped))->hEvent );
  1333. HeapFree( GetProcessHeap(), 0, pMidiDataListEntry->pOverlapped);
  1334. GlobalFreePtr( MidiDataDeviceInfo );
  1335. GlobalFreePtr( pMidiDataListEntry );
  1336. if (pTemp)
  1337. {
  1338. pTemp->lpNext = NULL;
  1339. }
  1340. else
  1341. {
  1342. DeviceInfo->DeviceState->lpMidiDataQueue = NULL;
  1343. }
  1344. }
  1345. MMRRETURN( mmr );
  1346. }
  1347. /****************************************************************************
  1348. * @doc INTERNAL
  1349. *
  1350. * @api MMRESULT | wdmaudCreateCompletionThread |
  1351. *
  1352. * @rdesc A MMSYS... type return code for the application.
  1353. *
  1354. ***************************************************************************/
  1355. MMRESULT wdmaudCreateCompletionThread
  1356. (
  1357. LPDEVICEINFO DeviceInfo
  1358. )
  1359. {
  1360. PTHREAD_START_ROUTINE fpThreadRoutine;
  1361. DPFASSERT(DeviceInfo->DeviceType == WaveOutDevice ||
  1362. DeviceInfo->DeviceType == WaveInDevice ||
  1363. DeviceInfo->DeviceType == MidiInDevice);
  1364. //
  1365. // Thread already created so...forget about it.
  1366. //
  1367. if (DeviceInfo->DeviceState->fThreadRunning)
  1368. {
  1369. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1370. return MMSYSERR_NOERROR;
  1371. }
  1372. //
  1373. // Pick which thread routine we want to create
  1374. //
  1375. if (WaveInDevice == DeviceInfo->DeviceType ||
  1376. WaveOutDevice == DeviceInfo->DeviceType)
  1377. {
  1378. fpThreadRoutine = (PTHREAD_START_ROUTINE)waveThread;
  1379. }
  1380. else if (MidiInDevice == DeviceInfo->DeviceType)
  1381. {
  1382. fpThreadRoutine = (PTHREAD_START_ROUTINE)midThread;
  1383. }
  1384. else
  1385. {
  1386. MMRRETURN( MMSYSERR_ERROR );
  1387. }
  1388. //
  1389. // Is there a problem with hThread? Well, here is where it gets set
  1390. // to a non-zero value. Basically, during this creation process, we
  1391. // look to see if there is already a work item scheduled on this thread. if
  1392. // not, we create one and schedule it.
  1393. //
  1394. // But, between the point where we check this value and the point where it
  1395. // gets set
  1396. //
  1397. if (NULL == DeviceInfo->DeviceState->hThread)
  1398. {
  1399. #ifdef DEBUG
  1400. if( (DeviceInfo->DeviceState->hevtQueue != NULL) &&
  1401. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTHREE) &&
  1402. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTWO) )
  1403. {
  1404. DPF(DL_ERROR|FA_ALL,("hevtQueue getting overwritten! %08X",DeviceInfo) );
  1405. }
  1406. #endif
  1407. DeviceInfo->DeviceState->hevtQueue =
  1408. CreateEvent( NULL, // no security
  1409. FALSE, // auto reset
  1410. FALSE, // initially not signalled
  1411. NULL ); // unnamed
  1412. #ifdef DEBUG
  1413. if( (DeviceInfo->DeviceState->hevtExitThread != NULL) &&
  1414. (DeviceInfo->DeviceState->hevtExitThread != (HANDLE)FOURTYEIGHT) )
  1415. {
  1416. DPF(DL_ERROR|FA_ALL,("hevtExitThread getting overwritten %08X",DeviceInfo) );
  1417. }
  1418. #endif
  1419. DeviceInfo->DeviceState->hevtExitThread =
  1420. CreateEvent( NULL, // no security
  1421. FALSE, // auto reset
  1422. FALSE, // initially not signalled
  1423. NULL ); // unnamed
  1424. DPFASSERT(NULL == DeviceInfo->DeviceState->hThread);
  1425. DPF(DL_TRACE|FA_SYNC,("Creating Completion Thread") );
  1426. DeviceInfo->DeviceState->hThread =
  1427. CreateThread( NULL, // no security
  1428. 0, // default stack
  1429. (PTHREAD_START_ROUTINE) fpThreadRoutine,
  1430. (PVOID) DeviceInfo, // parameter
  1431. 0, // default create flags
  1432. &DeviceInfo->DeviceState->dwThreadId ); // container for
  1433. // thread id
  1434. //
  1435. // TODO: I need to wait for the thread to actually start
  1436. // before I can move on
  1437. //
  1438. if (DeviceInfo->DeviceState->hThread)
  1439. SetThreadPriority(DeviceInfo->DeviceState->hThread, THREAD_PRIORITY_TIME_CRITICAL);
  1440. }
  1441. if (NULL == DeviceInfo->DeviceState->hThread)
  1442. {
  1443. if (DeviceInfo->DeviceState->hevtQueue)
  1444. {
  1445. CloseHandle( DeviceInfo->DeviceState->hevtQueue );
  1446. DeviceInfo->DeviceState->hevtQueue = NULL;
  1447. CloseHandle( DeviceInfo->DeviceState->hevtExitThread );
  1448. DeviceInfo->DeviceState->hevtExitThread = NULL;
  1449. }
  1450. MMRRETURN( MMSYSERR_ERROR );
  1451. }
  1452. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fThreadRunning, TRUE );
  1453. return MMSYSERR_NOERROR;
  1454. }
  1455. /****************************************************************************
  1456. * @doc INTERNAL
  1457. *
  1458. * @api MMRESULT | wdmaudDestroyCompletionThread |
  1459. *
  1460. * @rdesc A MMSYS... type return code for the application.
  1461. *
  1462. ***************************************************************************/
  1463. MMRESULT wdmaudDestroyCompletionThread
  1464. (
  1465. LPDEVICEINFO DeviceInfo
  1466. )
  1467. {
  1468. MMRESULT mmr;
  1469. if( (mmr=IsValidDeviceInfo(DeviceInfo)) != MMSYSERR_NOERROR )
  1470. {
  1471. MMRRETURN( mmr );
  1472. }
  1473. CRITENTER;
  1474. if( DeviceInfo->DeviceState->hThread )
  1475. {
  1476. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,FALSE);
  1477. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fExit, TRUE );
  1478. //
  1479. // If the thread handling the completion notifications, waveThread and
  1480. // midThread have completed, then hevtQueue will be invalid. We don't
  1481. // want to call SetEvent with invalid info. Also, if the thread has
  1482. // completed, then we know that hevtExitThread will have been signaled and
  1483. // fThreadRunning will be FALSE.
  1484. //
  1485. if( DeviceInfo->DeviceState->fThreadRunning )
  1486. {
  1487. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1488. SetEvent( DeviceInfo->DeviceState->hevtQueue );
  1489. }
  1490. CRITLEAVE;
  1491. //
  1492. // Ok, here we're going to wait until that routine below, waveThread
  1493. // completes and signals us.
  1494. //
  1495. DPF(DL_TRACE|FA_SYNC, ("DestroyThread: Waiting for thread to go away") );
  1496. WaitForSingleObject( DeviceInfo->DeviceState->hevtExitThread, INFINITE );
  1497. DPF(DL_TRACE|FA_SYNC, ("DestroyThread: Done waiting for thread to go away") );
  1498. CRITENTER;
  1499. CloseHandle( DeviceInfo->DeviceState->hThread );
  1500. DeviceInfo->DeviceState->hThread = NULL;
  1501. CloseHandle( DeviceInfo->DeviceState->hevtExitThread );
  1502. DeviceInfo->DeviceState->hevtExitThread = (HANDLE)FOURTYEIGHT; //NULL;
  1503. }
  1504. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fExit, FALSE );
  1505. ISVALIDDEVICEINFO(DeviceInfo);
  1506. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,FALSE);
  1507. CRITLEAVE;
  1508. return MMSYSERR_NOERROR;
  1509. }
  1510. /****************************************************************************
  1511. * @doc INTERNAL
  1512. *
  1513. * @api DWORD | waveThread |
  1514. *
  1515. ***************************************************************************/
  1516. DWORD waveThread
  1517. (
  1518. LPDEVICEINFO DeviceInfo
  1519. )
  1520. {
  1521. BOOL fDone;
  1522. LPWAVEHDR pWaveHdr;
  1523. MMRESULT mmr;
  1524. //
  1525. // Keep looping until all notifications are posted...
  1526. //
  1527. fDone = FALSE;
  1528. while (!fDone )
  1529. {
  1530. fDone = FALSE;
  1531. CRITENTER ;
  1532. ISVALIDDEVICEINFO(DeviceInfo);
  1533. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1534. if(pWaveHdr = DeviceInfo->DeviceState->lpWaveQueue)
  1535. {
  1536. PWAVEPREPAREDATA pWavePrepareData;
  1537. HANDLE hEvent;
  1538. if( (mmr=IsValidWaveHeader(pWaveHdr)) == MMSYSERR_NOERROR )
  1539. {
  1540. pWavePrepareData = (PWAVEPREPAREDATA)pWaveHdr->reserved;
  1541. if( (mmr=IsValidPrepareWaveHeader(pWavePrepareData)) == MMSYSERR_NOERROR )
  1542. {
  1543. hEvent = pWavePrepareData->pOverlapped->hEvent;
  1544. CRITLEAVE ;
  1545. WaitForSingleObject( hEvent, INFINITE );
  1546. CRITENTER ;
  1547. //
  1548. // Validate that our data is still intact
  1549. //
  1550. if( ( (mmr=IsValidDeviceInfo(DeviceInfo)) ==MMSYSERR_NOERROR ) &&
  1551. ( (mmr=IsValidDeviceState(DeviceInfo->DeviceState,TRUE)) == MMSYSERR_NOERROR ) )
  1552. {
  1553. DPF(DL_TRACE|FA_WAVE, ("Calling waveCompleteHeader") );
  1554. waveCompleteHeader(DeviceInfo);
  1555. } else {
  1556. //
  1557. // Problem: Major structures have changed. How can we complete
  1558. // this header? The only thing I can think of here is to
  1559. // terminate the thread.
  1560. //
  1561. goto Terminate_waveThread;
  1562. }
  1563. } else {
  1564. //
  1565. // Problem: reserved field that contains the Prepare data info
  1566. // is corrupt, thus we will not have a valid hEvent to wait on.
  1567. // remove this header and go on to the next.
  1568. //
  1569. DeviceInfo->DeviceState->lpWaveQueue = DeviceInfo->DeviceState->lpWaveQueue->lpNext;
  1570. }
  1571. } else {
  1572. //
  1573. // Problem: Our header is corrupt. We can't possibly wait on this
  1574. // because we'll never get signaled! thus we will not have a valid
  1575. // hEvent to wait on. Remove this header and go on to the next.
  1576. //
  1577. DeviceInfo->DeviceState->lpWaveQueue = DeviceInfo->DeviceState->lpWaveQueue->lpNext;
  1578. }
  1579. CRITLEAVE ;
  1580. }
  1581. else
  1582. {
  1583. // fDone = TRUE;
  1584. if (DeviceInfo->DeviceState->fRunning)
  1585. {
  1586. wdmaudIoControl(DeviceInfo,
  1587. 0,
  1588. NULL,
  1589. DeviceInfo->DeviceType == WaveOutDevice ?
  1590. IOCTL_WDMAUD_WAVE_OUT_PAUSE :
  1591. IOCTL_WDMAUD_WAVE_IN_STOP);
  1592. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fRunning, FALSE );
  1593. }
  1594. CRITLEAVE ;
  1595. WaitForSingleObject( DeviceInfo->DeviceState->hevtQueue, INFINITE );
  1596. //
  1597. // We could have been here for two reasons 1) the thread got starved
  1598. // ie. the header list went empty or 2) we're done with the headers.
  1599. // Only when we're done do we really want to exit this thread.
  1600. //
  1601. if( DeviceInfo->DeviceState->fExit )
  1602. {
  1603. fDone = TRUE;
  1604. }
  1605. }
  1606. }
  1607. CRITENTER;
  1608. ISVALIDDEVICEINFO(DeviceInfo);
  1609. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1610. CloseHandle( DeviceInfo->DeviceState->hevtQueue );
  1611. DeviceInfo->DeviceState->hevtQueue = (HANDLE)FOURTYTWO; // WAS NULL
  1612. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fThreadRunning, FALSE );
  1613. SetEvent( DeviceInfo->DeviceState->hevtExitThread );
  1614. DPF(DL_TRACE|FA_WAVE, ("waveThread: Closing") );
  1615. Terminate_waveThread:
  1616. CRITLEAVE;
  1617. return 0;
  1618. }
  1619. /****************************************************************************
  1620. * @doc INTERNAL
  1621. *
  1622. * @api DWORD | midThread |
  1623. *
  1624. ***************************************************************************/
  1625. DWORD midThread
  1626. (
  1627. LPDEVICEINFO DeviceInfo
  1628. )
  1629. {
  1630. BOOL fDone;
  1631. LPMIDIDATALISTENTRY pMidiDataListEntry;
  1632. int i;
  1633. MMRESULT mmr;
  1634. DPF(DL_TRACE|FA_MIDI, ("Entering") );
  1635. //
  1636. // Keep looping until all notifications are posted...
  1637. //
  1638. fDone = FALSE;
  1639. while (!fDone)
  1640. {
  1641. CRITENTER ;
  1642. ISVALIDDEVICEINFO(DeviceInfo);
  1643. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1644. if (pMidiDataListEntry = DeviceInfo->DeviceState->lpMidiDataQueue)
  1645. {
  1646. HANDLE hEvent;
  1647. if( (mmr=IsValidMidiDataListEntry(pMidiDataListEntry)) == MMSYSERR_NOERROR)
  1648. {
  1649. hEvent = ((LPOVERLAPPED)(pMidiDataListEntry->pOverlapped))->hEvent;
  1650. DPF(DL_TRACE|FA_MIDI, ("Waiting on pMidiDataListEntry = 0x%08lx", pMidiDataListEntry) );
  1651. CRITLEAVE ;
  1652. WaitForSingleObject( hEvent, INFINITE );
  1653. CRITENTER ;
  1654. DPF(DL_TRACE|FA_MIDI, ("Completed pMidiDataListEntry = 0x%08lx", pMidiDataListEntry) );
  1655. if( ((mmr=IsValidDeviceInfo(DeviceInfo)) == MMSYSERR_NOERROR) &&
  1656. ((mmr=IsValidDeviceState(DeviceInfo->DeviceState,TRUE)) == MMSYSERR_NOERROR ) )
  1657. {
  1658. //
  1659. // Parse and callback clients
  1660. //
  1661. wdmaudParseMidiData(DeviceInfo, pMidiDataListEntry);
  1662. if (DeviceInfo->DeviceState->fExit ||
  1663. !DeviceInfo->DeviceState->fRunning)
  1664. {
  1665. //
  1666. // Unlink from queue and free memory
  1667. //
  1668. wdmaudFreeMidiData(DeviceInfo, pMidiDataListEntry);
  1669. }
  1670. else
  1671. {
  1672. //
  1673. // Reuse this buffer to read Midi data
  1674. //
  1675. wdmaudGetMidiData(DeviceInfo, pMidiDataListEntry);
  1676. }
  1677. } else {
  1678. //
  1679. // Problem: Our major structure is bad. There is nothing that
  1680. // we can do, exit and hope for the best.
  1681. //
  1682. goto Terminate_midThread;
  1683. }
  1684. } else {
  1685. //
  1686. // Problem: the pMidiDataListEntry is invalid. We can't use it
  1687. // so we simply move on to the next one and hope for the best.
  1688. //
  1689. DeviceInfo->DeviceState->lpMidiDataQueue = DeviceInfo->DeviceState->lpMidiDataQueue->lpNext;
  1690. }
  1691. CRITLEAVE ;
  1692. }
  1693. else
  1694. {
  1695. fDone = TRUE;
  1696. CRITLEAVE ;
  1697. DPF(DL_TRACE|FA_MIDI, ("Waiting for signal to kill thread") );
  1698. WaitForSingleObject( DeviceInfo->DeviceState->hevtQueue, INFINITE );
  1699. DPF(DL_TRACE|FA_MIDI, ("Done waiting for signal to kill thread") );
  1700. }
  1701. }
  1702. CRITENTER;
  1703. ISVALIDDEVICEINFO(DeviceInfo);
  1704. ISVALIDDEVICESTATE(DeviceInfo->DeviceState,TRUE);
  1705. CloseHandle( DeviceInfo->DeviceState->hevtQueue );
  1706. DeviceInfo->DeviceState->hevtQueue = (HANDLE)FOURTYTHREE; //NULL;
  1707. InterlockedExchange( (LPLONG)&DeviceInfo->DeviceState->fThreadRunning, FALSE );
  1708. SetEvent( DeviceInfo->DeviceState->hevtExitThread );
  1709. DPF(DL_TRACE|FA_MIDI, ("Closing") );
  1710. Terminate_midThread:
  1711. CRITLEAVE;
  1712. return 0;
  1713. }
  1714. BOOL IsMidiDataDiscontinuous
  1715. (
  1716. PKSSTREAM_HEADER pHeader
  1717. )
  1718. {
  1719. DPFASSERT(pHeader);
  1720. //
  1721. // Check the OptionFlags for the end of the midi stream
  1722. //
  1723. return (pHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY);
  1724. }
  1725. ULONG GetStreamHeaderSize
  1726. (
  1727. PKSSTREAM_HEADER pHeader
  1728. )
  1729. {
  1730. DPFASSERT(pHeader);
  1731. //
  1732. // Check the OptionFlags for the end of the midi stream
  1733. //
  1734. return (pHeader->DataUsed);
  1735. }
  1736. BOOL IsSysExData
  1737. (
  1738. LPBYTE MusicData
  1739. )
  1740. {
  1741. DPFASSERT(MusicData);
  1742. return ( IS_SYSEX(*MusicData) ||
  1743. IS_EOX(*MusicData) ||
  1744. IS_DATA_BYTE(*MusicData) );
  1745. }
  1746. BOOL IsEndofSysEx
  1747. (
  1748. LPBYTE MusicData
  1749. )
  1750. {
  1751. DPFASSERT(MusicData);
  1752. return IS_EOX(*(MusicData));
  1753. }
  1754. void wdmaudParseSysExData
  1755. (
  1756. LPDEVICEINFO DeviceInfo,
  1757. LPMIDIDATA pMidiData,
  1758. BOOL MidiDataDiscontinuous
  1759. )
  1760. {
  1761. BOOL fCompleteSysEx = FALSE;
  1762. LPMIDIHDR pMidiInHdr;
  1763. PKSMUSICFORMAT MusicFormat;
  1764. ULONG MusicDataLeft;
  1765. LPBYTE MusicData;
  1766. ULONG RunningTimeMs;
  1767. ULONG DataCopySize;
  1768. ULONG HeaderFreeSpace;
  1769. ULONG MusicFormatDataLeft;
  1770. ULONG MusicFormatDataPosition = 0;
  1771. //
  1772. // Easier to use locals
  1773. //
  1774. MusicFormat = (PKSMUSICFORMAT)&pMidiData->MusicFormat;
  1775. MusicData = (LPBYTE)pMidiData->MusicData;
  1776. MusicDataLeft = pMidiData->StreamHeader.DataUsed;
  1777. RunningTimeMs = 0;
  1778. if ( MidiDataDiscontinuous ||
  1779. IsEndofSysEx(MusicData + MusicFormat->ByteCount - 1) )
  1780. {
  1781. fCompleteSysEx = TRUE;
  1782. }
  1783. while (MusicDataLeft || MidiDataDiscontinuous)
  1784. {
  1785. //
  1786. // update the running time for this Music Format header
  1787. //
  1788. if (MusicFormat->ByteCount == 0)
  1789. {
  1790. RunningTimeMs = DeviceInfo->DeviceState->LastTimeMs;
  1791. }
  1792. else
  1793. {
  1794. RunningTimeMs += MusicFormat->TimeDeltaMs;
  1795. DeviceInfo->DeviceState->LastTimeMs = RunningTimeMs;
  1796. }
  1797. //
  1798. // Get the next header from the queue
  1799. //
  1800. pMidiInHdr = DeviceInfo->DeviceState->lpMidiInQueue;
  1801. while (pMidiInHdr &&
  1802. MusicFormatDataPosition <= MusicFormat->ByteCount)
  1803. {
  1804. HeaderFreeSpace = pMidiInHdr->dwBufferLength -
  1805. pMidiInHdr->dwBytesRecorded;
  1806. MusicFormatDataLeft = MusicFormat->ByteCount -
  1807. MusicFormatDataPosition;
  1808. //
  1809. // Compute the size of the copy
  1810. //
  1811. DataCopySize = min(HeaderFreeSpace,MusicFormatDataLeft);
  1812. //
  1813. // Fill this, baby
  1814. //
  1815. if (DataCopySize)
  1816. {
  1817. RtlCopyMemory(pMidiInHdr->lpData + pMidiInHdr->dwBytesRecorded,
  1818. MusicData + MusicFormatDataPosition,
  1819. DataCopySize);
  1820. }
  1821. //
  1822. // update the number of bytes recorded
  1823. //
  1824. pMidiInHdr->dwBytesRecorded += DataCopySize;
  1825. MusicFormatDataPosition += DataCopySize;
  1826. DPF(DL_TRACE|FA_RECORD, ("Record SysEx: %d(%d) Data=0x%08lx",
  1827. DataCopySize,
  1828. pMidiInHdr->dwBytesRecorded,
  1829. *MusicData) );
  1830. //
  1831. // If the buffer is full or end-of-sysex byte is received,
  1832. // the buffer is marked as 'done' and it's owner is called back.
  1833. //
  1834. if ( (fCompleteSysEx && pMidiInHdr->dwBytesRecorded && (MusicFormatDataPosition == MusicFormat->ByteCount) ) // copied whole SysEx
  1835. || (pMidiInHdr->dwBufferLength == pMidiInHdr->dwBytesRecorded) ) // filled entire buffer
  1836. {
  1837. if (MidiDataDiscontinuous)
  1838. {
  1839. midiInCompleteHeader(DeviceInfo,
  1840. RunningTimeMs,
  1841. MIM_LONGERROR);
  1842. }
  1843. else
  1844. {
  1845. midiInCompleteHeader(DeviceInfo,
  1846. RunningTimeMs,
  1847. MIM_LONGDATA);
  1848. }
  1849. //
  1850. // Grab the next header to fill, if it exists
  1851. //
  1852. pMidiInHdr = DeviceInfo->DeviceState->lpMidiInQueue;
  1853. }
  1854. //
  1855. // Break out of loop when all of the data is copied
  1856. //
  1857. if (MusicFormatDataPosition == MusicFormat->ByteCount)
  1858. {
  1859. break;
  1860. }
  1861. //
  1862. // in the middle of a sysex and we still
  1863. // have room left in the header
  1864. //
  1865. } // while we have more headers and data to copy
  1866. //
  1867. // don't continue messin' with this irp
  1868. //
  1869. if (MidiDataDiscontinuous)
  1870. {
  1871. break;
  1872. }
  1873. MusicDataLeft -= sizeof(KSMUSICFORMAT) + ((MusicFormat->ByteCount + 3) & ~3);
  1874. MusicFormat = (PKSMUSICFORMAT)(MusicData + ((MusicFormat->ByteCount + 3) & ~3));
  1875. MusicData = (LPBYTE)(MusicFormat + 1);
  1876. } // while IrpDataLeft
  1877. return;
  1878. }
  1879. void wdmaudParseShortMidiData
  1880. (
  1881. LPDEVICEINFO DeviceInfo,
  1882. LPMIDIDATA pMidiData,
  1883. BOOL MidiDataDiscontinuous
  1884. )
  1885. {
  1886. BOOL fCompleteSysEx = FALSE;
  1887. LPMIDIHDR pMidiInHdr;
  1888. PKSMUSICFORMAT MusicFormat;
  1889. ULONG MusicDataLeft;
  1890. LPBYTE MusicData;
  1891. ULONG RunningTimeMs;
  1892. ULONG DataCopySize;
  1893. ULONG HeaderFreeSpace;
  1894. ULONG MusicFormatDataLeft;
  1895. ULONG MusicFormatDataPosition = 0;
  1896. //
  1897. // Easier to use locals
  1898. //
  1899. MusicFormat = (PKSMUSICFORMAT)&pMidiData->MusicFormat;
  1900. MusicData = (LPBYTE)pMidiData->MusicData;
  1901. MusicDataLeft = pMidiData->StreamHeader.DataUsed;
  1902. RunningTimeMs = 0;
  1903. while (MusicDataLeft || MidiDataDiscontinuous)
  1904. {
  1905. //
  1906. // update the running time for this Music Format header
  1907. //
  1908. if (MusicFormat->ByteCount == 0)
  1909. {
  1910. RunningTimeMs = DeviceInfo->DeviceState->LastTimeMs;
  1911. }
  1912. else
  1913. {
  1914. RunningTimeMs += MusicFormat->TimeDeltaMs;
  1915. DeviceInfo->DeviceState->LastTimeMs = RunningTimeMs;
  1916. }
  1917. //
  1918. // Non-used bytes should be zero'ed out
  1919. //
  1920. midiCallback(DeviceInfo,
  1921. MIM_DATA,
  1922. *((LPDWORD)MusicData),
  1923. RunningTimeMs);
  1924. //
  1925. // don't continue messin' with this irp
  1926. //
  1927. if (MidiDataDiscontinuous)
  1928. {
  1929. break;
  1930. }
  1931. MusicDataLeft -= sizeof(KSMUSICFORMAT) + ((MusicFormat->ByteCount + 3) & ~3);
  1932. MusicFormat = (PKSMUSICFORMAT)(MusicData + ((MusicFormat->ByteCount + 3) & ~3));
  1933. MusicData = (LPBYTE)(MusicFormat + 1);
  1934. } // while IrpDataLeft
  1935. return;
  1936. }
  1937. /****************************************************************************
  1938. * @doc INTERNAL
  1939. *
  1940. * @api VOID | wdmaudParseMidiData | This routine takes the MIDI data retrieved
  1941. * from kernel mode and calls back the application with the long or short
  1942. * messages packed in the buffer.
  1943. *
  1944. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical midi
  1945. * device.
  1946. *
  1947. * @comm The buffer flags are set and the buffer is passed to the auxiliary
  1948. * device task for processing.
  1949. ****************************************************************************/
  1950. void wdmaudParseMidiData
  1951. (
  1952. LPDEVICEINFO DeviceInfo,
  1953. LPMIDIDATALISTENTRY pMidiDataListEntry
  1954. )
  1955. {
  1956. BOOL MidiDataDiscontinuous;
  1957. ULONG DataRemaining;
  1958. ULONG BytesUsed;
  1959. MMRESULT mmr;
  1960. if( (mmr=IsValidMidiDataListEntry(pMidiDataListEntry)) == MMSYSERR_NOERROR )
  1961. {
  1962. DataRemaining = GetStreamHeaderSize(&pMidiDataListEntry->MidiData.StreamHeader);
  1963. MidiDataDiscontinuous = IsMidiDataDiscontinuous(&pMidiDataListEntry->MidiData.StreamHeader);
  1964. if ( IsSysExData((LPBYTE)pMidiDataListEntry->MidiData.MusicData) )
  1965. {
  1966. wdmaudParseSysExData(DeviceInfo,
  1967. &pMidiDataListEntry->MidiData,
  1968. MidiDataDiscontinuous);
  1969. }
  1970. else
  1971. {
  1972. // Must be short messages
  1973. wdmaudParseShortMidiData(DeviceInfo,
  1974. &pMidiDataListEntry->MidiData,
  1975. MidiDataDiscontinuous);
  1976. }
  1977. }
  1978. }
  1979. /****************************************************************************
  1980. * @doc INTERNAL
  1981. *
  1982. * @api VOID | wdmaudFreeMidiData | This routine unlinks and free the MIDI
  1983. * data structure pointed to on input.
  1984. *
  1985. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical midi
  1986. * device.
  1987. *
  1988. * @parm LPMIDIDATA | pMidiData | The data buffer to be cleaned up
  1989. *
  1990. ****************************************************************************/
  1991. void wdmaudFreeMidiData
  1992. (
  1993. LPDEVICEINFO DeviceInfo,
  1994. LPMIDIDATALISTENTRY pMidiDataListEntry
  1995. )
  1996. {
  1997. //
  1998. // Advance the head of the queue
  1999. //
  2000. DeviceInfo->DeviceState->lpMidiDataQueue = DeviceInfo->DeviceState->lpMidiDataQueue->lpNext;
  2001. //
  2002. // Free all associated data members
  2003. //
  2004. CloseHandle( ((LPOVERLAPPED)(pMidiDataListEntry->pOverlapped))->hEvent );
  2005. HeapFree( GetProcessHeap(), 0, pMidiDataListEntry->pOverlapped );
  2006. GlobalFreeDeviceInfo( pMidiDataListEntry->MidiDataDeviceInfo );
  2007. GlobalFreePtr( pMidiDataListEntry );
  2008. }
  2009. /****************************************************************************
  2010. * @doc INTERNAL
  2011. *
  2012. * @api MMRESULT | wdmaudFreeMidiQ |
  2013. *
  2014. ***************************************************************************/
  2015. MMRESULT wdmaudFreeMidiQ
  2016. (
  2017. LPDEVICEINFO DeviceInfo
  2018. )
  2019. {
  2020. LPMIDIHDR pHdr;
  2021. LPMIDIHDR pTemp;
  2022. DPF(DL_TRACE|FA_MIDI, ("entering") );
  2023. CRITENTER ;
  2024. //
  2025. // Grab the head of the MIDI In queue and iterate through
  2026. // completing the headers
  2027. //
  2028. pHdr = DeviceInfo->DeviceState->lpMidiInQueue;
  2029. DeviceInfo->DeviceState->lpMidiInQueue = NULL ; // mark the queue as empty
  2030. while (pHdr)
  2031. {
  2032. pTemp = pHdr->lpNext;
  2033. pHdr->dwFlags &= ~MHDR_INQUEUE ;
  2034. pHdr->dwFlags |= MHDR_DONE ;
  2035. pHdr->dwBytesRecorded = 0;
  2036. //
  2037. // Invoke the callback function
  2038. //
  2039. midiCallback(DeviceInfo,
  2040. MIM_LONGDATA,
  2041. (DWORD_PTR)pHdr,
  2042. DeviceInfo->DeviceState->LastTimeMs); // NOTE: This is not precise, but there is no way to
  2043. // know what the kernel time is without defining
  2044. // a new interface just for this.
  2045. pHdr = pTemp;
  2046. }
  2047. CRITLEAVE ;
  2048. return MMSYSERR_NOERROR;
  2049. }