Leaked source code of windows server 2003
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.

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