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.

4075 lines
127 KiB

  1. /****************************************************************************
  2. *
  3. * sysaudio.c
  4. *
  5. * System Audio Device (SAD) interfaces
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * 5-12-97 - Mike McLaughlin (MikeM)
  11. * 5-19-97 - Noel Cross (NoelC)
  12. *
  13. ***************************************************************************/
  14. #include "wdmsys.h"
  15. #include <wdmguid.h>
  16. static const WCHAR MediaCategories[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\";
  17. static const WCHAR NodeNameValue[] = L"Name";
  18. #pragma PAGEABLE_DATA
  19. ULONG gMidiPreferredDeviceNumber = MAXULONG;
  20. ULONG gWavePreferredSysaudioDevice = MAXULONG;
  21. #pragma PAGEABLE_CODE
  22. #pragma PAGEABLE_DATA
  23. int MyWcsicmp(const wchar_t *pwstr1, const wchar_t *pwstr2)
  24. {
  25. PAGED_CODE();
  26. if (!pwstr1) {
  27. DPF( DL_TRACE|FA_SYSAUDIO,("pwstr1 == NULL"));
  28. return (-1);
  29. }
  30. if (!pwstr2) {
  31. DPF( DL_TRACE|FA_SYSAUDIO, ("pwstr2 == NULL"));
  32. return (-1);
  33. }
  34. return _wcsicmp(pwstr1, pwstr2);
  35. }
  36. extern
  37. DWORD
  38. _cdecl
  39. _NtKernPhysicalDeviceObjectToDevNode(
  40. IN PDEVICE_OBJECT PhysicalDeviceObject
  41. );
  42. #ifndef IO_NO_PARAMETER_CHECKING
  43. #define IO_NO_PARAMETER_CHECKING 0x0100
  44. NTKERNELAPI NTSTATUS IoCreateFile
  45. (
  46. OUT PHANDLE FileHandle,
  47. IN ACCESS_MASK DesiredAccess,
  48. IN POBJECT_ATTRIBUTES ObjectAttributes,
  49. OUT PIO_STATUS_BLOCK IoStatusBlock,
  50. IN PLARGE_INTEGER AllocationSize OPTIONAL,
  51. IN ULONG FileAttributes,
  52. IN ULONG ShareAccess,
  53. IN ULONG Disposition,
  54. IN ULONG CreateOptions,
  55. IN PVOID EaBuffer OPTIONAL,
  56. IN ULONG EaLength,
  57. IN CREATE_FILE_TYPE CreateFileType,
  58. IN PVOID ExtraCreateParameters OPTIONAL,
  59. IN ULONG Options
  60. );
  61. #endif // !IO_NO_PARAMETER_CHECKING
  62. NTSTATUS OpenSysAudioPin
  63. (
  64. ULONG Device,
  65. ULONG PinId,
  66. KSPIN_DATAFLOW DataFlowRequested,
  67. PKSPIN_CONNECT pPinConnect,
  68. PFILE_OBJECT *ppFileObjectPin,
  69. PDEVICE_OBJECT *ppDeviceObjectPin,
  70. PCONTROLS_LIST pControlList
  71. )
  72. {
  73. PFILE_OBJECT pFileObjectDevice = NULL;
  74. KSPIN_COMMUNICATION Communication;
  75. HANDLE hDevice = NULL;
  76. HANDLE hPin = NULL;
  77. NTSTATUS Status = STATUS_SUCCESS;
  78. PAGED_CODE();
  79. Status = OpenSysAudio(&hDevice, &pFileObjectDevice);
  80. if(!NT_SUCCESS(Status))
  81. {
  82. goto exit;
  83. }
  84. //
  85. // Set the default renderer
  86. //
  87. Status = SetSysAudioProperty(pFileObjectDevice,
  88. KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
  89. sizeof(Device),
  90. &Device);
  91. if(!NT_SUCCESS(Status))
  92. {
  93. goto exit;
  94. }
  95. Status = GetPinProperty(pFileObjectDevice,
  96. KSPROPERTY_PIN_COMMUNICATION,
  97. PinId,
  98. sizeof(KSPIN_COMMUNICATION),
  99. &Communication);
  100. if(!NT_SUCCESS(Status))
  101. {
  102. goto exit;
  103. }
  104. if(Communication != KSPIN_COMMUNICATION_SINK &&
  105. Communication != KSPIN_COMMUNICATION_BOTH)
  106. {
  107. Status = STATUS_INVALID_DEVICE_REQUEST;
  108. goto exit;
  109. }
  110. pPinConnect->PinId = PinId;
  111. pPinConnect->PinToHandle = NULL;
  112. if (DataFlowRequested == KSPIN_DATAFLOW_OUT)
  113. {
  114. Status = KsCreatePin(hDevice,
  115. pPinConnect,
  116. GENERIC_READ,
  117. &hPin);
  118. }
  119. else // KSPIN_DATAFLOW_OUT
  120. {
  121. Status = KsCreatePin(hDevice,
  122. pPinConnect,
  123. GENERIC_WRITE,
  124. &hPin);
  125. }
  126. if(!NT_SUCCESS(Status))
  127. {
  128. if(STATUS_NO_MATCH == Status)
  129. {
  130. Status = STATUS_INVALID_DEVICE_REQUEST;
  131. }
  132. hPin = NULL;
  133. goto exit;
  134. }
  135. Status = ObReferenceObjectByHandle(hPin,
  136. GENERIC_READ | GENERIC_WRITE,
  137. NULL,
  138. KernelMode,
  139. ppFileObjectPin,
  140. NULL);
  141. if(!NT_SUCCESS(Status))
  142. {
  143. DPF(DL_WARNING|FA_SYSAUDIO,("ObReferenceObjectByHandle failed Status=%X",Status) );
  144. goto exit;
  145. }
  146. GetControlNodes ( pFileObjectDevice,
  147. *ppFileObjectPin,
  148. PinId,
  149. pControlList ) ;
  150. *ppDeviceObjectPin = IoGetRelatedDeviceObject(*ppFileObjectPin);
  151. exit:
  152. if(hPin != NULL)
  153. {
  154. NtClose(hPin);
  155. }
  156. if(pFileObjectDevice != NULL)
  157. {
  158. ObDereferenceObject(pFileObjectDevice);
  159. }
  160. if(hDevice != NULL)
  161. {
  162. NtClose(hDevice);
  163. }
  164. RETURN(Status);
  165. }
  166. VOID CloseSysAudio
  167. (
  168. PWDMACONTEXT pWdmaContext,
  169. PFILE_OBJECT pFileObjectPin
  170. )
  171. {
  172. ULONG d;
  173. PAGED_CODE();
  174. ObDereferenceObject(pFileObjectPin);
  175. UpdatePreferredDevice(pWdmaContext);
  176. }
  177. NTSTATUS OpenSysAudio
  178. (
  179. PHANDLE pHandle,
  180. PFILE_OBJECT *ppFileObject
  181. )
  182. {
  183. NTSTATUS Status = STATUS_SUCCESS;
  184. PWSTR pwstrSymbolicLinkList = NULL;
  185. PWSTR pwstr;
  186. PAGED_CODE();
  187. ASSERT(*pHandle == NULL);
  188. ASSERT(*ppFileObject == NULL);
  189. Status = IoGetDeviceInterfaces(
  190. &KSCATEGORY_SYSAUDIO,
  191. NULL,
  192. 0,
  193. &pwstrSymbolicLinkList);
  194. if(!NT_SUCCESS(Status)) {
  195. DPF( DL_TRACE|FA_SYSAUDIO, ("IoGetDeviceInterfaces failed: Status=%08x", Status));
  196. goto exit;
  197. }
  198. // There is a double UNICODE_NULL at the end of the list
  199. pwstr = pwstrSymbolicLinkList;
  200. while(*pwstr != UNICODE_NULL) {
  201. Status = OpenDevice(pwstr, pHandle);
  202. if(NT_SUCCESS(Status)) {
  203. break;
  204. }
  205. ASSERT(*pHandle == NULL);
  206. // Get next symbolic link
  207. while(*pwstr++ != UNICODE_NULL);
  208. }
  209. if( NULL == *pHandle )
  210. {
  211. goto exit;
  212. }
  213. //
  214. // Security-Penetration issue:
  215. //
  216. // It has been brought up that using this handle is a security issue since in the time
  217. // between creating the handle and now, the handle might be pointing to a different
  218. // fileobject altogether. I am assured that as long as I don't touch any of the fields
  219. // in the file object and only send 'safe' Ioctls, this will not be a problem.
  220. //
  221. Status = ObReferenceObjectByHandle(
  222. *pHandle,
  223. FILE_READ_DATA | FILE_WRITE_DATA,
  224. *IoFileObjectType,
  225. ExGetPreviousMode(),
  226. ppFileObject,
  227. NULL);
  228. if(!NT_SUCCESS(Status)) {
  229. DPF( DL_TRACE|FA_SYSAUDIO, ("ObReferenceObjectByHandle failed: Status=%08x", Status));
  230. goto exit;
  231. }
  232. exit:
  233. if(!NT_SUCCESS(Status)) {
  234. if(*ppFileObject != NULL) {
  235. ObDereferenceObject(*ppFileObject);
  236. *ppFileObject = NULL;
  237. }
  238. if(*pHandle != NULL) {
  239. NtClose(*pHandle);
  240. *pHandle = NULL;
  241. }
  242. }
  243. AudioFreeMemory_Unknown(&pwstrSymbolicLinkList);
  244. RETURN(Status);
  245. }
  246. NTSTATUS OpenDevice
  247. (
  248. PWSTR pwstrDevice,
  249. PHANDLE pHandle
  250. )
  251. {
  252. IO_STATUS_BLOCK IoStatusBlock;
  253. UNICODE_STRING UnicodeDeviceString;
  254. OBJECT_ATTRIBUTES ObjectAttributes;
  255. PAGED_CODE();
  256. RtlInitUnicodeString(&UnicodeDeviceString, pwstrDevice);
  257. InitializeObjectAttributes(
  258. &ObjectAttributes,
  259. &UnicodeDeviceString,
  260. 0,
  261. NULL,
  262. NULL);
  263. return(IoCreateFile(
  264. pHandle,
  265. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  266. &ObjectAttributes,
  267. &IoStatusBlock,
  268. NULL,
  269. 0,
  270. 0,
  271. FILE_OPEN,
  272. FILE_SYNCHRONOUS_IO_NONALERT,
  273. NULL,
  274. 0,
  275. CreateFileTypeNone,
  276. NULL,
  277. IO_FORCE_ACCESS_CHECK | IO_NO_PARAMETER_CHECKING));
  278. }
  279. NTSTATUS GetPinProperty
  280. (
  281. PFILE_OBJECT pFileObject,
  282. ULONG PropertyId,
  283. ULONG PinId,
  284. ULONG cbProperty,
  285. PVOID pProperty
  286. )
  287. {
  288. ULONG BytesReturned;
  289. KSP_PIN Property;
  290. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  291. PAGED_CODE();
  292. if (pFileObject)
  293. {
  294. Property.Property.Set = KSPROPSETID_Pin;
  295. Property.Property.Id = PropertyId;
  296. Property.Property.Flags = KSPROPERTY_TYPE_GET;
  297. Property.PinId = PinId;
  298. Property.Reserved = 0;
  299. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
  300. PropertyId, PinId) );
  301. Status = KsSynchronousIoControlDevice(
  302. pFileObject,
  303. KernelMode,
  304. IOCTL_KS_PROPERTY,
  305. &Property,
  306. sizeof(Property),
  307. pProperty,
  308. cbProperty,
  309. &BytesReturned);
  310. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
  311. Status,pProperty,cbProperty,BytesReturned) );
  312. if(!NT_SUCCESS(Status)) {
  313. DPF(DL_WARNING|FA_SYSAUDIO,("Property query failed Status=%X",Status) );
  314. goto exit;
  315. }
  316. ASSERT(BytesReturned == cbProperty);
  317. }
  318. exit:
  319. RETURN(Status);
  320. }
  321. NTSTATUS GetPinPropertyEx
  322. (
  323. PFILE_OBJECT pFileObject,
  324. ULONG PropertyId,
  325. ULONG PinId,
  326. PVOID *ppProperty
  327. )
  328. {
  329. ULONG BytesReturned;
  330. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  331. KSP_PIN Pin;
  332. PAGED_CODE();
  333. if (pFileObject)
  334. {
  335. Pin.Property.Set = KSPROPSETID_Pin;
  336. Pin.Property.Id = PropertyId;
  337. Pin.Property.Flags = KSPROPERTY_TYPE_GET;
  338. Pin.PinId = PinId;
  339. Pin.Reserved = 0;
  340. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
  341. PropertyId, PinId) );
  342. Status = KsSynchronousIoControlDevice(
  343. pFileObject,
  344. KernelMode,
  345. IOCTL_KS_PROPERTY,
  346. &Pin,
  347. sizeof(KSP_PIN),
  348. NULL,
  349. 0,
  350. &BytesReturned);
  351. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  352. Status,BytesReturned) );
  353. ASSERT(!NT_SUCCESS(Status));
  354. if(Status != STATUS_BUFFER_OVERFLOW) {
  355. //
  356. // The driver should have returned the number of bytes that we needed
  357. // to allocate and STATUS_BUFFER_OVERFLOW. But, if they returned a
  358. // successful error code, we must not return success. Thus, we're making
  359. // up a new return code - STATUS_INVALID_BUFFER_SIZE.
  360. //
  361. if( NT_SUCCESS(Status) )
  362. Status = STATUS_INVALID_BUFFER_SIZE;
  363. goto exit;
  364. }
  365. if(BytesReturned == 0)
  366. {
  367. Status = STATUS_BUFFER_TOO_SMALL;
  368. goto exit;
  369. }
  370. Status = AudioAllocateMemory_Paged(BytesReturned,
  371. TAG_AudQ_PROPERTY,
  372. ZERO_FILL_MEMORY,
  373. ppProperty );
  374. if(!NT_SUCCESS(Status))
  375. {
  376. goto exit;
  377. }
  378. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, PinId=%X",
  379. PropertyId, PinId) );
  380. Status = KsSynchronousIoControlDevice(
  381. pFileObject,
  382. KernelMode,
  383. IOCTL_KS_PROPERTY,
  384. &Pin,
  385. sizeof(KSP_PIN),
  386. *ppProperty,
  387. BytesReturned,
  388. &BytesReturned);
  389. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  390. Status,BytesReturned) );
  391. if(!NT_SUCCESS(Status))
  392. {
  393. AudioFreeMemory_Unknown(ppProperty);
  394. goto exit;
  395. }
  396. }
  397. exit:
  398. if( !NT_SUCCESS(Status) )
  399. {
  400. *ppProperty = NULL;
  401. }
  402. RETURN(Status);
  403. }
  404. VOID GetControlNodes
  405. (
  406. PFILE_OBJECT pDeviceFileObject,
  407. PFILE_OBJECT pPinFileObject,
  408. ULONG PinId,
  409. PCONTROLS_LIST pControlList
  410. )
  411. {
  412. ULONG i ;
  413. PAGED_CODE();
  414. if ( pControlList == NULL )
  415. {
  416. return ;
  417. }
  418. for ( i = 0; i < pControlList->Count; i++ ) \
  419. {
  420. pControlList->Controls[i].NodeId =
  421. ControlNodeFromGuid (
  422. pDeviceFileObject,
  423. pPinFileObject,
  424. PinId,
  425. &pControlList->Controls[i].Control ) ;
  426. }
  427. }
  428. ULONG ControlNodeFromGuid
  429. (
  430. PFILE_OBJECT pDeviceFileObject,
  431. PFILE_OBJECT pPinFileObject,
  432. ULONG PinId,
  433. GUID* NodeType
  434. )
  435. {
  436. ULONG NumNodes, NumConnections ;
  437. ULONG FirstConnectionIndex ;
  438. PKSMULTIPLE_ITEM pNodeItems, pConnectionItems ;
  439. GUID* pNodes ;
  440. PKSTOPOLOGY_CONNECTION pConnections, pConnection ;
  441. ULONG NodeId ;
  442. PAGED_CODE();
  443. // assume there are no nodes
  444. NodeId = INVALID_NODE ;
  445. pNodeItems = NULL ;
  446. pConnectionItems = NULL ;
  447. // Get the array of Node GUIDs
  448. pNodeItems = GetTopologyProperty ( pDeviceFileObject,
  449. KSPROPERTY_TOPOLOGY_NODES ) ;
  450. if ( pNodeItems == NULL )
  451. {
  452. DPF(DL_WARNING|FA_SYSAUDIO,("GetTopologyProperty NODES failed") );
  453. goto exit ;
  454. }
  455. NumNodes = pNodeItems->Count ;
  456. pNodes = (GUID *)(pNodeItems+1) ;
  457. // Get the array of Connections
  458. pConnectionItems = GetTopologyProperty ( pDeviceFileObject,
  459. KSPROPERTY_TOPOLOGY_CONNECTIONS ) ;
  460. if ( pConnectionItems == NULL )
  461. {
  462. DPF(DL_WARNING|FA_SYSAUDIO,("GetTopologyProperty CONNECTIONS failed") );
  463. goto exit ;
  464. }
  465. NumConnections = pConnectionItems->Count ;
  466. pConnections = (PKSTOPOLOGY_CONNECTION)(pConnectionItems+1) ;
  467. // First get the start connection for the given PinId
  468. FirstConnectionIndex = GetFirstConnectionIndex ( pPinFileObject ) ;
  469. if ( FirstConnectionIndex == 0xffffffff )
  470. {
  471. DPF(DL_WARNING|FA_SYSAUDIO,("GetFirstConnectionIndex failed") );
  472. goto exit ;
  473. }
  474. pConnection = pConnections + FirstConnectionIndex ;
  475. ASSERT ( pConnection ) ;
  476. // NOTE : Assumes DataFlowOut. Need to modify if we want to support
  477. // Volume for wavein pins.
  478. while ((pConnection) && (pConnection->ToNode != KSFILTER_NODE) )
  479. {
  480. if ( pConnection->ToNode >= NumNodes )
  481. {
  482. ASSERT ( 0 ) ;
  483. }
  484. else
  485. {
  486. if (IsEqualGUID(&pNodes[pConnection->ToNode], NodeType))
  487. {
  488. NodeId = pConnection->ToNode ;
  489. break ;
  490. }
  491. }
  492. pConnection = FindConnection ( pConnections,
  493. NumConnections,
  494. pConnection->ToNode,
  495. 0,
  496. WILD_CARD,
  497. WILD_CARD ) ;
  498. }
  499. exit:
  500. AudioFreeMemory_Unknown( &pConnectionItems ) ;
  501. AudioFreeMemory_Unknown( &pNodeItems ) ;
  502. return ( NodeId ) ;
  503. }
  504. PVOID GetTopologyProperty
  505. (
  506. PFILE_OBJECT pDeviceFileObject,
  507. ULONG PropertyId
  508. )
  509. {
  510. KSPROPERTY Property ;
  511. PVOID pBuf = NULL;
  512. ULONG BytesReturned ;
  513. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  514. PAGED_CODE();
  515. BytesReturned = 0;
  516. pBuf = NULL ;
  517. if (pDeviceFileObject)
  518. {
  519. Property.Set = KSPROPSETID_Topology ;
  520. Property.Id = PropertyId ;
  521. Property.Flags = KSPROPERTY_TYPE_GET;
  522. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
  523. PropertyId) );
  524. Status = KsSynchronousIoControlDevice(
  525. pDeviceFileObject,
  526. KernelMode,
  527. IOCTL_KS_PROPERTY,
  528. &Property,
  529. sizeof(Property),
  530. NULL,
  531. 0,
  532. &BytesReturned);
  533. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, BytesRet=%d",
  534. Status,BytesReturned) );
  535. ASSERT(!NT_SUCCESS(Status));
  536. if(Status != STATUS_BUFFER_OVERFLOW) {
  537. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  538. goto exit;
  539. }
  540. Status = AudioAllocateMemory_Paged(BytesReturned,
  541. TAG_Audq_PROPERTY,
  542. ZERO_FILL_MEMORY|LIMIT_MEMORY,
  543. &pBuf );
  544. if(!NT_SUCCESS(Status))
  545. {
  546. goto exit;
  547. }
  548. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
  549. PropertyId) );
  550. Status = KsSynchronousIoControlDevice(
  551. pDeviceFileObject,
  552. KernelMode,
  553. IOCTL_KS_PROPERTY,
  554. &Property,
  555. sizeof(Property),
  556. pBuf,
  557. BytesReturned,
  558. &BytesReturned);
  559. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,pBuf=%X,BytesRet=%d",
  560. Status,pBuf,BytesReturned) );
  561. if(!NT_SUCCESS(Status))
  562. {
  563. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  564. AudioFreeMemory_Unknown ( &pBuf ) ;
  565. goto exit;
  566. }
  567. }
  568. exit:
  569. return pBuf ;
  570. }
  571. PKSTOPOLOGY_CONNECTION FindConnection
  572. (
  573. PKSTOPOLOGY_CONNECTION pConnections,
  574. ULONG NumConnections,
  575. ULONG FromNode,
  576. ULONG FromPin,
  577. ULONG ToNode,
  578. ULONG ToPin
  579. )
  580. {
  581. PKSTOPOLOGY_CONNECTION pConnection ;
  582. ULONG i ;
  583. PAGED_CODE();
  584. pConnection = pConnections ;
  585. for ( i = 0; i < NumConnections; i++ )
  586. {
  587. if ( ((FromNode == WILD_CARD) || (FromNode == pConnection->FromNode)) &&
  588. ((FromPin == WILD_CARD) || (FromPin == pConnection->FromNodePin)) &&
  589. ((ToNode == WILD_CARD) || (ToNode == pConnection->ToNode)) &&
  590. ((ToPin == WILD_CARD) || (ToPin == pConnection->ToNodePin)) )
  591. return pConnection ;
  592. pConnection++ ;
  593. }
  594. return ( NULL ) ;
  595. }
  596. ULONG GetFirstConnectionIndex
  597. (
  598. PFILE_OBJECT pPinFileObject
  599. )
  600. {
  601. KSPROPERTY Property ;
  602. ULONG Index = 0xffffffff;
  603. ULONG BytesReturned ;
  604. NTSTATUS Status = STATUS_INVALID_PARAMETER ;
  605. PAGED_CODE();
  606. if (pPinFileObject)
  607. {
  608. Property.Set = KSPROPSETID_Sysaudio_Pin ;
  609. Property.Id = KSPROPERTY_SYSAUDIO_TOPOLOGY_CONNECTION_INDEX ;
  610. Property.Flags = KSPROPERTY_TYPE_GET;
  611. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X",
  612. Property.Id) );
  613. Status = KsSynchronousIoControlDevice(
  614. pPinFileObject,
  615. KernelMode,
  616. IOCTL_KS_PROPERTY,
  617. &Property,
  618. sizeof(Property),
  619. &Index,
  620. sizeof ( Index ),
  621. &BytesReturned);
  622. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, Index=%X,BytesRet=%d",
  623. Status,Index,BytesReturned) );
  624. }
  625. if(!NT_SUCCESS(Status))
  626. {
  627. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  628. return ( 0xffffffff ) ;
  629. }
  630. return ( Index ) ;
  631. }
  632. VOID UpdatePreferredDevice
  633. (
  634. PWDMACONTEXT pWdmaContext
  635. )
  636. {
  637. ULONG d;
  638. PAGED_CODE();
  639. //
  640. // This causes the preferred sysaudio device to be queried if there
  641. // are no open midi out streams.
  642. //
  643. for(d = 0; d < MAXNUMDEVS; d++)
  644. {
  645. if(pWdmaContext->MidiOutDevs[d].Device != UNUSED_DEVICE &&
  646. pWdmaContext->MidiOutDevs[d].pMidiPin &&
  647. pWdmaContext->MidiOutDevs[d].pMidiPin->fGraphRunning)
  648. {
  649. return;
  650. }
  651. }
  652. pWdmaContext->PreferredSysaudioWaveDevice = gWavePreferredSysaudioDevice;
  653. }
  654. NTSTATUS SetPreferredDevice
  655. (
  656. PWDMACONTEXT pContext,
  657. LPDEVICEINFO pDeviceInfo
  658. )
  659. {
  660. SYSAUDIO_PREFERRED_DEVICE Preferred;
  661. ULONG TranslatedDeviceNumber;
  662. ULONG SysaudioDevice;
  663. ULONG BytesReturned;
  664. NTSTATUS Status;
  665. PAGED_CODE();
  666. if(pContext->pFileObjectSysaudio == NULL) {
  667. Status = STATUS_SUCCESS;
  668. goto exit;
  669. }
  670. TranslatedDeviceNumber = wdmaudTranslateDeviceNumber(
  671. pContext,
  672. pDeviceInfo->DeviceType,
  673. pDeviceInfo->wstrDeviceInterface,
  674. pDeviceInfo->DeviceNumber);
  675. if(MAXULONG == TranslatedDeviceNumber) {
  676. DPF(DL_WARNING|FA_SYSAUDIO,("Invalid Device Number") );
  677. Status = STATUS_INVALID_PARAMETER;
  678. goto exit;
  679. }
  680. SysaudioDevice = pContext->apCommonDevice
  681. [pDeviceInfo->DeviceType][TranslatedDeviceNumber]->Device;
  682. switch(pDeviceInfo->DeviceType) {
  683. case WaveOutDevice:
  684. Preferred.Index = KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT;
  685. gWavePreferredSysaudioDevice = SysaudioDevice;
  686. UpdatePreferredDevice(pContext);
  687. break;
  688. case WaveInDevice:
  689. Preferred.Index = KSPROPERTY_SYSAUDIO_RECORD_DEFAULT;
  690. break;
  691. case MidiOutDevice:
  692. Preferred.Index = KSPROPERTY_SYSAUDIO_MIDI_DEFAULT;
  693. gMidiPreferredDeviceNumber = TranslatedDeviceNumber;
  694. break;
  695. default:
  696. Status = STATUS_SUCCESS;
  697. goto exit;
  698. }
  699. Preferred.Property.Set = KSPROPSETID_Sysaudio;
  700. Preferred.Property.Id = KSPROPERTY_SYSAUDIO_PREFERRED_DEVICE;
  701. Preferred.Property.Flags = KSPROPERTY_TYPE_SET;
  702. if(pDeviceInfo->dwFlags == 0) {
  703. Preferred.Flags = 0;
  704. }
  705. else {
  706. Preferred.Flags = SYSAUDIO_FLAGS_CLEAR_PREFERRED;
  707. if(pDeviceInfo->DeviceType == WaveOutDevice) {
  708. gWavePreferredSysaudioDevice = MAXULONG;
  709. }
  710. else if(pDeviceInfo->DeviceType == MidiOutDevice) {
  711. gMidiPreferredDeviceNumber = MAXULONG;
  712. }
  713. }
  714. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, Preferred=%X",
  715. Preferred,Preferred.Property.Id) );
  716. Status = KsSynchronousIoControlDevice(
  717. pContext->pFileObjectSysaudio,
  718. KernelMode,
  719. IOCTL_KS_PROPERTY,
  720. &Preferred,
  721. sizeof(Preferred),
  722. &SysaudioDevice,
  723. sizeof(SysaudioDevice),
  724. &BytesReturned);
  725. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, SysaudioDevice=%X,BytesRet=%d",
  726. Status,SysaudioDevice,BytesReturned) );
  727. if(!NT_SUCCESS(Status)) {
  728. DPF(DL_WARNING|FA_SYSAUDIO,("Property Query failed Status=%X",Status) );
  729. goto exit;
  730. }
  731. if(pDeviceInfo->DeviceType == WaveOutDevice &&
  732. gMidiPreferredDeviceNumber != MAXULONG) {
  733. ULONG d;
  734. d = pContext->apCommonDevice[MidiOutDevice]
  735. [gMidiPreferredDeviceNumber]->PreferredDevice;
  736. if(d != MAXULONG &&
  737. (d == gMidiPreferredDeviceNumber ||
  738. pContext->apCommonDevice[MidiOutDevice][d]->PreferredDevice == d)) {
  739. Preferred.Index = KSPROPERTY_SYSAUDIO_MIDI_DEFAULT;
  740. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Property.Id=%X, Preferred=%X",
  741. Preferred,Preferred.Property.Id) );
  742. Status = KsSynchronousIoControlDevice(
  743. pContext->pFileObjectSysaudio,
  744. KernelMode,
  745. IOCTL_KS_PROPERTY,
  746. &Preferred,
  747. sizeof(Preferred),
  748. &SysaudioDevice,
  749. sizeof(SysaudioDevice),
  750. &BytesReturned);
  751. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, SysaudioDevice=%X,BytesRet=%d",
  752. Status,SysaudioDevice,BytesReturned) );
  753. if(!NT_SUCCESS(Status)) {
  754. DPF(DL_WARNING|FA_SYSAUDIO,("Property Query failed Status=%X",Status) );
  755. goto exit;
  756. }
  757. }
  758. }
  759. exit:
  760. RETURN(Status);
  761. }
  762. NTSTATUS GetSysAudioProperty
  763. (
  764. PFILE_OBJECT pFileObject,
  765. ULONG PropertyId,
  766. ULONG DeviceIndex,
  767. ULONG cbProperty,
  768. PVOID pProperty
  769. )
  770. {
  771. ULONG BytesReturned;
  772. KSPROPERTYPLUS Property;
  773. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  774. PAGED_CODE();
  775. if (pFileObject)
  776. {
  777. Property.Property.Set = KSPROPSETID_Sysaudio;
  778. Property.Property.Id = PropertyId;
  779. Property.Property.Flags = KSPROPERTY_TYPE_GET;
  780. Property.DeviceIndex = DeviceIndex;
  781. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X, DI=%X",PropertyId,DeviceIndex) );
  782. Status = KsSynchronousIoControlDevice(pFileObject,
  783. KernelMode,
  784. IOCTL_KS_PROPERTY,
  785. &Property,
  786. sizeof(Property),
  787. pProperty,
  788. cbProperty,
  789. &BytesReturned);
  790. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
  791. Status,pProperty,cbProperty,BytesReturned) );
  792. }
  793. RETURN( Status );
  794. }
  795. NTSTATUS SetSysAudioProperty
  796. (
  797. PFILE_OBJECT pFileObject,
  798. ULONG PropertyId,
  799. ULONG cbProperty,
  800. PVOID pProperty
  801. )
  802. {
  803. ULONG BytesReturned;
  804. KSPROPERTY Property;
  805. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  806. PAGED_CODE();
  807. if (pFileObject)
  808. {
  809. Property.Set = KSPROPSETID_Sysaudio;
  810. Property.Id = PropertyId;
  811. Property.Flags = KSPROPERTY_TYPE_SET;
  812. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",
  813. PropertyId) );
  814. Status = KsSynchronousIoControlDevice(pFileObject,
  815. KernelMode,
  816. IOCTL_KS_PROPERTY,
  817. &Property,
  818. sizeof(Property),
  819. pProperty,
  820. cbProperty,
  821. &BytesReturned);
  822. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
  823. Status,pProperty,cbProperty,BytesReturned) );
  824. }
  825. RETURN(Status);
  826. }
  827. DWORD wdmaudTranslateDeviceNumber
  828. (
  829. PWDMACONTEXT pWdmaContext,
  830. DWORD DeviceType,
  831. PCWSTR DeviceInterface,
  832. DWORD DeviceNumber
  833. )
  834. {
  835. PCOMMONDEVICE *ppCommonDevice;
  836. DWORD d, j;
  837. PAGED_CODE();
  838. ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  839. for (d = 0; d < MAXNUMDEVS; d++ )
  840. {
  841. if (ppCommonDevice[d]->Device == UNUSED_DEVICE ||
  842. MyWcsicmp(ppCommonDevice[d]->DeviceInterface, DeviceInterface))
  843. {
  844. continue;
  845. }
  846. if(ppCommonDevice[d]->PreferredDevice == MAXULONG ||
  847. ppCommonDevice[d]->PreferredDevice == d)
  848. {
  849. if (DeviceNumber == 0)
  850. {
  851. if (ppCommonDevice[d]->PreferredDevice == d)
  852. {
  853. if(pWdmaContext->PreferredSysaudioWaveDevice != MAXULONG)
  854. {
  855. for (j = 0; j < MAXNUMDEVS; j++)
  856. {
  857. if (j == d)
  858. continue;
  859. if (ppCommonDevice[j]->PreferredDevice == d &&
  860. ppCommonDevice[j]->Device ==
  861. pWdmaContext->PreferredSysaudioWaveDevice)
  862. {
  863. return j;
  864. }
  865. }
  866. }
  867. }
  868. return d;
  869. }
  870. else
  871. {
  872. DeviceNumber--;
  873. }
  874. }
  875. }
  876. return MAXULONG;
  877. }
  878. int
  879. CmpStr(
  880. PWSTR pwstr1,
  881. PWSTR pwstr2
  882. )
  883. {
  884. PAGED_CODE();
  885. if(pwstr1 == NULL && pwstr2 == NULL) {
  886. return(0);
  887. }
  888. if(pwstr1 == NULL || pwstr2 == NULL) {
  889. return(1);
  890. }
  891. return(wcscmp(pwstr1, pwstr2));
  892. }
  893. NTSTATUS AddDevice
  894. (
  895. PWDMACONTEXT pWdmaContext,
  896. ULONG Device,
  897. DWORD DeviceType,
  898. PCWSTR DeviceInterface,
  899. ULONG PinId,
  900. PWSTR pwstrName,
  901. BOOL fUsePreferred,
  902. PDATARANGES pDataRanges,
  903. PKSCOMPONENTID ComponentId
  904. )
  905. {
  906. PCOMMONDEVICE *papCommonDevice;
  907. DWORD DeviceNumber;
  908. DWORD d;
  909. PKSDATARANGE_MUSIC MusicDataRange;
  910. PAGED_CODE();
  911. switch(DeviceType)
  912. {
  913. case MidiOutDevice:
  914. MusicDataRange = (PKSDATARANGE_MUSIC)&pDataRanges->aDataRanges[0];
  915. if ( !IsEqualGUID( &KSMUSIC_TECHNOLOGY_SWSYNTH, &MusicDataRange->Technology ) )
  916. {
  917. fUsePreferred = FALSE;
  918. }
  919. break;
  920. case MidiInDevice:
  921. fUsePreferred = FALSE;
  922. break;
  923. default:
  924. // Do nothing
  925. break;
  926. }
  927. DPF( DL_TRACE|FA_SYSAUDIO, ("D# %02x DT %02x DI %ls PI %02x %01x",
  928. Device, DeviceType, DeviceInterface, PinId, fUsePreferred));
  929. papCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  930. for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
  931. {
  932. if (papCommonDevice[DeviceNumber]->Device != UNUSED_DEVICE &&
  933. !MyWcsicmp(papCommonDevice[DeviceNumber]->DeviceInterface, DeviceInterface) &&
  934. !CmpStr(papCommonDevice[DeviceNumber]->pwstrName, pwstrName))
  935. {
  936. papCommonDevice[DeviceNumber]->Device = Device;
  937. papCommonDevice[DeviceNumber]->PinId = PinId;
  938. ASSERT(
  939. (!fUsePreferred &&
  940. papCommonDevice[DeviceNumber]->PreferredDevice ==
  941. MAXULONG) ||
  942. (fUsePreferred &&
  943. papCommonDevice[DeviceNumber]->PreferredDevice !=
  944. MAXULONG));
  945. break;
  946. }
  947. }
  948. if (DeviceNumber < MAXNUMDEVS)
  949. {
  950. // We found an existing device that matches this one. We need to free
  951. // some stuff before setting up the new stuff
  952. AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->pwstrName);
  953. AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->DeviceInterface);
  954. AudioFreeMemory_Unknown(&papCommonDevice[DeviceNumber]->ComponentId);
  955. switch (DeviceType)
  956. {
  957. case WaveOutDevice:
  958. AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[DeviceNumber].AudioDataRanges);
  959. break;
  960. case WaveInDevice:
  961. AudioFreeMemory_Unknown(&pWdmaContext->WaveInDevs[DeviceNumber].AudioDataRanges);
  962. break;
  963. case MidiOutDevice:
  964. AudioFreeMemory_Unknown(&pWdmaContext->MidiOutDevs[DeviceNumber].MusicDataRanges);
  965. break;
  966. case MidiInDevice:
  967. AudioFreeMemory_Unknown(&pWdmaContext->MidiInDevs[DeviceNumber].MusicDataRanges);
  968. break;
  969. }
  970. } else {
  971. // We didn't find an existing device that matches the new one. Search
  972. // for an unused slot in our device lists
  973. for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
  974. {
  975. if (papCommonDevice[DeviceNumber]->Device == UNUSED_DEVICE)
  976. break;
  977. }
  978. }
  979. if (DeviceNumber == MAXNUMDEVS)
  980. RETURN( STATUS_INSUFFICIENT_RESOURCES );
  981. if (!NT_SUCCESS(AudioAllocateMemory_Paged((wcslen(DeviceInterface)+1)*sizeof(WCHAR),
  982. TAG_AudD_DEVICEINFO,
  983. DEFAULT_MEMORY,
  984. &papCommonDevice[DeviceNumber]->DeviceInterface)))
  985. {
  986. RETURN( STATUS_INSUFFICIENT_RESOURCES );
  987. }
  988. wcscpy(papCommonDevice[DeviceNumber]->DeviceInterface, DeviceInterface);
  989. papCommonDevice[DeviceNumber]->Device = Device;
  990. papCommonDevice[DeviceNumber]->PinId = PinId;
  991. papCommonDevice[DeviceNumber]->pwstrName = pwstrName;
  992. papCommonDevice[DeviceNumber]->PreferredDevice = MAXULONG;
  993. papCommonDevice[DeviceNumber]->ComponentId = ComponentId;
  994. switch(DeviceType)
  995. {
  996. case WaveOutDevice:
  997. pWdmaContext->WaveOutDevs[DeviceNumber].AudioDataRanges = pDataRanges;
  998. break;
  999. case WaveInDevice:
  1000. pWdmaContext->WaveInDevs[DeviceNumber].AudioDataRanges= pDataRanges;
  1001. break;
  1002. case MidiOutDevice:
  1003. pWdmaContext->MidiOutDevs[DeviceNumber].MusicDataRanges = pDataRanges;
  1004. break;
  1005. case MidiInDevice:
  1006. pWdmaContext->MidiInDevs[DeviceNumber].MusicDataRanges = pDataRanges;
  1007. break;
  1008. case AuxDevice:
  1009. break;
  1010. default:
  1011. ASSERT(FALSE);
  1012. RETURN(STATUS_INVALID_PARAMETER);
  1013. }
  1014. if (fUsePreferred)
  1015. {
  1016. papCommonDevice[DeviceNumber]->PreferredDevice =
  1017. DeviceNumber;
  1018. for (d = 0; d < MAXNUMDEVS; d++)
  1019. {
  1020. if (d == DeviceNumber)
  1021. continue;
  1022. if (papCommonDevice[d]->Device == UNUSED_DEVICE)
  1023. continue;
  1024. if (papCommonDevice[d]->PreferredDevice != d)
  1025. continue;
  1026. if(CmpStr(papCommonDevice[d]->pwstrName, pwstrName) != 0)
  1027. continue;
  1028. papCommonDevice[DeviceNumber]->PreferredDevice = d;
  1029. ASSERT(papCommonDevice[d]->PreferredDevice == d);
  1030. break;
  1031. }
  1032. }
  1033. return STATUS_SUCCESS;
  1034. }
  1035. WORD GetMidiTechnology
  1036. (
  1037. PKSDATARANGE_MUSIC MusicDataRange
  1038. )
  1039. {
  1040. WORD Technology = MOD_MIDIPORT; // default to MIDIPORT
  1041. PAGED_CODE();
  1042. if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_FMSYNTH,
  1043. &MusicDataRange->Technology ) )
  1044. {
  1045. Technology = MOD_FMSYNTH;
  1046. }
  1047. else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_WAVETABLE,
  1048. &MusicDataRange->Technology ) )
  1049. {
  1050. Technology = MOD_WAVETABLE;
  1051. }
  1052. else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_SWSYNTH,
  1053. &MusicDataRange->Technology ) )
  1054. {
  1055. Technology = MOD_SWSYNTH;
  1056. }
  1057. else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_SQSYNTH,
  1058. &MusicDataRange->Technology ) )
  1059. {
  1060. Technology = MOD_SQSYNTH;
  1061. }
  1062. else if ( IsEqualGUID( &KSMUSIC_TECHNOLOGY_PORT,
  1063. &MusicDataRange->Technology ) )
  1064. {
  1065. Technology = MOD_MIDIPORT;
  1066. }
  1067. return Technology;
  1068. }
  1069. DWORD GetFormats
  1070. (
  1071. PKSDATARANGE_AUDIO AudioDataRange
  1072. )
  1073. {
  1074. DWORD dwSamples = 0;
  1075. DWORD dwChannels = 0;
  1076. DWORD dwBits = 0;
  1077. PAGED_CODE();
  1078. // The WAVE_FORMAT_XXXX flags are bit flags
  1079. //
  1080. // So we take advantage of that by determining three
  1081. // sets of information:
  1082. // - frequencies that are in the valid range
  1083. // - valid bits per sample
  1084. // - number of channels
  1085. //
  1086. // We than bitwise-AND the three values to get
  1087. // the intersection of valid formats
  1088. //
  1089. // Is 11.025 KHz valid?
  1090. if (AudioDataRange->MinimumSampleFrequency <= 11025 &&
  1091. AudioDataRange->MaximumSampleFrequency >= 11025)
  1092. {
  1093. dwSamples |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
  1094. }
  1095. // Is 22.05 KHz valid?
  1096. if (AudioDataRange->MinimumSampleFrequency <= 22050 &&
  1097. AudioDataRange->MaximumSampleFrequency >= 22050)
  1098. {
  1099. dwSamples |= WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16;
  1100. }
  1101. // Is 44.1KHz valid?
  1102. if (AudioDataRange->MinimumSampleFrequency <= 44100 &&
  1103. AudioDataRange->MaximumSampleFrequency >= 44100)
  1104. {
  1105. dwSamples |= WAVE_FORMAT_44M08 | WAVE_FORMAT_44S08 | WAVE_FORMAT_44M16 | WAVE_FORMAT_44S16;
  1106. }
  1107. // Is 48 KHz valid?
  1108. if (AudioDataRange->MinimumSampleFrequency <= 48000 &&
  1109. AudioDataRange->MaximumSampleFrequency >= 48000)
  1110. {
  1111. dwSamples |= WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16;
  1112. }
  1113. // Is 96 KHz valid?
  1114. if (AudioDataRange->MinimumSampleFrequency <= 96000 &&
  1115. AudioDataRange->MaximumSampleFrequency >= 96000)
  1116. {
  1117. dwSamples |= WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16;
  1118. }
  1119. // Is 8 bit per sample valid?
  1120. if (AudioDataRange->MinimumBitsPerSample <= 8 &&
  1121. AudioDataRange->MaximumBitsPerSample >= 8)
  1122. {
  1123. dwBits |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2M08 |
  1124. WAVE_FORMAT_2S08 | WAVE_FORMAT_44M08 | WAVE_FORMAT_44S08 |
  1125. WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96M08 |
  1126. WAVE_FORMAT_96S08;
  1127. }
  1128. // Is 16 bits per sample valid?
  1129. if (AudioDataRange->MinimumBitsPerSample <= 16 &&
  1130. AudioDataRange->MaximumBitsPerSample >= 16)
  1131. {
  1132. dwBits |= WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 |
  1133. WAVE_FORMAT_2S16 | WAVE_FORMAT_44M16 | WAVE_FORMAT_44S16 |
  1134. WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96M16 |
  1135. WAVE_FORMAT_96S16;
  1136. }
  1137. // Is one channel (aka mono sound) valid?
  1138. if (AudioDataRange->MaximumChannels >= 1)
  1139. {
  1140. dwChannels |= WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M08 |
  1141. WAVE_FORMAT_2M16 | WAVE_FORMAT_44M08 | WAVE_FORMAT_44M16 |
  1142. WAVE_FORMAT_48M08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M08 |
  1143. WAVE_FORMAT_48M16;
  1144. }
  1145. // Are two channels (aka stereo sound) valid?
  1146. if (AudioDataRange->MaximumChannels >= 2)
  1147. {
  1148. dwChannels |= WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S08 |
  1149. WAVE_FORMAT_2S16 | WAVE_FORMAT_44S08 | WAVE_FORMAT_44S16 |
  1150. WAVE_FORMAT_48S08 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S08 |
  1151. WAVE_FORMAT_96S16;
  1152. }
  1153. dwSamples = dwSamples & dwBits & dwChannels;
  1154. return dwSamples;
  1155. }
  1156. //
  1157. // Assist with unicode conversions
  1158. //
  1159. VOID CopyUnicodeStringtoAnsiString
  1160. (
  1161. LPSTR lpstr,
  1162. LPCWSTR lpwstr,
  1163. int len
  1164. )
  1165. {
  1166. UNICODE_STRING SourceString;
  1167. ANSI_STRING DestinationString;
  1168. NTSTATUS Status;
  1169. PAGED_CODE();
  1170. RtlInitUnicodeString(&SourceString, lpwstr);
  1171. Status = RtlUnicodeStringToAnsiString(&DestinationString, &SourceString, TRUE);
  1172. if (NT_SUCCESS(Status)) {
  1173. if (DestinationString.MaximumLength<len) {
  1174. len=DestinationString.MaximumLength;
  1175. }
  1176. RtlCopyMemory(lpstr, DestinationString.Buffer, len);
  1177. RtlFreeAnsiString(&DestinationString);
  1178. lpstr[len-1]=0;
  1179. }
  1180. else if (len>0) {
  1181. *lpstr=0;
  1182. }
  1183. }
  1184. VOID CopyAnsiStringtoUnicodeString
  1185. (
  1186. LPWSTR lpwstr,
  1187. LPCSTR lpstr,
  1188. int len
  1189. )
  1190. {
  1191. PAGED_CODE();
  1192. while (len)
  1193. {
  1194. *lpwstr = (WCHAR) *lpstr;
  1195. lpwstr++;
  1196. lpstr++;
  1197. len--;
  1198. }
  1199. lpwstr--;
  1200. *lpwstr=0;
  1201. }
  1202. UINT GetCapsIndex
  1203. (
  1204. PWDMACONTEXT pWdmaContext,
  1205. PWSTR pwstrName,
  1206. DWORD DeviceType,
  1207. DWORD DeviceNumber
  1208. )
  1209. {
  1210. PCOMMONDEVICE *ppCommonDevice;
  1211. UINT MatchCount = 0;
  1212. DWORD d;
  1213. PAGED_CODE();
  1214. ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  1215. //
  1216. // Loop through all of the devices for a particular devicetype
  1217. //
  1218. for( d = 0; d < MAXNUMDEVS; d++ )
  1219. {
  1220. if (ppCommonDevice[d]->Device != UNUSED_DEVICE &&
  1221. !CmpStr(ppCommonDevice[d]->pwstrName, pwstrName))
  1222. {
  1223. MatchCount++;
  1224. if (DeviceNumber == d)
  1225. {
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. //
  1231. // returns index of the friendly name.
  1232. //
  1233. return MatchCount;
  1234. }
  1235. NTSTATUS
  1236. ReadProductNameFromMediaCategories(
  1237. IN REFGUID ProductNameGuid,
  1238. OUT PWSTR *NameBuffer
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Queries the "Name" key from the specified category GUID.
  1243. Arguments:
  1244. ProductNameGuid -
  1245. The GUID to locate the name value for.
  1246. NameBuffer -
  1247. The place in which to put the value.
  1248. --*/
  1249. {
  1250. OBJECT_ATTRIBUTES ObjectAttributes;
  1251. NTSTATUS Status;
  1252. HANDLE CategoryKey;
  1253. KEY_VALUE_PARTIAL_INFORMATION PartialInfoHeader;
  1254. WCHAR RegistryPath[sizeof(MediaCategories) + 39];
  1255. UNICODE_STRING RegistryString;
  1256. UNICODE_STRING ValueName;
  1257. ULONG BytesReturned;
  1258. PAGED_CODE();
  1259. //
  1260. // Build the registry key path to the specified category GUID.
  1261. //
  1262. Status = RtlStringFromGUID(ProductNameGuid, &RegistryString);
  1263. if (!NT_SUCCESS(Status)) {
  1264. RETURN( Status );
  1265. }
  1266. wcscpy(RegistryPath, MediaCategories);
  1267. wcscat(RegistryPath, RegistryString.Buffer);
  1268. RtlFreeUnicodeString(&RegistryString);
  1269. RtlInitUnicodeString(&RegistryString, RegistryPath);
  1270. InitializeObjectAttributes(&ObjectAttributes,
  1271. &RegistryString,
  1272. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1273. NULL,
  1274. NULL);
  1275. if (!NT_SUCCESS(Status = ZwOpenKey(&CategoryKey, KEY_READ, &ObjectAttributes))) {
  1276. RETURN( Status );
  1277. }
  1278. //
  1279. // Read the "Name" value beneath this category key.
  1280. //
  1281. RtlInitUnicodeString(&ValueName, NodeNameValue);
  1282. Status = ZwQueryValueKey(
  1283. CategoryKey,
  1284. &ValueName,
  1285. KeyValuePartialInformation,
  1286. &PartialInfoHeader,
  1287. sizeof(PartialInfoHeader),
  1288. &BytesReturned);
  1289. //
  1290. // Even if the read did not cause an overflow, just take the same
  1291. // code path, as such a thing would not normally happen.
  1292. //
  1293. if ((Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS(Status)) {
  1294. PKEY_VALUE_PARTIAL_INFORMATION PartialInfoBuffer = NULL;
  1295. //
  1296. // Allocate a buffer for the actual size of data needed.
  1297. //
  1298. Status = AudioAllocateMemory_Paged(BytesReturned,
  1299. TAG_Audp_NAME,
  1300. ZERO_FILL_MEMORY,
  1301. &PartialInfoBuffer );
  1302. if (NT_SUCCESS(Status)) {
  1303. //
  1304. // Retrieve the actual name.
  1305. //
  1306. Status = ZwQueryValueKey(
  1307. CategoryKey,
  1308. &ValueName,
  1309. KeyValuePartialInformation,
  1310. PartialInfoBuffer,
  1311. BytesReturned,
  1312. &BytesReturned);
  1313. if (NT_SUCCESS(Status)) {
  1314. //
  1315. // Make sure that there is always a value.
  1316. //
  1317. if (!PartialInfoBuffer->DataLength || (PartialInfoBuffer->Type != REG_SZ)) {
  1318. Status = STATUS_UNSUCCESSFUL;
  1319. } else {
  1320. Status = AudioAllocateMemory_Paged(PartialInfoBuffer->DataLength,
  1321. TAG_Audp_NAME,
  1322. DEFAULT_MEMORY,
  1323. NameBuffer );
  1324. if (NT_SUCCESS(Status)) {
  1325. RtlCopyMemory(
  1326. *NameBuffer,
  1327. PartialInfoBuffer->Data,
  1328. PartialInfoBuffer->DataLength);
  1329. }
  1330. }
  1331. }
  1332. AudioFreeMemory_Unknown(&PartialInfoBuffer);
  1333. } else {
  1334. Status = STATUS_INSUFFICIENT_RESOURCES;
  1335. }
  1336. }
  1337. ZwClose(CategoryKey);
  1338. RETURN( Status );
  1339. }
  1340. WORD ChooseCorrectMid
  1341. (
  1342. REFGUID Manufacturer
  1343. )
  1344. {
  1345. PAGED_CODE();
  1346. if (IS_COMPATIBLE_MMREG_MID(Manufacturer))
  1347. {
  1348. return EXTRACT_MMREG_MID(Manufacturer);
  1349. }
  1350. else
  1351. {
  1352. return MM_UNMAPPED;
  1353. }
  1354. }
  1355. WORD ChooseCorrectPid
  1356. (
  1357. REFGUID Product
  1358. )
  1359. {
  1360. PAGED_CODE();
  1361. if (IS_COMPATIBLE_MMREG_PID(Product))
  1362. {
  1363. return EXTRACT_MMREG_PID(Product);
  1364. }
  1365. else
  1366. {
  1367. return MM_PID_UNMAPPED;
  1368. }
  1369. }
  1370. NTSTATUS FillWaveOutDevCaps
  1371. (
  1372. PWDMACONTEXT pWdmaContext,
  1373. DWORD DeviceNumber,
  1374. LPBYTE lpCaps,
  1375. DWORD dwSize
  1376. )
  1377. {
  1378. WAVEOUTCAPS2W wc2;
  1379. WAVEDEVICE WaveDevice;
  1380. PDATARANGES AudioDataRanges;
  1381. PKSDATARANGE_AUDIO pDataRange;
  1382. ULONG d;
  1383. UINT CapsIndex;
  1384. WCHAR szTemp[256];
  1385. PAGED_CODE();
  1386. WaveDevice = pWdmaContext->WaveOutDevs[DeviceNumber];
  1387. //
  1388. // If available, use the ComponentId to gather information about the device.
  1389. // Otherwise, fall back to hardcoded devcaps.
  1390. //
  1391. if ( (WaveDevice.PreferredDevice == MAXULONG) &&
  1392. (WaveDevice.ComponentId) )
  1393. {
  1394. wc2.NameGuid = WaveDevice.ComponentId->Name;
  1395. wc2.wMid = ChooseCorrectMid(&WaveDevice.ComponentId->Manufacturer);
  1396. wc2.ManufacturerGuid = WaveDevice.ComponentId->Manufacturer;
  1397. wc2.wPid = ChooseCorrectPid(&WaveDevice.ComponentId->Product);
  1398. wc2.ProductGuid = WaveDevice.ComponentId->Product;
  1399. wc2.vDriverVersion = (WaveDevice.ComponentId->Version << 8) |
  1400. (WaveDevice.ComponentId->Revision & 0xFF);
  1401. }
  1402. else
  1403. {
  1404. wc2.NameGuid = GUID_NULL;
  1405. wc2.wMid = MM_MICROSOFT;
  1406. INIT_MMREG_MID( &wc2.ManufacturerGuid, wc2.wMid );
  1407. wc2.wPid = MM_MSFT_WDMAUDIO_WAVEOUT;
  1408. INIT_MMREG_PID( &wc2.ProductGuid, wc2.wPid );
  1409. wc2.vDriverVersion = 0x050a;
  1410. }
  1411. //
  1412. // Assume that KMixer is sample accurate
  1413. //
  1414. wc2.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME |
  1415. WAVECAPS_SAMPLEACCURATE ;
  1416. //
  1417. // Compute the wChannels and dwFormats by consolidating the caps
  1418. // from each of the dataranges
  1419. //
  1420. wc2.wChannels = 0;
  1421. wc2.dwFormats = 0;
  1422. AudioDataRanges = WaveDevice.AudioDataRanges;
  1423. pDataRange = (PKSDATARANGE_AUDIO)&AudioDataRanges->aDataRanges[0];
  1424. for(d = 0; d < AudioDataRanges->Count; d++)
  1425. {
  1426. if (pDataRange->DataRange.FormatSize >= sizeof(KSDATARANGE_AUDIO))
  1427. {
  1428. //
  1429. // Only produce caps for PCM formats
  1430. //
  1431. if ( EXTRACT_WAVEFORMATEX_ID(&pDataRange->DataRange.SubFormat) ==
  1432. WAVE_FORMAT_PCM )
  1433. {
  1434. // Get the largest number of supported channels
  1435. if ( (WORD)pDataRange->MaximumChannels > wc2.wChannels)
  1436. wc2.wChannels = (WORD)pDataRange->MaximumChannels;
  1437. wc2.dwFormats |= GetFormats( pDataRange );
  1438. }
  1439. }
  1440. // Get the pointer to the next data range
  1441. (PUCHAR)pDataRange += ((pDataRange->DataRange.FormatSize +
  1442. FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
  1443. }
  1444. //
  1445. // Add an index in the form of "(%d)" to the end of the szPname string if two or more
  1446. // devices have the same name
  1447. //
  1448. ASSERT(WaveDevice.pwstrName);
  1449. CapsIndex = GetCapsIndex( pWdmaContext, WaveDevice.pwstrName, WaveOutDevice, DeviceNumber );
  1450. if (CapsIndex < 2)
  1451. {
  1452. wcsncpy(wc2.szPname, WaveDevice.pwstrName, MAXPNAMELEN);
  1453. }
  1454. else
  1455. {
  1456. swprintf(szTemp, STR_PNAME, WaveDevice.pwstrName, CapsIndex);
  1457. wcsncpy(wc2.szPname, szTemp, MAXPNAMELEN);
  1458. }
  1459. wc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1460. //
  1461. // Copy the caps information into the caller supplied buffer
  1462. //
  1463. RtlCopyMemory(lpCaps, &wc2, min(dwSize, sizeof(wc2)));
  1464. return STATUS_SUCCESS;
  1465. }
  1466. NTSTATUS FillWaveInDevCaps
  1467. (
  1468. PWDMACONTEXT pWdmaContext,
  1469. DWORD DeviceNumber,
  1470. LPBYTE lpCaps,
  1471. DWORD dwSize
  1472. )
  1473. {
  1474. WAVEINCAPS2W wc2;
  1475. WAVEDEVICE WaveDevice;
  1476. PDATARANGES AudioDataRanges;
  1477. PKSDATARANGE_AUDIO pDataRange;
  1478. ULONG d;
  1479. UINT CapsIndex;
  1480. WCHAR szTemp[256];
  1481. PAGED_CODE();
  1482. WaveDevice = pWdmaContext->WaveInDevs[DeviceNumber];
  1483. //
  1484. // If available, use the ComponentId to gather information about the device.
  1485. // Otherwise, fall back to hardcoded devcaps.
  1486. //
  1487. if ( (WaveDevice.PreferredDevice == MAXULONG) &&
  1488. (WaveDevice.ComponentId) )
  1489. {
  1490. wc2.NameGuid = WaveDevice.ComponentId->Name;
  1491. wc2.wMid = ChooseCorrectMid(&WaveDevice.ComponentId->Manufacturer);
  1492. wc2.ManufacturerGuid = WaveDevice.ComponentId->Manufacturer;
  1493. wc2.wPid = ChooseCorrectPid(&WaveDevice.ComponentId->Product);
  1494. wc2.ProductGuid = WaveDevice.ComponentId->Product;
  1495. wc2.vDriverVersion = (WaveDevice.ComponentId->Version << 8) |
  1496. (WaveDevice.ComponentId->Revision & 0xFF);
  1497. }
  1498. else
  1499. {
  1500. wc2.NameGuid = GUID_NULL;
  1501. wc2.wMid = MM_MICROSOFT;
  1502. INIT_MMREG_MID( &wc2.ManufacturerGuid, wc2.wMid );
  1503. wc2.wPid = MM_MSFT_WDMAUDIO_WAVEIN;
  1504. INIT_MMREG_PID( &wc2.ProductGuid, wc2.wPid );
  1505. wc2.vDriverVersion = 0x050a;
  1506. }
  1507. //
  1508. // Compute the wChannels and dwFormats by consolidating the caps
  1509. // from each of the dataranges
  1510. //
  1511. wc2.wChannels = 0;
  1512. wc2.dwFormats = 0;
  1513. AudioDataRanges = WaveDevice.AudioDataRanges;
  1514. pDataRange = (PKSDATARANGE_AUDIO)&AudioDataRanges->aDataRanges[0];
  1515. for(d = 0; d < AudioDataRanges->Count; d++)
  1516. {
  1517. if (pDataRange->DataRange.FormatSize >= sizeof(KSDATARANGE_AUDIO))
  1518. {
  1519. //
  1520. // Only produce caps for PCM formats
  1521. //
  1522. if ( EXTRACT_WAVEFORMATEX_ID(&pDataRange->DataRange.SubFormat) ==
  1523. WAVE_FORMAT_PCM )
  1524. {
  1525. // Get the largest number of supported channels
  1526. if ( (WORD)pDataRange->MaximumChannels > wc2.wChannels)
  1527. wc2.wChannels = (WORD)pDataRange->MaximumChannels;
  1528. wc2.dwFormats |= GetFormats( pDataRange );
  1529. }
  1530. }
  1531. // Get the pointer to the next data range
  1532. (PUCHAR)pDataRange += ((pDataRange->DataRange.FormatSize +
  1533. FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
  1534. }
  1535. //
  1536. // Add an index in the form of "(%d)" to the end of the szPname string if two or more
  1537. // devices have the same name
  1538. //
  1539. ASSERT(WaveDevice.pwstrName);
  1540. CapsIndex = GetCapsIndex( pWdmaContext, WaveDevice.pwstrName, WaveInDevice, DeviceNumber );
  1541. if (CapsIndex < 2)
  1542. {
  1543. wcsncpy(wc2.szPname, WaveDevice.pwstrName, MAXPNAMELEN);
  1544. }
  1545. else
  1546. {
  1547. swprintf(szTemp, STR_PNAME, WaveDevice.pwstrName, CapsIndex);
  1548. wcsncpy(wc2.szPname, szTemp, MAXPNAMELEN);
  1549. }
  1550. wc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1551. //
  1552. // Copy the caps information into the caller supplied buffer
  1553. //
  1554. RtlCopyMemory(lpCaps, &wc2, min(dwSize, sizeof(wc2)));
  1555. return STATUS_SUCCESS;
  1556. }
  1557. NTSTATUS FillMidiOutDevCaps
  1558. (
  1559. PWDMACONTEXT pWdmaContext,
  1560. DWORD DeviceNumber,
  1561. LPBYTE lpCaps,
  1562. DWORD dwSize
  1563. )
  1564. {
  1565. MIDIOUTCAPS2W mc2;
  1566. MIDIDEVICE MidiDevice;
  1567. PDATARANGES MusicDataRanges;
  1568. PKSDATARANGE_MUSIC pDataRange;
  1569. UINT CapsIndex;
  1570. WCHAR szTemp[256];
  1571. PAGED_CODE();
  1572. MidiDevice = pWdmaContext->MidiOutDevs[DeviceNumber];
  1573. //
  1574. // If available, use the ComponentId to gather information about the device.
  1575. // Otherwise, fall back to hardcoded devcaps.
  1576. //
  1577. if ( (MidiDevice.PreferredDevice == MAXULONG) &&
  1578. (MidiDevice.ComponentId) )
  1579. {
  1580. mc2.NameGuid = MidiDevice.ComponentId->Name;
  1581. mc2.wMid = ChooseCorrectMid(&MidiDevice.ComponentId->Manufacturer);
  1582. mc2.ManufacturerGuid = MidiDevice.ComponentId->Manufacturer;
  1583. mc2.wPid = ChooseCorrectPid(&MidiDevice.ComponentId->Product);
  1584. mc2.ProductGuid = MidiDevice.ComponentId->Product;
  1585. mc2.vDriverVersion = (MidiDevice.ComponentId->Version << 8) |
  1586. (MidiDevice.ComponentId->Revision & 0xFF);
  1587. }
  1588. else
  1589. {
  1590. mc2.NameGuid = GUID_NULL;
  1591. mc2.wMid = MM_MICROSOFT;
  1592. INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
  1593. mc2.wPid = MM_MSFT_WDMAUDIO_MIDIOUT;
  1594. INIT_MMREG_PID( &mc2.ProductGuid, mc2.wMid );
  1595. mc2.vDriverVersion = 0x050a;
  1596. }
  1597. MusicDataRanges = MidiDevice.MusicDataRanges;
  1598. pDataRange = (PKSDATARANGE_MUSIC)&MusicDataRanges->aDataRanges[0];
  1599. //
  1600. // Use the first datarange. Could cause problems for pins
  1601. // that support multiple music dataranges.
  1602. //
  1603. if (pDataRange->DataRange.FormatSize < sizeof(KSDATARANGE_MUSIC))
  1604. {
  1605. mc2.wTechnology = MOD_MIDIPORT;
  1606. mc2.wVoices = 0;
  1607. mc2.wNotes = 0;
  1608. mc2.wChannelMask= 0;
  1609. }
  1610. else
  1611. {
  1612. mc2.wTechnology = GetMidiTechnology( pDataRange );
  1613. mc2.wVoices = (WORD)pDataRange->Channels;
  1614. mc2.wNotes = (WORD)pDataRange->Notes;
  1615. mc2.wChannelMask= (WORD)pDataRange->ChannelMask;
  1616. }
  1617. mc2.dwSupport = 0L;
  1618. if (mc2.wTechnology != MOD_MIDIPORT)
  1619. {
  1620. mc2.dwSupport |= MIDICAPS_VOLUME | MIDICAPS_LRVOLUME;
  1621. }
  1622. ASSERT(MidiDevice.pwstrName);
  1623. CapsIndex = GetCapsIndex( pWdmaContext, MidiDevice.pwstrName, MidiOutDevice, DeviceNumber );
  1624. if (CapsIndex < 2)
  1625. {
  1626. wcsncpy(mc2.szPname, MidiDevice.pwstrName, MAXPNAMELEN);
  1627. }
  1628. else
  1629. {
  1630. // Only add the index to the string if we need to
  1631. swprintf(szTemp, STR_PNAME, MidiDevice.pwstrName, CapsIndex);
  1632. wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
  1633. }
  1634. mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1635. RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
  1636. return STATUS_SUCCESS;
  1637. }
  1638. NTSTATUS FillMidiInDevCaps
  1639. (
  1640. PWDMACONTEXT pWdmaContext,
  1641. DWORD DeviceNumber,
  1642. LPBYTE lpCaps,
  1643. DWORD dwSize
  1644. )
  1645. {
  1646. MIDIINCAPS2W mc2;
  1647. MIDIDEVICE MidiDevice;
  1648. UINT CapsIndex;
  1649. WCHAR szTemp[256];
  1650. PAGED_CODE();
  1651. MidiDevice = pWdmaContext->MidiInDevs[DeviceNumber];
  1652. //
  1653. // If available, use the ComponentId to gather information about the device.
  1654. // Otherwise, fall back to hardcoded devcaps.
  1655. //
  1656. if ( (MidiDevice.PreferredDevice == MAXULONG) &&
  1657. (MidiDevice.ComponentId) )
  1658. {
  1659. mc2.NameGuid = MidiDevice.ComponentId->Name;
  1660. mc2.wMid = ChooseCorrectMid(&MidiDevice.ComponentId->Manufacturer);
  1661. mc2.ManufacturerGuid = MidiDevice.ComponentId->Manufacturer;
  1662. mc2.wPid = ChooseCorrectPid(&MidiDevice.ComponentId->Product);
  1663. mc2.ProductGuid = MidiDevice.ComponentId->Product;
  1664. mc2.vDriverVersion = (MidiDevice.ComponentId->Version << 8) |
  1665. (MidiDevice.ComponentId->Revision & 0xFF);
  1666. }
  1667. else
  1668. {
  1669. mc2.NameGuid = GUID_NULL;
  1670. mc2.wMid = MM_MICROSOFT;
  1671. INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
  1672. mc2.wPid = MM_MSFT_WDMAUDIO_MIDIIN;
  1673. INIT_MMREG_PID( &mc2.ProductGuid, mc2.wPid );
  1674. mc2.vDriverVersion = 0x050a;
  1675. }
  1676. mc2.dwSupport = 0L; /* functionality supported by driver */
  1677. ASSERT(MidiDevice.pwstrName);
  1678. CapsIndex = GetCapsIndex( pWdmaContext, MidiDevice.pwstrName, MidiInDevice, DeviceNumber );
  1679. if (CapsIndex < 2)
  1680. {
  1681. wcsncpy(mc2.szPname, MidiDevice.pwstrName, MAXPNAMELEN);
  1682. }
  1683. else
  1684. {
  1685. // Only add the index to the string if we need to
  1686. swprintf(szTemp, STR_PNAME, MidiDevice.pwstrName, CapsIndex);
  1687. wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
  1688. }
  1689. mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1690. RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
  1691. return STATUS_SUCCESS;
  1692. }
  1693. NTSTATUS FillMixerDevCaps
  1694. (
  1695. PWDMACONTEXT pWdmaContext,
  1696. DWORD DeviceNumber,
  1697. LPBYTE lpCaps,
  1698. DWORD dwSize
  1699. )
  1700. {
  1701. MIXERCAPS2W mc2;
  1702. MIXERDEVICE Mixer;
  1703. UINT CapsIndex;
  1704. WCHAR szTemp[256];
  1705. PAGED_CODE();
  1706. Mixer = pWdmaContext->MixerDevs[DeviceNumber];
  1707. //
  1708. // If available, use the ComponentId to gather information about the device.
  1709. // Otherwise, fall back to hardcoded devcaps.
  1710. //
  1711. if ( (Mixer.PreferredDevice == MAXULONG) &&
  1712. (Mixer.ComponentId) )
  1713. {
  1714. mc2.NameGuid = Mixer.ComponentId->Name;
  1715. mc2.wMid = ChooseCorrectMid(&Mixer.ComponentId->Manufacturer);
  1716. mc2.ManufacturerGuid = Mixer.ComponentId->Manufacturer;
  1717. mc2.wPid = ChooseCorrectPid(&Mixer.ComponentId->Product);
  1718. mc2.ProductGuid = Mixer.ComponentId->Product;
  1719. mc2.vDriverVersion = (Mixer.ComponentId->Version << 8) |
  1720. (Mixer.ComponentId->Revision & 0xFF);
  1721. }
  1722. else
  1723. {
  1724. mc2.NameGuid = GUID_NULL;
  1725. mc2.wMid = MM_MICROSOFT;
  1726. INIT_MMREG_MID( &mc2.ManufacturerGuid, mc2.wMid );
  1727. mc2.wPid = MM_MSFT_WDMAUDIO_MIXER;
  1728. INIT_MMREG_PID( &mc2.ProductGuid, mc2.wPid );
  1729. mc2.vDriverVersion = 0x050a;
  1730. }
  1731. mc2.fdwSupport = 0L; /* functionality supported by driver */
  1732. mc2.cDestinations = kmxlGetNumDestinations( &Mixer );
  1733. ASSERT(Mixer.pwstrName);
  1734. CapsIndex = GetCapsIndex( pWdmaContext, Mixer.pwstrName, MixerDevice, DeviceNumber );
  1735. if (CapsIndex < 2)
  1736. {
  1737. wcsncpy(mc2.szPname, Mixer.pwstrName, MAXPNAMELEN);
  1738. }
  1739. else
  1740. {
  1741. // Only add the index to the string if we need to
  1742. swprintf(szTemp, STR_PNAME, Mixer.pwstrName, CapsIndex);
  1743. wcsncpy(mc2.szPname, szTemp, MAXPNAMELEN);
  1744. }
  1745. mc2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1746. RtlCopyMemory(lpCaps, &mc2, min(dwSize, sizeof(mc2)));
  1747. return STATUS_SUCCESS;
  1748. }
  1749. NTSTATUS FillAuxDevCaps
  1750. (
  1751. PWDMACONTEXT pWdmaContext,
  1752. DWORD DeviceNumber,
  1753. LPBYTE lpCaps,
  1754. DWORD dwSize
  1755. )
  1756. {
  1757. AUXCAPS2W ac2;
  1758. AUXDEVICE AuxDev;
  1759. UINT CapsIndex;
  1760. WCHAR szTemp[256];
  1761. PAGED_CODE();
  1762. AuxDev = pWdmaContext->AuxDevs[DeviceNumber];
  1763. //
  1764. // If available, use the ComponentId to gather information about the device.
  1765. // Otherwise, fall back to hardcoded devcaps.
  1766. //
  1767. if ( (AuxDev.PreferredDevice == MAXULONG) &&
  1768. (AuxDev.ComponentId) )
  1769. {
  1770. ac2.NameGuid = AuxDev.ComponentId->Name;
  1771. ac2.wMid = ChooseCorrectMid(&AuxDev.ComponentId->Manufacturer);
  1772. ac2.ManufacturerGuid = AuxDev.ComponentId->Manufacturer;
  1773. ac2.wPid = ChooseCorrectPid(&AuxDev.ComponentId->Product);
  1774. ac2.ProductGuid = AuxDev.ComponentId->Product;
  1775. ac2.vDriverVersion = (AuxDev.ComponentId->Version << 8) |
  1776. (AuxDev.ComponentId->Revision & 0xFF);
  1777. }
  1778. else
  1779. {
  1780. ac2.NameGuid = GUID_NULL;
  1781. ac2.wMid = MM_MICROSOFT;
  1782. INIT_MMREG_MID( &ac2.ManufacturerGuid, ac2.wMid );
  1783. ac2.wPid = MM_MSFT_WDMAUDIO_AUX;
  1784. INIT_MMREG_PID( &ac2.ProductGuid, ac2.wPid );
  1785. ac2.vDriverVersion = 0x050a;
  1786. }
  1787. ac2.wTechnology = AUXCAPS_CDAUDIO ; // | AUXCAPS_AUXIN ;
  1788. ac2.dwSupport = AUXCAPS_LRVOLUME | AUXCAPS_VOLUME;
  1789. ASSERT(AuxDev.pwstrName);
  1790. CapsIndex = GetCapsIndex( pWdmaContext, AuxDev.pwstrName, AuxDevice, DeviceNumber );
  1791. if (CapsIndex < 2)
  1792. {
  1793. wcsncpy(ac2.szPname, AuxDev.pwstrName, MAXPNAMELEN);
  1794. }
  1795. else
  1796. {
  1797. // Only add the index to the string if we need to
  1798. swprintf(szTemp, STR_PNAME, AuxDev.pwstrName, CapsIndex);
  1799. wcsncpy(ac2.szPname, szTemp, MAXPNAMELEN);
  1800. }
  1801. ac2.szPname[MAXPNAMELEN-1] = UNICODE_NULL;
  1802. RtlCopyMemory(lpCaps, &ac2, min(dwSize, sizeof(ac2)));
  1803. return STATUS_SUCCESS;
  1804. }
  1805. NTSTATUS wdmaudGetDevCaps
  1806. (
  1807. PWDMACONTEXT pWdmaContext,
  1808. DWORD DeviceType,
  1809. DWORD DeviceNumber,
  1810. LPBYTE lpCaps,
  1811. DWORD dwSize
  1812. )
  1813. {
  1814. NTSTATUS Status = STATUS_SUCCESS;
  1815. PAGED_CODE();
  1816. ASSERT(DeviceType == WaveOutDevice ||
  1817. DeviceType == WaveInDevice ||
  1818. DeviceType == MidiOutDevice ||
  1819. DeviceType == MidiInDevice ||
  1820. DeviceType == MixerDevice ||
  1821. DeviceType == AuxDevice);
  1822. switch(DeviceType) {
  1823. case WaveOutDevice:
  1824. Status = FillWaveOutDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1825. break;
  1826. case WaveInDevice:
  1827. Status = FillWaveInDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1828. break;
  1829. case MidiOutDevice:
  1830. Status = FillMidiOutDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1831. break;
  1832. case MidiInDevice:
  1833. Status = FillMidiInDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1834. break;
  1835. case MixerDevice:
  1836. Status = FillMixerDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1837. break;
  1838. case AuxDevice:
  1839. Status = FillAuxDevCaps(pWdmaContext,DeviceNumber,lpCaps,dwSize);
  1840. break;
  1841. default:
  1842. ASSERT(0);
  1843. }
  1844. return Status;
  1845. }
  1846. BOOL IsEqualInterface
  1847. (
  1848. PKSPIN_INTERFACE pInterface1,
  1849. PKSPIN_INTERFACE pInterface2
  1850. )
  1851. {
  1852. PAGED_CODE();
  1853. return ( IsEqualGUID(&pInterface1->Set, &pInterface2->Set) &&
  1854. (pInterface1->Id == pInterface2->Id) &&
  1855. (pInterface1->Flags == pInterface2->Flags) );
  1856. }
  1857. /****************************************************************************
  1858. *
  1859. * PnPCompletionRoutine - Finish the PnP Irp
  1860. *
  1861. * Not Exported.
  1862. *
  1863. * ENTRY: Standard PIO_COMPLETION_ROUTINE.
  1864. *
  1865. * EXIT: Standard NT status.
  1866. *
  1867. ***************************************************************************/
  1868. NTSTATUS
  1869. PnPCompletionRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, PVOID pContext)
  1870. {
  1871. PAGED_CODE();
  1872. //
  1873. // Wake ourselves: the device has finally started/stopped.
  1874. //
  1875. KeSetEvent((PKEVENT)pContext, 0, FALSE);
  1876. //
  1877. // The completion itself never fails.
  1878. //
  1879. RETURN(STATUS_MORE_PROCESSING_REQUIRED);
  1880. }
  1881. /****************************************************************************
  1882. *
  1883. * SynchronousCallDriver - Synchronously send a plug and play irp
  1884. *
  1885. * Not exported.
  1886. *
  1887. * ENTRY: pfdo is the function device object.
  1888. *
  1889. * pIrp is the IRP to send.
  1890. *
  1891. * ppResult is filled in with the information value.
  1892. *
  1893. * EXIT: Standard NT status.
  1894. *
  1895. ***************************************************************************/
  1896. NTSTATUS
  1897. SynchronousCallDriver(PDEVICE_OBJECT pfdo, PIRP pIrp, PVOID *ppResult)
  1898. {
  1899. NTSTATUS ntStatus;
  1900. KEVENT keEventObject;
  1901. PAGED_CODE();
  1902. //
  1903. // Set the thread (should typically be msgsrv32's).
  1904. //
  1905. pIrp->Tail.Overlay.Thread=PsGetCurrentThread();
  1906. //
  1907. // Initialize the status block.
  1908. //
  1909. pIrp->IoStatus.Status=STATUS_NOT_SUPPORTED;
  1910. //
  1911. // Initialize our wait event, in case we need to wait.
  1912. //
  1913. KeInitializeEvent( &keEventObject,
  1914. SynchronizationEvent,
  1915. FALSE);
  1916. //
  1917. // Set our completion routine so we can free the IRP and wake
  1918. // ourselfs.
  1919. //
  1920. IoSetCompletionRoutine( pIrp,
  1921. PnPCompletionRoutine,
  1922. &keEventObject,
  1923. TRUE,
  1924. TRUE,
  1925. TRUE);
  1926. //
  1927. // Call the stack now.
  1928. //
  1929. ntStatus=IoCallDriver(pfdo, pIrp);
  1930. //
  1931. // Wait if it is pending.
  1932. //
  1933. if (ntStatus==STATUS_PENDING) {
  1934. //
  1935. // Wait for the completion.
  1936. //
  1937. ntStatus=KeWaitForSingleObject( &keEventObject,
  1938. Executive,
  1939. KernelMode,
  1940. FALSE,
  1941. (PLARGE_INTEGER) NULL );
  1942. //
  1943. // Three cases: timeout (which can't be since we pass null),
  1944. // success or USER_APC (which I don't know what to do).
  1945. //
  1946. if (ntStatus==STATUS_USER_APC) {
  1947. // IopCancelAlertedRequest(&keEventObject, pIrp );
  1948. }
  1949. }
  1950. //
  1951. // Initialize the result, if requested.
  1952. //
  1953. if (ppResult)
  1954. *ppResult=NULL;
  1955. //
  1956. // Otherwise return the result of the operation.
  1957. //
  1958. ntStatus=pIrp->IoStatus.Status;
  1959. //
  1960. // Fill in the result if requested.
  1961. //
  1962. if (ppResult)
  1963. *ppResult=(PVOID)(pIrp->IoStatus.Information);
  1964. RETURN(ntStatus);
  1965. }
  1966. BOOL IsPinForDevNode
  1967. (
  1968. PFILE_OBJECT pFileObjectDevice,
  1969. ULONG Index,
  1970. PCWSTR DeviceInterface
  1971. )
  1972. {
  1973. NTSTATUS Status;
  1974. WCHAR szInterfaceName[256];
  1975. BOOL Result;
  1976. PAGED_CODE();
  1977. Status = GetSysAudioProperty(pFileObjectDevice,
  1978. KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME,
  1979. Index,
  1980. sizeof(szInterfaceName),
  1981. szInterfaceName);
  1982. if (NT_SUCCESS(Status))
  1983. {
  1984. // TODO: Eventually will not need to munge the strings
  1985. PWSTR pszIn = NULL;
  1986. PWSTR pszSysaudio = NULL;
  1987. Status = AudioAllocateMemory_Paged((wcslen(DeviceInterface)+1) * sizeof(WCHAR),
  1988. TAG_Audp_NAME,
  1989. DEFAULT_MEMORY,
  1990. &pszIn );
  1991. if (NT_SUCCESS(Status))
  1992. {
  1993. Status = AudioAllocateMemory_Paged((wcslen(szInterfaceName)+1) * sizeof(WCHAR),
  1994. TAG_Audp_NAME,
  1995. DEFAULT_MEMORY,
  1996. &pszSysaudio );
  1997. if (NT_SUCCESS(Status))
  1998. {
  1999. PWCHAR pch;
  2000. wcscpy(pszIn, DeviceInterface);
  2001. wcscpy(pszSysaudio, szInterfaceName);
  2002. // pszIn[1] = '\\';
  2003. pszSysaudio[1] = '\\';
  2004. // _DbgPrintF( DEBUGLVL_VERBOSE, ("IsPinForDevnode: Sysaudio returns interface name %ls", pszSysaudio));
  2005. // _DbgPrintF( DEBUGLVL_VERBOSE, ("IsPinForDevnode: Comparing against %ls", pszIn));
  2006. if (!MyWcsicmp(pszIn, pszSysaudio)) {
  2007. Result = TRUE;
  2008. } else {
  2009. Result = FALSE;
  2010. }
  2011. AudioFreeMemory_Unknown(&pszSysaudio);
  2012. } else {
  2013. Result = FALSE;
  2014. }
  2015. AudioFreeMemory_Unknown(&pszIn);
  2016. } else {
  2017. Result = FALSE;
  2018. }
  2019. } else {
  2020. Result = FALSE;
  2021. }
  2022. return Result;
  2023. }
  2024. ULONG FindMixerForDevNode(
  2025. IN PMIXERDEVICE paMixerDevs,
  2026. IN PCWSTR DeviceInterface
  2027. )
  2028. {
  2029. ULONG i;
  2030. PAGED_CODE();
  2031. for( i = 0; i < MAXNUMDEVS; i++ ) {
  2032. if( ( paMixerDevs[ i ].Device != UNUSED_DEVICE ) &&
  2033. !MyWcsicmp( paMixerDevs[ i ].DeviceInterface, DeviceInterface ) )
  2034. {
  2035. return( i );
  2036. }
  2037. }
  2038. return( UNUSED_DEVICE );
  2039. }
  2040. NTSTATUS InitializeAuxGetNumDevs
  2041. (
  2042. PWDMACONTEXT pWdmaContext,
  2043. PCWSTR DeviceInterface
  2044. )
  2045. {
  2046. NTSTATUS Status;
  2047. PWSTR pwstrNameAux = NULL;
  2048. DWORD dw;
  2049. ULONG MixerIndex;
  2050. PKSCOMPONENTID ComponentId = NULL;
  2051. PAGED_CODE();
  2052. //
  2053. // Get the name from the mixer device
  2054. //
  2055. MixerIndex = FindMixerForDevNode(pWdmaContext->MixerDevs, DeviceInterface);
  2056. if ( (MixerIndex != UNUSED_DEVICE) && (pWdmaContext->MixerDevs[MixerIndex].pwstrName != NULL) )
  2057. {
  2058. //
  2059. // Check for CD volume control
  2060. //
  2061. Status = IsVolumeControl( pWdmaContext,
  2062. DeviceInterface,
  2063. MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC,
  2064. &dw,
  2065. &dw );
  2066. if(NT_SUCCESS(Status))
  2067. {
  2068. Status = AudioAllocateMemory_Paged((wcslen(pWdmaContext->MixerDevs[MixerIndex].pwstrName) + 1) * sizeof(WCHAR),
  2069. TAG_Audp_NAME,
  2070. DEFAULT_MEMORY,
  2071. &pwstrNameAux);
  2072. if (NT_SUCCESS(Status))
  2073. {
  2074. wcscpy(pwstrNameAux, pWdmaContext->MixerDevs[MixerIndex].pwstrName);
  2075. if (pWdmaContext->MixerDevs[MixerIndex].ComponentId)
  2076. {
  2077. Status = AudioAllocateMemory_Paged(sizeof(*ComponentId),
  2078. TAG_Audp_NAME,
  2079. DEFAULT_MEMORY,
  2080. &ComponentId);
  2081. if (NT_SUCCESS(Status))
  2082. {
  2083. RtlCopyMemory(ComponentId, pWdmaContext->MixerDevs[MixerIndex].ComponentId, sizeof(*ComponentId));
  2084. }
  2085. }
  2086. else
  2087. {
  2088. ComponentId = NULL;
  2089. }
  2090. Status = AddDevice(pWdmaContext,
  2091. 0,
  2092. AuxDevice,
  2093. DeviceInterface,
  2094. 0,
  2095. pwstrNameAux,
  2096. FALSE,
  2097. NULL,
  2098. ComponentId);
  2099. if (NT_SUCCESS(Status))
  2100. {
  2101. FindVolumeControl(pWdmaContext, DeviceInterface, AuxDevice);
  2102. } else {
  2103. AudioFreeMemory_Unknown(&ComponentId);
  2104. AudioFreeMemory_Unknown(&pwstrNameAux);
  2105. }
  2106. }
  2107. }
  2108. }
  2109. // if anything fails, still return success so InitializeGetNumDevs
  2110. // returns 0 devices
  2111. return(STATUS_SUCCESS);
  2112. }
  2113. NTSTATUS InitializeMixerGetNumDevs
  2114. (
  2115. IN PWDMACONTEXT pWdmaContext,
  2116. IN PCWSTR DeviceInterface
  2117. )
  2118. {
  2119. NTSTATUS Status;
  2120. PMIXERDEVICE paMixerDevs;
  2121. PWAVEDEVICE paWaveOutDevs;
  2122. PWAVEDEVICE paWaveInDevs;
  2123. ULONG i, j;
  2124. PAGED_CODE();
  2125. // WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING
  2126. //
  2127. // This function makes a few assumptions. If any of the assumptions
  2128. // below change, this function must be updated accordingly!
  2129. //
  2130. // 1) Mixer devices are initialized after all other device classes.
  2131. //
  2132. // 2) SysAudio device numbers are the same for the different interfaces
  2133. // (WaveOut,WaveIn,MidiOut,MidiIn,Mixer) for a devnode.
  2134. //
  2135. // WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING
  2136. paWaveOutDevs = pWdmaContext->WaveOutDevs;
  2137. paWaveInDevs = pWdmaContext->WaveInDevs;
  2138. paMixerDevs = pWdmaContext->MixerDevs;
  2139. for( i = 0; i < MAXNUMDEVS; i++ ) {
  2140. //
  2141. // Look for WaveOut interfaces
  2142. //
  2143. if( ( paWaveOutDevs[ i ].Device != UNUSED_DEVICE ) &&
  2144. ( !MyWcsicmp(paWaveOutDevs[ i ].DeviceInterface, DeviceInterface) ) ) {
  2145. for( j = 0; j < MAXNUMDEVS; j++ ) {
  2146. //ASSERT(paMixerDevs[j].Device == UNUSED_DEVICE ?
  2147. // NULL == paMixerDevs[j].DeviceInterface :
  2148. // NULL != paMixerDevs[j].DeviceInterface);
  2149. if( ( paMixerDevs[ j ].Device != UNUSED_DEVICE ) &&
  2150. ( !MyWcsicmp(paMixerDevs[ j ].DeviceInterface, DeviceInterface) ) )
  2151. {
  2152. //
  2153. // We've found a devnode that has already been added
  2154. // to the mixer list.
  2155. //
  2156. kmxlDeInit(&paMixerDevs[j]);
  2157. paMixerDevs[ j ].Device = paWaveOutDevs[ i ].Device;
  2158. break;
  2159. }
  2160. } // for
  2161. if( j == MAXNUMDEVS ) {
  2162. for( j = 0; j < MAXNUMDEVS; j++ ) {
  2163. if( paMixerDevs[ j ].Device == UNUSED_DEVICE ) {
  2164. break;
  2165. }
  2166. }
  2167. if( j == MAXNUMDEVS ) {
  2168. RETURN( STATUS_INSUFFICIENT_RESOURCES );
  2169. }
  2170. Status = AudioAllocateMemory_Paged((wcslen(paWaveOutDevs[i].pwstrName) + 1) * sizeof(WCHAR),
  2171. TAG_Audp_NAME,
  2172. DEFAULT_MEMORY,
  2173. &paMixerDevs[j].pwstrName);
  2174. if (NT_SUCCESS(Status))
  2175. {
  2176. wcscpy(paMixerDevs[j].pwstrName, paWaveOutDevs[i].pwstrName);
  2177. Status = AudioAllocateMemory_Paged((wcslen(paWaveOutDevs[i].DeviceInterface) + 1) * sizeof(WCHAR),
  2178. TAG_AudD_DEVICEINFO,
  2179. DEFAULT_MEMORY,
  2180. &paMixerDevs[j].DeviceInterface);
  2181. if (NT_SUCCESS(Status))
  2182. {
  2183. wcscpy(paMixerDevs[j].DeviceInterface, paWaveOutDevs[i].DeviceInterface);
  2184. paMixerDevs[j].Device = paWaveOutDevs[i].Device;
  2185. paMixerDevs[j].PreferredDevice = paWaveOutDevs[i].PreferredDevice;
  2186. if (paWaveOutDevs[i].ComponentId)
  2187. {
  2188. Status = AudioAllocateMemory_Paged(sizeof(KSCOMPONENTID),
  2189. TAG_Audp_NAME,
  2190. DEFAULT_MEMORY,
  2191. &paMixerDevs[j].ComponentId);
  2192. if (NT_SUCCESS(Status))
  2193. {
  2194. RtlCopyMemory(paMixerDevs[j].ComponentId, paWaveOutDevs[i].ComponentId, sizeof(KSCOMPONENTID));
  2195. }
  2196. }
  2197. else
  2198. {
  2199. paMixerDevs[j].ComponentId = NULL;
  2200. }
  2201. } else {
  2202. AudioFreeMemory_Unknown(&paMixerDevs[j].pwstrName);
  2203. }
  2204. }
  2205. if (!NT_SUCCESS(Status)) {
  2206. RETURN( Status );
  2207. }
  2208. } // if
  2209. } // if
  2210. //
  2211. // Loop for WaveIn interfaces.
  2212. //
  2213. if( ( paWaveInDevs[ i ].Device != UNUSED_DEVICE ) &&
  2214. ( !MyWcsicmp(paWaveInDevs[ i ].DeviceInterface, DeviceInterface) ) ) {
  2215. for( j = 0; j < MAXNUMDEVS; j++ ) {
  2216. ASSERT(paMixerDevs[j].Device == UNUSED_DEVICE ?
  2217. NULL == paMixerDevs[j].DeviceInterface :
  2218. NULL != paMixerDevs[j].DeviceInterface);
  2219. if( ( paMixerDevs[ j ].Device != UNUSED_DEVICE ) &&
  2220. ( !MyWcsicmp(paMixerDevs[ j ].DeviceInterface, DeviceInterface) ) )
  2221. {
  2222. //
  2223. // We've found a devnode that has already been added
  2224. // to the mixer list.
  2225. //
  2226. kmxlDeInit(&paMixerDevs[j]);
  2227. paMixerDevs[ j ].Device = paWaveInDevs[ i ].Device;
  2228. break;
  2229. }
  2230. } // for
  2231. if( j == MAXNUMDEVS ) {
  2232. for( j = 0; j < MAXNUMDEVS; j++ ) {
  2233. if( paMixerDevs[ j ].Device == UNUSED_DEVICE ) {
  2234. break;
  2235. }
  2236. }
  2237. if( j == MAXNUMDEVS ) {
  2238. RETURN( STATUS_INSUFFICIENT_RESOURCES );
  2239. }
  2240. Status = AudioAllocateMemory_Paged((wcslen(paWaveInDevs[i].pwstrName) + 1) * sizeof(WCHAR),
  2241. TAG_AudD_DEVICEINFO,
  2242. DEFAULT_MEMORY,
  2243. &paMixerDevs[j].pwstrName);
  2244. if (NT_SUCCESS(Status))
  2245. {
  2246. wcscpy(paMixerDevs[j].pwstrName, paWaveInDevs[i].pwstrName);
  2247. Status = AudioAllocateMemory_Paged((wcslen(paWaveInDevs[i].DeviceInterface) + 1) * sizeof(WCHAR),
  2248. TAG_AudD_DEVICEINFO,
  2249. DEFAULT_MEMORY,
  2250. &paMixerDevs[j].DeviceInterface);
  2251. if (NT_SUCCESS(Status))
  2252. {
  2253. wcscpy(paMixerDevs[j].DeviceInterface, paWaveInDevs[i].DeviceInterface);
  2254. paMixerDevs[j].Device = paWaveInDevs[i].Device;
  2255. paMixerDevs[j].PreferredDevice = paWaveInDevs[i].PreferredDevice;
  2256. if (paWaveInDevs[i].ComponentId)
  2257. {
  2258. Status = AudioAllocateMemory_Paged(sizeof(KSCOMPONENTID),
  2259. TAG_Audp_NAME,
  2260. DEFAULT_MEMORY,
  2261. &paMixerDevs[j].ComponentId);
  2262. if (NT_SUCCESS(Status))
  2263. {
  2264. RtlCopyMemory(paMixerDevs[j].ComponentId, paWaveInDevs[i].ComponentId, sizeof(KSCOMPONENTID));
  2265. }
  2266. }
  2267. else
  2268. {
  2269. paMixerDevs[j].ComponentId = NULL;
  2270. }
  2271. } else {
  2272. AudioFreeMemory_Unknown(&paMixerDevs[j].pwstrName);
  2273. }
  2274. }
  2275. if (!NT_SUCCESS(Status)) {
  2276. RETURN( Status );
  2277. }
  2278. } // if
  2279. } // if
  2280. } // for
  2281. return( STATUS_SUCCESS );
  2282. }
  2283. NTSTATUS InitializeGetNumDevs
  2284. (
  2285. PWDMACONTEXT pWdmaContext,
  2286. DWORD DeviceType,
  2287. PCWSTR DeviceInterface,
  2288. LPDWORD lpNumberOfDevices
  2289. )
  2290. {
  2291. NTSTATUS Status=STATUS_SUCCESS;
  2292. HANDLE hDevice = NULL;
  2293. PDATARANGES pDataRanges = NULL;
  2294. PIDENTIFIERS pPinInterfaces = NULL;
  2295. PFILE_OBJECT pFileObjectDevice = NULL;
  2296. KSPIN_INTERFACE RequestedInterface;
  2297. KSPIN_DATAFLOW RequestedDataFlow;
  2298. GUID RequestedMajorFormat;
  2299. GUID RequestedSubFormat;
  2300. GUID guidCategory;
  2301. ULONG cPins;
  2302. ULONG PinId;
  2303. ULONG Device;
  2304. ULONG TotalDevices;
  2305. ULONG ulSize;
  2306. DWORD cDevs;
  2307. ULONG i;
  2308. BOOL fDeviceAdded = FALSE;
  2309. PAGED_CODE();
  2310. ASSERT(DeviceType == WaveOutDevice ||
  2311. DeviceType == WaveInDevice ||
  2312. DeviceType == MidiOutDevice ||
  2313. DeviceType == MidiInDevice ||
  2314. DeviceType == MixerDevice ||
  2315. DeviceType == AuxDevice);
  2316. DPF( DL_TRACE|FA_SYSAUDIO, ("Class = %d", DeviceType) );
  2317. //
  2318. // Setup a structure to compare with the interfaces that
  2319. // we want to find the number of.
  2320. //
  2321. switch (DeviceType)
  2322. {
  2323. case WaveOutDevice:
  2324. RequestedInterface.Set = KSINTERFACESETID_Media;
  2325. RequestedInterface.Id = KSINTERFACE_MEDIA_WAVE_QUEUED;
  2326. RequestedInterface.Flags = 0;
  2327. RequestedDataFlow = KSPIN_DATAFLOW_IN;
  2328. RequestedMajorFormat = KSDATAFORMAT_TYPE_AUDIO;
  2329. RequestedSubFormat = KSDATAFORMAT_TYPE_WILDCARD;
  2330. break;
  2331. case WaveInDevice:
  2332. RequestedInterface.Set = KSINTERFACESETID_Standard;
  2333. RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
  2334. RequestedInterface.Flags = 0;
  2335. RequestedDataFlow = KSPIN_DATAFLOW_OUT;
  2336. RequestedMajorFormat = KSDATAFORMAT_TYPE_AUDIO;
  2337. RequestedSubFormat = KSDATAFORMAT_TYPE_WILDCARD;
  2338. break;
  2339. case MidiOutDevice:
  2340. RequestedInterface.Set = KSINTERFACESETID_Standard;
  2341. RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
  2342. RequestedInterface.Flags = 0;
  2343. RequestedDataFlow = KSPIN_DATAFLOW_IN;
  2344. RequestedMajorFormat = KSDATAFORMAT_TYPE_MUSIC;
  2345. RequestedSubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
  2346. break;
  2347. case MidiInDevice:
  2348. RequestedInterface.Set = KSINTERFACESETID_Standard;
  2349. RequestedInterface.Id = KSINTERFACE_STANDARD_STREAMING;
  2350. RequestedInterface.Flags = 0;
  2351. RequestedDataFlow = KSPIN_DATAFLOW_OUT;
  2352. RequestedMajorFormat = KSDATAFORMAT_TYPE_MUSIC;
  2353. RequestedSubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
  2354. break;
  2355. case MixerDevice:
  2356. Status = InitializeMixerGetNumDevs( pWdmaContext, DeviceInterface );
  2357. fDeviceAdded = NT_SUCCESS(Status);
  2358. goto exit;
  2359. case AuxDevice:
  2360. Status = InitializeAuxGetNumDevs( pWdmaContext, DeviceInterface );
  2361. fDeviceAdded = NT_SUCCESS(Status);
  2362. goto exit;
  2363. }
  2364. //
  2365. // Get a handle to sysaudio
  2366. //
  2367. Status = OpenSysAudio(&hDevice, &pFileObjectDevice);
  2368. if(!NT_SUCCESS(Status))
  2369. {
  2370. goto exit;
  2371. }
  2372. //
  2373. // for every pin on every device see if the interface matches
  2374. // the DeviceType requested from user mode
  2375. //
  2376. Status = GetSysAudioProperty(pFileObjectDevice,
  2377. KSPROPERTY_SYSAUDIO_DEVICE_COUNT,
  2378. 0, // not used
  2379. sizeof(TotalDevices),
  2380. &TotalDevices);
  2381. if(!NT_SUCCESS(Status))
  2382. {
  2383. DPF(DL_WARNING|FA_SYSAUDIO,("GetSysAudioProperty failed Status=%X",Status) );
  2384. goto exit;
  2385. }
  2386. for (Device = 0; Device < TotalDevices; Device++)
  2387. {
  2388. //
  2389. // Set the default renderer
  2390. //
  2391. Status = SetSysAudioProperty(pFileObjectDevice,
  2392. KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
  2393. sizeof(Device),
  2394. &Device);
  2395. if(!NT_SUCCESS(Status))
  2396. {
  2397. DPF(DL_WARNING|FA_SYSAUDIO,("GetSysAudioProperty failed Status=%X",Status) );
  2398. goto exit;
  2399. }
  2400. //
  2401. // Verify that this device matches the DevNode
  2402. // being enumerated
  2403. //
  2404. if (!IsPinForDevNode(pFileObjectDevice,Device,DeviceInterface))
  2405. {
  2406. continue;
  2407. }
  2408. //
  2409. // Get the number of pins on the default renderer
  2410. //
  2411. Status = GetPinProperty(pFileObjectDevice,
  2412. KSPROPERTY_PIN_CTYPES,
  2413. 0,
  2414. sizeof(cPins),
  2415. &cPins);
  2416. if(!NT_SUCCESS(Status))
  2417. {
  2418. DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
  2419. goto exit;
  2420. }
  2421. for(PinId = cPins; PinId > 0; PinId--)
  2422. {
  2423. KSPIN_DATAFLOW DataFlow;
  2424. KSPIN_COMMUNICATION CommunicationType;
  2425. PKSDATARANGE pDataRange;
  2426. PWSTR pwstrName = NULL;
  2427. PKSCOMPONENTID ComponentId = NULL;
  2428. BOOL fInterfaceFound;
  2429. BOOL fUsePreferred;
  2430. ULONG index;
  2431. ULONG d;
  2432. //
  2433. // Check the dataflow
  2434. //
  2435. Status = GetPinProperty(pFileObjectDevice,
  2436. KSPROPERTY_PIN_DATAFLOW,
  2437. PinId-1,
  2438. sizeof(KSPIN_DATAFLOW),
  2439. &DataFlow);
  2440. if(!NT_SUCCESS(Status))
  2441. {
  2442. DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
  2443. goto exit;
  2444. }
  2445. if(RequestedDataFlow != DataFlow)
  2446. {
  2447. continue;
  2448. }
  2449. //
  2450. // Check the communication type
  2451. //
  2452. Status = GetPinProperty(pFileObjectDevice,
  2453. KSPROPERTY_PIN_COMMUNICATION,
  2454. PinId-1,
  2455. sizeof(KSPIN_COMMUNICATION),
  2456. &CommunicationType);
  2457. if(!NT_SUCCESS(Status))
  2458. {
  2459. DPF(DL_WARNING|FA_SYSAUDIO,("GetPinProperty failed Status=%X",Status) );
  2460. goto exit;
  2461. }
  2462. if(KSPIN_COMMUNICATION_SINK != CommunicationType &&
  2463. KSPIN_COMMUNICATION_BOTH != CommunicationType)
  2464. {
  2465. continue;
  2466. }
  2467. //
  2468. // Allocates memory on my behalf. Free later!!!
  2469. //
  2470. Status = GetPinPropertyEx(pFileObjectDevice,
  2471. KSPROPERTY_PIN_INTERFACES,
  2472. PinId-1,
  2473. &pPinInterfaces);
  2474. //
  2475. // GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
  2476. // expect. Thus, if we get this error, we need to keep looking rather
  2477. // then fail. If it returns STATUS_PROPSET_NOT_FOUND pPinInterfaces
  2478. // will be NULL thus we must not touch it.
  2479. //
  2480. // Thus, if not successful AND not a successful error -> error out.
  2481. //
  2482. if(!NT_SUCCESS(Status) && Status != STATUS_PROPSET_NOT_FOUND )
  2483. {
  2484. DPF(DL_WARNING|FA_SYSAUDIO,("GetPinPropertyEx failed Status=%X",Status) );
  2485. goto exit;
  2486. }
  2487. if( pPinInterfaces )
  2488. {
  2489. //
  2490. // Find an interface that matches
  2491. //
  2492. fInterfaceFound = FALSE;
  2493. for(index = 0; index < pPinInterfaces->Count; index++)
  2494. {
  2495. if (IsEqualInterface(&RequestedInterface,
  2496. &pPinInterfaces->aIdentifiers[index]))
  2497. {
  2498. fInterfaceFound = TRUE;
  2499. break;
  2500. }
  2501. }
  2502. //
  2503. // We're done with the memory, so free
  2504. //
  2505. AudioFreeMemory_Unknown(&pPinInterfaces);
  2506. if (!fInterfaceFound)
  2507. {
  2508. continue;
  2509. }
  2510. }
  2511. //
  2512. // If the device exposes a component Id, get it and cache it in AddDevice
  2513. //
  2514. Status = AudioAllocateMemory_Paged(sizeof(*ComponentId),
  2515. TAG_Audp_NAME,
  2516. ZERO_FILL_MEMORY,
  2517. &ComponentId);
  2518. if(NT_SUCCESS(Status))
  2519. {
  2520. Status = GetSysAudioProperty(pFileObjectDevice,
  2521. KSPROPERTY_SYSAUDIO_COMPONENT_ID,
  2522. Device,
  2523. sizeof(*ComponentId),
  2524. ComponentId);
  2525. //
  2526. // WorkItem: It is highly likely that GetSysAudioProperty will
  2527. // return STATUS_INVALID_DEVICE_REQUEST for this call. Why?
  2528. //
  2529. if (!NT_SUCCESS(Status))
  2530. {
  2531. // Not a failure
  2532. AudioFreeMemory_Unknown(&ComponentId);
  2533. ComponentId = NULL;
  2534. }
  2535. }
  2536. fUsePreferred = FALSE;
  2537. pwstrName = NULL;
  2538. // Get the friendly name for this device.
  2539. // - First see if it the category is KSCATEGORY_WDMAUD_USE_PIN_NAME because
  2540. // SWMIDI uses this and there should only be one instance of SWMIDI
  2541. // in the system.
  2542. //
  2543. // - Next check to see if the pins provide names, without using the
  2544. // KSCATEGORY_WDMAUD_USE_PIN_NAME category. If so, use the name provided
  2545. // by the pin.
  2546. //
  2547. // - Lastly, use the friendly name for the device if it exists.
  2548. //
  2549. // If all attempts to get a name fail, then this pin is not used by WDMAUD.
  2550. Status = GetPinProperty(pFileObjectDevice,
  2551. KSPROPERTY_PIN_CATEGORY,
  2552. PinId-1,
  2553. sizeof(GUID),
  2554. &guidCategory);
  2555. //
  2556. // WorkItem: GetPinProperty returns code c0000225 - STATUS_INVALID_DEVICE_REQUEST
  2557. // for this call. Why?
  2558. //
  2559. if(NT_SUCCESS(Status))
  2560. {
  2561. if(IsEqualGUID(&KSCATEGORY_WDMAUD_USE_PIN_NAME, &guidCategory))
  2562. {
  2563. Status = GetPinPropertyEx(pFileObjectDevice,
  2564. KSPROPERTY_PIN_NAME,
  2565. PinId-1,
  2566. &pwstrName);
  2567. //
  2568. // GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
  2569. // expect. Thus, if we get this error, we need to keep looking rather
  2570. // then fail. If it returns STATUS_PROPSET_NOT_FOUND pwstrName
  2571. // will be NULL thus we must not touch it.
  2572. //
  2573. // Thus, if successful or it's the successful error code -> success
  2574. //
  2575. if(NT_SUCCESS(Status) || Status == STATUS_PROPSET_NOT_FOUND)
  2576. {
  2577. fUsePreferred = TRUE;
  2578. }
  2579. else
  2580. {
  2581. ASSERT(pwstrName == NULL);
  2582. }
  2583. }
  2584. }
  2585. // As long as this is not SWMIDI, first try reading the name from the component ID
  2586. if ((fUsePreferred == FALSE) && (ComponentId != NULL))
  2587. {
  2588. ReadProductNameFromMediaCategories(&ComponentId->Name,
  2589. &pwstrName);
  2590. }
  2591. // If that didn't work, take the regular old friendly name
  2592. if(pwstrName == NULL)
  2593. {
  2594. Status = GetSysAudioProperty(
  2595. pFileObjectDevice,
  2596. KSPROPERTY_SYSAUDIO_DEVICE_FRIENDLY_NAME,
  2597. Device,
  2598. sizeof(ulSize),
  2599. &ulSize);
  2600. if(NT_SUCCESS(Status))
  2601. {
  2602. Status = AudioAllocateMemory_Paged(ulSize,
  2603. TAG_Audp_NAME,
  2604. ZERO_FILL_MEMORY,
  2605. &pwstrName);
  2606. if(!NT_SUCCESS(Status))
  2607. {
  2608. goto exit;
  2609. }
  2610. Status = GetSysAudioProperty(
  2611. pFileObjectDevice,
  2612. KSPROPERTY_SYSAUDIO_DEVICE_FRIENDLY_NAME,
  2613. Device,
  2614. ulSize,
  2615. pwstrName);
  2616. if (!NT_SUCCESS(Status))
  2617. {
  2618. AudioFreeMemory_Unknown(&pwstrName);
  2619. }
  2620. }
  2621. //
  2622. // Last chance...don't use devices without names
  2623. //
  2624. if (pwstrName == NULL)
  2625. {
  2626. AudioFreeMemory_Unknown(&ComponentId);
  2627. continue;
  2628. }
  2629. }
  2630. //
  2631. // Allocates memory on my behalf. Store these
  2632. // dataranges in the structure of the device if
  2633. // we find a match that is good.
  2634. //
  2635. Status = GetPinPropertyEx(pFileObjectDevice,
  2636. KSPROPERTY_PIN_DATARANGES,
  2637. PinId-1,
  2638. &pDataRanges);
  2639. //
  2640. // GetPinPropertyEx can return STATUS_PROPSET_NOT_FOUND which we
  2641. // expect. Thus, if we get this error, we need to keep looking rather
  2642. // then fail. If it returns STATUS_PROPSET_NOT_FOUND pDataRanges
  2643. // will be NULL thus we must not touch it.
  2644. //
  2645. // Thus, if not successful AND not a successful error -> error out.
  2646. //
  2647. if (!NT_SUCCESS(Status) && Status != STATUS_PROPSET_NOT_FOUND )
  2648. {
  2649. DPF(DL_WARNING|FA_SYSAUDIO,("GetPinPropertyEx failed Status=%X",Status) );
  2650. goto exit;
  2651. }
  2652. if( pDataRanges )
  2653. {
  2654. //
  2655. // See if we have a majorformat and subformat that
  2656. // we want
  2657. //
  2658. pDataRange = &pDataRanges->aDataRanges[0];
  2659. for(d = 0; d < pDataRanges->Count; d++)
  2660. {
  2661. if (IsEqualGUID(&RequestedMajorFormat,
  2662. &pDataRange->MajorFormat) &&
  2663. (IsEqualGUID(&RequestedSubFormat,
  2664. &KSDATAFORMAT_TYPE_WILDCARD) ||
  2665. IsEqualGUID(&RequestedSubFormat,
  2666. &pDataRange->SubFormat) ) )
  2667. {
  2668. DPF( DL_TRACE|FA_SYSAUDIO, ("Found device!!!") );
  2669. //
  2670. // Store so that we can retrieve later on
  2671. // an open or getcaps call
  2672. //
  2673. Status = AddDevice(pWdmaContext,
  2674. Device,
  2675. DeviceType,
  2676. DeviceInterface,
  2677. PinId-1,
  2678. pwstrName,
  2679. fUsePreferred,
  2680. pDataRanges,
  2681. ComponentId);
  2682. if (NT_SUCCESS(Status))
  2683. {
  2684. fDeviceAdded = TRUE;
  2685. //
  2686. // Mark these NULL so that it doesn't get freed
  2687. // at the end of the loop.
  2688. //
  2689. // This memory will get freed when the devnode
  2690. // is removed and the device entry gets cleaned
  2691. // up in RemoveDevNode.
  2692. //
  2693. pwstrName = NULL;
  2694. pDataRanges = NULL;
  2695. ComponentId = NULL;
  2696. }
  2697. break; // Don't need to check anymore dataranges
  2698. }
  2699. // Get the pointer to the next data range
  2700. (PUCHAR)pDataRange += ((pDataRange->FormatSize +
  2701. FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
  2702. }
  2703. }
  2704. //
  2705. // We're done with the memory, so free
  2706. //
  2707. AudioFreeMemory_Unknown(&pDataRanges);
  2708. AudioFreeMemory_Unknown(&pwstrName);
  2709. AudioFreeMemory_Unknown(&ComponentId);
  2710. } // pin enumeration
  2711. } // device enumeration
  2712. exit:
  2713. //
  2714. // Close down sysaudio for now
  2715. //
  2716. AudioFreeMemory_Unknown(&pPinInterfaces);
  2717. AudioFreeMemory_Unknown(&pDataRanges);
  2718. if(pFileObjectDevice != NULL)
  2719. {
  2720. ObDereferenceObject(pFileObjectDevice);
  2721. }
  2722. if(hDevice != NULL)
  2723. {
  2724. NtClose(hDevice);
  2725. }
  2726. if(fDeviceAdded)
  2727. {
  2728. PCOMMONDEVICE *ppCommonDevice;
  2729. ULONG cRealDevs;
  2730. ppCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  2731. for (cRealDevs = cDevs = i = 0; i < MAXNUMDEVS; i++)
  2732. {
  2733. if (ppCommonDevice[i]->Device == UNUSED_DEVICE ||
  2734. MyWcsicmp(ppCommonDevice[i]->DeviceInterface, DeviceInterface))
  2735. {
  2736. continue;
  2737. }
  2738. ++cRealDevs;
  2739. if (ppCommonDevice[i]->PreferredDevice == MAXULONG ||
  2740. ppCommonDevice[i]->PreferredDevice == i)
  2741. {
  2742. ++cDevs;
  2743. }
  2744. }
  2745. if(cDevs == 0 && cRealDevs > 0) {
  2746. *lpNumberOfDevices = MAXULONG;
  2747. }
  2748. else {
  2749. *lpNumberOfDevices = cDevs;
  2750. }
  2751. }
  2752. else
  2753. {
  2754. *lpNumberOfDevices = 0;
  2755. }
  2756. RETURN( Status );
  2757. }
  2758. NTSTATUS wdmaudGetNumDevs
  2759. (
  2760. PWDMACONTEXT pContext,
  2761. DWORD DeviceType,
  2762. PCWSTR DeviceInterfaceIn,
  2763. LPDWORD lpNumberOfDevices
  2764. )
  2765. {
  2766. PDEVNODE_LIST_ITEM pDevNodeListItem;
  2767. NTSTATUS Status = STATUS_SUCCESS;
  2768. LARGE_INTEGER li = {0, 0};
  2769. PLIST_ENTRY ple;
  2770. PAGED_CODE();
  2771. ASSERT(DeviceType == WaveOutDevice ||
  2772. DeviceType == WaveInDevice ||
  2773. DeviceType == MidiOutDevice ||
  2774. DeviceType == MidiInDevice ||
  2775. DeviceType == MixerDevice ||
  2776. DeviceType == AuxDevice);
  2777. *lpNumberOfDevices = 0;
  2778. //
  2779. // Can't use WdmaGrabMutex/WdmaReleaseMutex here
  2780. //
  2781. ASSERT(Status == STATUS_SUCCESS);
  2782. for(ple = pContext->DevNodeListHead.Flink; ple != &pContext->DevNodeListHead; ple = ple->Flink) {
  2783. pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
  2784. if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
  2785. if(pDevNodeListItem->cDevices[DeviceType] == MAXULONG) {
  2786. DPF( DL_TRACE|FA_SYSAUDIO, ("MAXULONG: %ls[%d]",
  2787. DeviceInterfaceIn,
  2788. DeviceType));
  2789. //
  2790. // This status code there are still some pending add or
  2791. // remove devices so the actual number of devices can't
  2792. // be returned.
  2793. //
  2794. Status = STATUS_DEVICE_OFF_LINE;
  2795. }
  2796. else {
  2797. *lpNumberOfDevices = pDevNodeListItem->cDevices[DeviceType];
  2798. ASSERT(Status == STATUS_SUCCESS);
  2799. }
  2800. goto exit;
  2801. }
  2802. }
  2803. //
  2804. // This status code there are still some pending add or
  2805. // remove devices so the actual number of devices can't
  2806. // be returned.
  2807. //
  2808. Status = STATUS_DEVICE_OFF_LINE;
  2809. exit:
  2810. if(NT_SUCCESS(Status)) {
  2811. DPF( DL_TRACE|FA_SYSAUDIO, ("SUCCESS %ls[%d] %d",
  2812. DeviceInterfaceIn,
  2813. DeviceType,
  2814. *lpNumberOfDevices));
  2815. }
  2816. RETURN(Status);
  2817. }
  2818. NTSTATUS PinProperty
  2819. (
  2820. PFILE_OBJECT pFileObject,
  2821. const GUID *pPropertySet,
  2822. ULONG ulPropertyId,
  2823. ULONG ulFlags,
  2824. ULONG cbProperty,
  2825. PVOID pProperty
  2826. )
  2827. {
  2828. KSPROPERTY Property;
  2829. ULONG BytesReturned;
  2830. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2831. PAGED_CODE();
  2832. if (pFileObject)
  2833. {
  2834. Property.Set = *pPropertySet;
  2835. Property.Id = ulPropertyId;
  2836. Property.Flags = ulFlags;
  2837. ASSERT( pFileObject || !"PinProperty called with invalid pFileObject");
  2838. if (ulPropertyId == KSPROPERTY_CONNECTION_STATE)
  2839. {
  2840. DPF( DL_TRACE|FA_SYSAUDIO, ("State=%d",*(PKSSTATE)pProperty));
  2841. }
  2842. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",ulPropertyId) );
  2843. Status = KsSynchronousIoControlDevice(
  2844. pFileObject,
  2845. KernelMode,
  2846. IOCTL_KS_PROPERTY,
  2847. &Property,
  2848. sizeof(Property),
  2849. pProperty,
  2850. cbProperty,
  2851. &BytesReturned);
  2852. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pProperty=%X,cbProperty=%X,BytesRet=%d",
  2853. Status,pProperty,cbProperty,BytesReturned) );
  2854. }
  2855. if(!NT_SUCCESS(Status))
  2856. {
  2857. DPF(DL_TRACE|FA_SYSAUDIO, ("FAILED SetState = %d",*(PKSSTATE)pProperty));
  2858. goto exit;
  2859. }
  2860. exit:
  2861. RETURN(Status);
  2862. }
  2863. NTSTATUS PinMethod
  2864. (
  2865. PFILE_OBJECT pFileObject,
  2866. const GUID *pMethodSet,
  2867. ULONG ulMethodId,
  2868. ULONG ulFlags,
  2869. ULONG cbMethod,
  2870. PVOID pMethod
  2871. )
  2872. {
  2873. KSMETHOD Method;
  2874. ULONG BytesReturned;
  2875. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2876. PAGED_CODE();
  2877. if (pFileObject)
  2878. {
  2879. Method.Set = *pMethodSet;
  2880. Method.Id = ulMethodId;
  2881. Method.Flags = ulFlags;
  2882. ASSERT( pFileObject || !"PinMethod called with invalid pFileObject");
  2883. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",ulMethodId) );
  2884. Status = KsSynchronousIoControlDevice(
  2885. pFileObject,
  2886. KernelMode,
  2887. IOCTL_KS_METHOD,
  2888. &Method,
  2889. sizeof(Method),
  2890. pMethod,
  2891. cbMethod,
  2892. &BytesReturned);
  2893. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X, pMethod=%X,cbMethod=%X,BytesRet=%d",
  2894. Status,pMethod,cbMethod,BytesReturned) );
  2895. }
  2896. if(!NT_SUCCESS(Status))
  2897. {
  2898. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Status=%X",Status) );
  2899. goto exit;
  2900. }
  2901. exit:
  2902. RETURN(Status);
  2903. }
  2904. NTSTATUS
  2905. AttachVirtualSource(
  2906. PFILE_OBJECT pFileObject,
  2907. ULONG ulPinId
  2908. )
  2909. {
  2910. SYSAUDIO_ATTACH_VIRTUAL_SOURCE AttachVirtualSource;
  2911. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2912. ULONG BytesReturned;
  2913. PAGED_CODE();
  2914. if (pFileObject)
  2915. {
  2916. if(ulPinId == MAXULONG) {
  2917. DPF(DL_WARNING|FA_SYSAUDIO,("Invalid ulPinId=%X",ulPinId) );
  2918. Status = STATUS_INVALID_DEVICE_REQUEST;
  2919. goto exit;
  2920. }
  2921. AttachVirtualSource.Property.Set = KSPROPSETID_Sysaudio_Pin;
  2922. AttachVirtualSource.Property.Id =
  2923. KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE;
  2924. AttachVirtualSource.Property.Flags = KSPROPERTY_TYPE_SET;
  2925. AttachVirtualSource.MixerPinId = ulPinId;
  2926. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Id=%X",
  2927. AttachVirtualSource.Property.Id) );
  2928. Status = KsSynchronousIoControlDevice(
  2929. pFileObject,
  2930. KernelMode,
  2931. IOCTL_KS_PROPERTY,
  2932. &AttachVirtualSource,
  2933. sizeof(AttachVirtualSource),
  2934. NULL,
  2935. 0,
  2936. &BytesReturned);
  2937. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  2938. Status,BytesReturned) );
  2939. }
  2940. if(!NT_SUCCESS(Status)) {
  2941. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Status=%X",Status) );
  2942. goto exit;
  2943. }
  2944. exit:
  2945. RETURN(Status);
  2946. }
  2947. NTSTATUS
  2948. SysAudioPnPNotification(
  2949. IN PVOID NotificationStructure,
  2950. IN PVOID _Context
  2951. )
  2952. {
  2953. PWDMACONTEXT pContext = (PWDMACONTEXT)_Context;
  2954. PDEVICE_INTERFACE_CHANGE_NOTIFICATION pNotification;
  2955. NTSTATUS Status = STATUS_SUCCESS;
  2956. PAGED_CODE();
  2957. ASSERT(pContext);
  2958. DPF( DL_TRACE|FA_SYSAUDIO,("pWdmaContext=%08Xh", pContext) );
  2959. pNotification =
  2960. (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
  2961. // The notification sends null terminated unicode strings
  2962. if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
  2963. Status = QueueWorkList(pContext, InitializeSysaudio, pContext, 0);
  2964. if (!NT_SUCCESS(Status)) {
  2965. // At this point pContext->fInitializeSysaudio will still be false because we never
  2966. // ran the work item. If we don't signal this event, IOCTL_WDMAUD_INIT will deadlock.
  2967. ASSERT(pContext->fInitializeSysaudio == FALSE);
  2968. KeSetEvent(&pContext->InitializedSysaudioEvent, 0, FALSE);
  2969. }
  2970. }
  2971. return(Status);
  2972. }
  2973. NTSTATUS
  2974. InitializeSysaudio(
  2975. PVOID Reference1,
  2976. PVOID Reference2
  2977. )
  2978. {
  2979. PWDMACONTEXT pWdmaContext = (PWDMACONTEXT)Reference1;
  2980. SYSAUDIO_CREATE_VIRTUAL_SOURCE CreateVirtualSource;
  2981. NTSTATUS Status = STATUS_SUCCESS;
  2982. ULONG BytesReturned;
  2983. KSEVENT Event;
  2984. PAGED_CODE();
  2985. ASSERT(pWdmaContext);
  2986. DPF( DL_TRACE|FA_SYSAUDIO,("pWdmaContext=%08Xh", pWdmaContext) );
  2987. if(pWdmaContext->SysaudioWorkerObject == NULL) {
  2988. goto exit;
  2989. }
  2990. if( pWdmaContext->pFileObjectSysaudio == NULL )
  2991. {
  2992. pWdmaContext->pFileObjectSysaudio = kmxlOpenSysAudio();
  2993. if( pWdmaContext->pFileObjectSysaudio == NULL )
  2994. {
  2995. DPF(DL_WARNING|FA_SYSAUDIO,("NULL pFileObjectSysaudio, pWdmaContext=%08X",pWdmaContext) );
  2996. goto exit;
  2997. }
  2998. }
  2999. //
  3000. // Initialize the wave and synth virtual source lines
  3001. //
  3002. CreateVirtualSource.Property.Set = KSPROPSETID_Sysaudio;
  3003. CreateVirtualSource.Property.Flags = KSPROPERTY_TYPE_GET;
  3004. if(pWdmaContext->VirtualWavePinId == MAXULONG) {
  3005. CreateVirtualSource.Property.Id =
  3006. KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE_ONLY;
  3007. CreateVirtualSource.PinCategory = KSNODETYPE_LEGACY_AUDIO_CONNECTOR;
  3008. CreateVirtualSource.PinName = KSNODETYPE_LEGACY_AUDIO_CONNECTOR;
  3009. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
  3010. Status = KsSynchronousIoControlDevice(
  3011. pWdmaContext->pFileObjectSysaudio,
  3012. KernelMode,
  3013. IOCTL_KS_PROPERTY,
  3014. &CreateVirtualSource,
  3015. sizeof(CreateVirtualSource),
  3016. &pWdmaContext->VirtualWavePinId,
  3017. sizeof(pWdmaContext->VirtualWavePinId),
  3018. &BytesReturned);
  3019. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  3020. Status,BytesReturned) );
  3021. if(!NT_SUCCESS(Status)) {
  3022. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  3023. goto exit;
  3024. }
  3025. ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualWavePinId));
  3026. }
  3027. if(pWdmaContext->VirtualMidiPinId == MAXULONG) {
  3028. CreateVirtualSource.Property.Id =
  3029. KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
  3030. CreateVirtualSource.PinCategory = KSNODETYPE_SYNTHESIZER;
  3031. CreateVirtualSource.PinName = KSNODETYPE_SWSYNTH;
  3032. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
  3033. Status = KsSynchronousIoControlDevice(
  3034. pWdmaContext->pFileObjectSysaudio,
  3035. KernelMode,
  3036. IOCTL_KS_PROPERTY,
  3037. &CreateVirtualSource,
  3038. sizeof(CreateVirtualSource),
  3039. &pWdmaContext->VirtualMidiPinId,
  3040. sizeof(pWdmaContext->VirtualMidiPinId),
  3041. &BytesReturned);
  3042. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  3043. Status,BytesReturned) );
  3044. if(!NT_SUCCESS(Status)) {
  3045. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  3046. goto exit;
  3047. }
  3048. ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualMidiPinId));
  3049. }
  3050. if(pWdmaContext->VirtualCDPinId == MAXULONG) {
  3051. CreateVirtualSource.Property.Id =
  3052. KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
  3053. CreateVirtualSource.PinCategory = KSNODETYPE_CD_PLAYER;
  3054. CreateVirtualSource.PinName = KSNODETYPE_CD_PLAYER;
  3055. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY %X",CreateVirtualSource) );
  3056. Status = KsSynchronousIoControlDevice(
  3057. pWdmaContext->pFileObjectSysaudio,
  3058. KernelMode,
  3059. IOCTL_KS_PROPERTY,
  3060. &CreateVirtualSource,
  3061. sizeof(CreateVirtualSource),
  3062. &pWdmaContext->VirtualCDPinId,
  3063. sizeof(pWdmaContext->VirtualCDPinId),
  3064. &BytesReturned);
  3065. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  3066. Status,BytesReturned) );
  3067. if(!NT_SUCCESS(Status)) {
  3068. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  3069. goto exit;
  3070. }
  3071. ASSERT(BytesReturned == sizeof(pWdmaContext->VirtualCDPinId));
  3072. }
  3073. //
  3074. // Initialize the device add/remove ks event
  3075. //
  3076. if(!pWdmaContext->fInitializeSysaudio) {
  3077. Event.Set = KSEVENTSETID_Sysaudio;
  3078. Event.Id = KSEVENT_SYSAUDIO_ADDREMOVE_DEVICE;
  3079. Event.Flags = KSEVENT_TYPE_ENABLE;
  3080. pWdmaContext->EventData.NotificationType = KSEVENTF_KSWORKITEM;
  3081. pWdmaContext->EventData.KsWorkItem.WorkQueueItem =
  3082. &pWdmaContext->SysaudioWorkItem;
  3083. pWdmaContext->EventData.KsWorkItem.KsWorkerObject =
  3084. pWdmaContext->SysaudioWorkerObject;
  3085. pWdmaContext->EventData.KsWorkItem.Reserved = 0;
  3086. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY Event=%X",Event) );
  3087. Status = KsSynchronousIoControlDevice(
  3088. pWdmaContext->pFileObjectSysaudio,
  3089. KernelMode,
  3090. IOCTL_KS_ENABLE_EVENT,
  3091. &Event,
  3092. sizeof(Event),
  3093. &pWdmaContext->EventData,
  3094. sizeof(pWdmaContext->EventData),
  3095. &BytesReturned);
  3096. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  3097. Status,BytesReturned) );
  3098. if(!NT_SUCCESS(Status)) {
  3099. DPF(DL_WARNING|FA_SYSAUDIO,("Failed Property query Status=%X",Status) );
  3100. goto exit;
  3101. }
  3102. pWdmaContext->fInitializeSysaudio = TRUE;
  3103. }
  3104. exit:
  3105. KeSetEvent(&pWdmaContext->InitializedSysaudioEvent, 0, FALSE);
  3106. RETURN(Status);
  3107. }
  3108. VOID
  3109. UninitializeSysaudio(
  3110. PWDMACONTEXT pWdmaContext
  3111. )
  3112. {
  3113. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3114. ULONG BytesReturned;
  3115. PAGED_CODE();
  3116. DPF( DL_TRACE|FA_SYSAUDIO, ("Entering") );
  3117. if(pWdmaContext->pFileObjectSysaudio != NULL) {
  3118. if(pWdmaContext->fInitializeSysaudio) {
  3119. DPF( DL_TRACE|FA_SYSAUDIO,("KS_DISABLE_EVENT EventData=%X",
  3120. pWdmaContext->EventData) );
  3121. Status = KsSynchronousIoControlDevice(
  3122. pWdmaContext->pFileObjectSysaudio,
  3123. KernelMode,
  3124. IOCTL_KS_DISABLE_EVENT,
  3125. &pWdmaContext->EventData,
  3126. sizeof(pWdmaContext->EventData),
  3127. NULL,
  3128. 0,
  3129. &BytesReturned);
  3130. DPF( DL_TRACE|FA_SYSAUDIO,("KS_PROPERTY results Status=%X,BytesRet=%d",
  3131. Status,BytesReturned) );
  3132. pWdmaContext->VirtualWavePinId = MAXULONG;
  3133. pWdmaContext->VirtualMidiPinId = MAXULONG;
  3134. pWdmaContext->VirtualCDPinId = MAXULONG;
  3135. pWdmaContext->fInitializeSysaudio = FALSE;
  3136. DPF( DL_TRACE|FA_SYSAUDIO,("Exiting %08x", Status));
  3137. }
  3138. }
  3139. }
  3140. NTSTATUS
  3141. AddDevNode(
  3142. PWDMACONTEXT pContext,
  3143. PCWSTR DeviceInterfaceIn,
  3144. UINT DeviceType
  3145. )
  3146. {
  3147. NTSTATUS Status=STATUS_SUCCESS;
  3148. PDEVNODE_LIST_ITEM pDevNodeListItem = NULL;
  3149. PLIST_ENTRY ple;
  3150. ULONG t;
  3151. PAGED_CODE();
  3152. DPF( DL_TRACE|FA_SYSAUDIO,("%08x [%ls] %d", pContext, DeviceInterfaceIn, DeviceType));
  3153. for(ple = pContext->DevNodeListHead.Flink; ple != &pContext->DevNodeListHead; ple = ple->Flink) {
  3154. pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
  3155. if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
  3156. ++pDevNodeListItem->cReference;
  3157. DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now %d", pDevNodeListItem->cReference));
  3158. goto exit;
  3159. }
  3160. }
  3161. // Limit the number of devnodes that can be added
  3162. if (pContext->DevNodeListCount > MAXDEVNODES) {
  3163. Status = STATUS_INSUFFICIENT_RESOURCES;
  3164. goto exit;
  3165. }
  3166. pDevNodeListItem = NULL;
  3167. Status = AudioAllocateMemory_Paged(sizeof(DEVNODE_LIST_ITEM),
  3168. TAG_AudN_NODE,
  3169. ZERO_FILL_MEMORY,
  3170. &pDevNodeListItem);
  3171. if(!NT_SUCCESS(Status)) {
  3172. goto exit;
  3173. }
  3174. DPF( DL_TRACE|FA_SYSAUDIO, ("New pDevNodeListItem (%08x)", pDevNodeListItem));
  3175. Status = AudioAllocateMemory_Paged((wcslen(DeviceInterfaceIn)+1)*sizeof(WCHAR),
  3176. TAG_AudD_DEVICEINFO,
  3177. ZERO_FILL_MEMORY,
  3178. &pDevNodeListItem->DeviceInterface);
  3179. if (!NT_SUCCESS(Status)) {
  3180. AudioFreeMemory(sizeof(DEVNODE_LIST_ITEM),&pDevNodeListItem);
  3181. goto exit;
  3182. }
  3183. wcscpy(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn);
  3184. pDevNodeListItem->cReference = 1;
  3185. DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now 1"));
  3186. for(t = 0; t < MAX_DEVICE_CLASS; t++) {
  3187. pDevNodeListItem->cDevices[t] = MAXULONG;
  3188. pDevNodeListItem->fAdded[t] = FALSE;
  3189. }
  3190. InsertTailList(&pContext->DevNodeListHead, &pDevNodeListItem->Next);
  3191. pContext->DevNodeListCount++;
  3192. exit:
  3193. if (pDevNodeListItem)
  3194. {
  3195. pDevNodeListItem->fAdded[DeviceType] = TRUE;
  3196. Status=ProcessDevNodeListItem(pContext, pDevNodeListItem, DeviceType);
  3197. }
  3198. RETURN( Status );
  3199. }
  3200. VOID
  3201. RemoveDevNode(
  3202. PWDMACONTEXT pWdmaContext,
  3203. PCWSTR DeviceInterfaceIn,
  3204. UINT DeviceType
  3205. )
  3206. {
  3207. PDEVNODE_LIST_ITEM pDevNodeListItem;
  3208. PLIST_ENTRY ple, pleNext;
  3209. PCOMMONDEVICE *papCommonDevice;
  3210. ULONG d, j;
  3211. PAGED_CODE();
  3212. DPF( DL_TRACE|FA_SYSAUDIO, ("%08x %ls %d", pWdmaContext, DeviceInterfaceIn, DeviceType));
  3213. papCommonDevice = &pWdmaContext->apCommonDevice[DeviceType][0];
  3214. for(ple = pWdmaContext->DevNodeListHead.Flink; ple != &pWdmaContext->DevNodeListHead; ple = pleNext) {
  3215. pleNext = ple->Flink;
  3216. pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
  3217. if(!MyWcsicmp(pDevNodeListItem->DeviceInterface, DeviceInterfaceIn)) {
  3218. for (d = 0; d < MAXNUMDEVS; d++) {
  3219. if(papCommonDevice[d]->Device == UNUSED_DEVICE ||
  3220. MyWcsicmp(papCommonDevice[d]->DeviceInterface, DeviceInterfaceIn)) {
  3221. continue;
  3222. }
  3223. if(papCommonDevice[d]->PreferredDevice == d) {
  3224. ULONG p = MAXULONG;
  3225. for(j = 0; j < MAXNUMDEVS; j++) {
  3226. if(j == d)
  3227. continue;
  3228. if(papCommonDevice[j]->Device == UNUSED_DEVICE)
  3229. continue;
  3230. if(papCommonDevice[j]->PreferredDevice != d)
  3231. continue;
  3232. if(p == MAXULONG) {
  3233. p = j;
  3234. }
  3235. papCommonDevice[j]->PreferredDevice = p;
  3236. }
  3237. }
  3238. switch(DeviceType)
  3239. {
  3240. case WaveOutDevice:
  3241. if ( pWdmaContext->WaveOutDevs[d].pTimer != NULL )
  3242. KeCancelTimer(pWdmaContext->WaveOutDevs[d].pTimer);
  3243. CleanupWavePins(&pWdmaContext->WaveOutDevs[d]);
  3244. AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].AudioDataRanges);
  3245. AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].pTimer);
  3246. AudioFreeMemory_Unknown(&pWdmaContext->WaveOutDevs[d].pDpc);
  3247. break;
  3248. case WaveInDevice:
  3249. CleanupWavePins(&pWdmaContext->WaveInDevs[d]);
  3250. AudioFreeMemory_Unknown(&pWdmaContext->WaveInDevs[d].AudioDataRanges);
  3251. break;
  3252. case MidiOutDevice:
  3253. CloseMidiDevicePin(&pWdmaContext->MidiOutDevs[d]);
  3254. AudioFreeMemory_Unknown(&pWdmaContext->MidiOutDevs[d].MusicDataRanges);
  3255. break;
  3256. case MidiInDevice:
  3257. CloseMidiDevicePin(&pWdmaContext->MidiInDevs[d]);
  3258. AudioFreeMemory_Unknown(&pWdmaContext->MidiInDevs[d].MusicDataRanges);
  3259. break;
  3260. case MixerDevice:
  3261. kmxlDeInit(&pWdmaContext->MixerDevs[d]);
  3262. break;
  3263. }
  3264. AudioFreeMemory_Unknown(&papCommonDevice[d]->pwstrName);
  3265. AudioFreeMemory_Unknown(&papCommonDevice[d]->DeviceInterface);
  3266. AudioFreeMemory_Unknown(&papCommonDevice[d]->ComponentId);
  3267. papCommonDevice[d]->pwstrName = NULL;
  3268. papCommonDevice[d]->DeviceInterface = NULL;
  3269. papCommonDevice[d]->Device = UNUSED_DEVICE;
  3270. }
  3271. pDevNodeListItem->cDevices[DeviceType] = MAXULONG;
  3272. pDevNodeListItem->fAdded[DeviceType] = FALSE;
  3273. ASSERT(pDevNodeListItem->cReference > 0);
  3274. if(--pDevNodeListItem->cReference > 0) {
  3275. DPF( DL_TRACE|FA_SYSAUDIO, ("cReference is now %d", pDevNodeListItem->cReference));
  3276. break;
  3277. }
  3278. DPF( DL_TRACE|FA_SYSAUDIO, ("Freeing %08x", pDevNodeListItem));
  3279. RemoveEntryList(&pDevNodeListItem->Next);
  3280. pWdmaContext->DevNodeListCount--;
  3281. AudioFreeMemory_Unknown(&pDevNodeListItem->DeviceInterface);
  3282. AudioFreeMemory_Unknown(&pDevNodeListItem);
  3283. break;
  3284. }
  3285. }
  3286. }
  3287. VOID
  3288. SysaudioAddRemove(
  3289. PWDMACONTEXT pContext
  3290. )
  3291. {
  3292. PDEVNODE_LIST_ITEM pDevNodeListItem;
  3293. PLIST_ENTRY ple;
  3294. int t;
  3295. PAGED_CODE();
  3296. DPF( DL_TRACE|FA_SYSAUDIO, ("Entering"));
  3297. WdmaGrabMutex(pContext);
  3298. DPFASSERT(IsValidWdmaContext(pContext));
  3299. if(pContext->SysaudioWorkerObject != NULL) {
  3300. for(ple = pContext->DevNodeListHead.Flink;
  3301. ple != &pContext->DevNodeListHead;
  3302. ple = ple->Flink) {
  3303. pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
  3304. for(t = 0; t < MAX_DEVICE_CLASS; t++) {
  3305. ProcessDevNodeListItem(pContext, pDevNodeListItem, t);
  3306. }
  3307. }
  3308. }
  3309. // Need this for to get more KS events
  3310. pContext->SysaudioWorkItem.List.Blink = NULL;
  3311. WdmaReleaseMutex(pContext);
  3312. DPF(DL_TRACE|FA_SYSAUDIO, ("Exiting"));
  3313. }
  3314. NTSTATUS
  3315. ProcessDevNodeListItem
  3316. (
  3317. PWDMACONTEXT pWdmaContext,
  3318. PDEVNODE_LIST_ITEM pDevNodeListItem,
  3319. ULONG DeviceType
  3320. )
  3321. {
  3322. NTSTATUS Status=STATUS_SUCCESS;
  3323. PAGED_CODE();
  3324. if(!pWdmaContext->fInitializeSysaudio) {
  3325. RETURN( STATUS_UNSUCCESSFUL );
  3326. }
  3327. if(!pDevNodeListItem->fAdded[DeviceType]) {
  3328. ASSERT(pDevNodeListItem->cDevices[DeviceType] == MAXULONG);
  3329. RETURN( Status );
  3330. }
  3331. DPF( DL_TRACE|FA_SYSAUDIO, ("%ls[%d]",
  3332. pDevNodeListItem->DeviceInterface,
  3333. DeviceType));
  3334. Status=InitializeGetNumDevs(
  3335. pWdmaContext,
  3336. DeviceType,
  3337. pDevNodeListItem->DeviceInterface,
  3338. &pDevNodeListItem->cDevices[DeviceType]);
  3339. if (!NT_SUCCESS(Status)) {
  3340. RETURN( Status );
  3341. }
  3342. if(DeviceType == MixerDevice &&
  3343. (pDevNodeListItem->fAdded[WaveOutDevice] ||
  3344. pDevNodeListItem->fAdded[WaveInDevice])) {
  3345. Status = kmxlInitializeMixer( pWdmaContext,
  3346. pDevNodeListItem->DeviceInterface,
  3347. pDevNodeListItem->cDevices[MixerDevice] );
  3348. if(NT_SUCCESS(Status) && pDevNodeListItem->cDevices[MixerDevice]) {
  3349. if(pDevNodeListItem->fAdded[WaveOutDevice]) {
  3350. FindVolumeControl(pWdmaContext, pDevNodeListItem->DeviceInterface, WaveOutDevice);
  3351. }
  3352. if(pDevNodeListItem->fAdded[MidiOutDevice]) {
  3353. FindVolumeControl(pWdmaContext, pDevNodeListItem->DeviceInterface, MidiOutDevice);
  3354. }
  3355. }
  3356. }
  3357. RETURN( Status );
  3358. }
  3359. #pragma LOCKED_CODE
  3360. NTSTATUS
  3361. QueueWorkList
  3362. (
  3363. PWDMACONTEXT pContext,
  3364. VOID (*Function)(
  3365. PVOID Reference1,
  3366. PVOID Reference2
  3367. ),
  3368. PVOID Reference1,
  3369. PVOID Reference2
  3370. )
  3371. {
  3372. NTSTATUS Status = STATUS_SUCCESS;
  3373. PWORK_LIST_ITEM pWorkListItem = NULL;
  3374. if(pContext->WorkListWorkerObject == NULL) {
  3375. ASSERT(NT_SUCCESS(Status));
  3376. goto exit;
  3377. }
  3378. Status = AudioAllocateMemory_Fixed(sizeof(WORK_LIST_ITEM),
  3379. TAG_AudE_EVENT,
  3380. ZERO_FILL_MEMORY,
  3381. &pWorkListItem);
  3382. if(!NT_SUCCESS(Status))
  3383. {
  3384. DPF( DL_TRACE|FA_SYSAUDIO, ("Failing QueueWorkList: %08x", Status));
  3385. goto exit;
  3386. }
  3387. pWorkListItem->Reference1 = Reference1;
  3388. pWorkListItem->Reference2 = Reference2;
  3389. pWorkListItem->Function = Function;
  3390. ExInterlockedInsertTailList(&pContext->WorkListHead,
  3391. &pWorkListItem->Next,
  3392. &pContext->WorkListSpinLock);
  3393. if(InterlockedIncrement(&pContext->cPendingWorkList) == 1) {
  3394. KsQueueWorkItem(pContext->WorkListWorkerObject, &pContext->WorkListWorkItem);
  3395. }
  3396. exit:
  3397. RETURN( Status );
  3398. }
  3399. VOID
  3400. WorkListWorker(
  3401. PVOID pReference
  3402. )
  3403. {
  3404. PWDMACONTEXT pContext = (PWDMACONTEXT)pReference;
  3405. PWORK_LIST_ITEM pWorkListItem;
  3406. PLIST_ENTRY ple;
  3407. ASSERT(pContext);
  3408. WdmaGrabMutex(pContext);
  3409. while((ple = ExInterlockedRemoveHeadList(
  3410. &pContext->WorkListHead,
  3411. &pContext->WorkListSpinLock)) != NULL)
  3412. {
  3413. pWorkListItem = CONTAINING_RECORD(ple, WORK_LIST_ITEM, Next);
  3414. (*pWorkListItem->Function)(pWorkListItem->Reference1,pWorkListItem->Reference2);
  3415. AudioFreeMemory(sizeof(sizeof(WORK_LIST_ITEM)),&pWorkListItem);
  3416. if(InterlockedDecrement(&pContext->cPendingWorkList) == 0) {
  3417. break;
  3418. }
  3419. }
  3420. WdmaReleaseMutex(pContext);
  3421. }
  3422. VOID
  3423. WdmaGrabMutex(
  3424. PWDMACONTEXT pWdmaContext
  3425. )
  3426. {
  3427. // KeWaitForMutexObject(&pWdmaContext->wdmaContextMutex, Executive, KernelMode, FALSE, NULL);
  3428. //
  3429. // Turn off the APCDisable flag in the thread structure before going for our
  3430. // mutex. This will prevent us from getting suspeneded while holding this
  3431. // mutex.
  3432. //
  3433. KeEnterCriticalRegion();
  3434. KeWaitForMutexObject(&wdmaMutex, Executive, KernelMode, FALSE, NULL);
  3435. }
  3436. VOID
  3437. WdmaReleaseMutex(
  3438. PWDMACONTEXT pWdmaContext
  3439. )
  3440. {
  3441. // KeReleaseMutex(&pWdmaContext->wdmaContextMutex, FALSE);
  3442. KeReleaseMutex(&wdmaMutex, FALSE);
  3443. KeLeaveCriticalRegion();
  3444. }
  3445. VOID WdmaContextCleanup(PWDMACONTEXT pWdmaContext)
  3446. {
  3447. LONG DeviceType;
  3448. LONG DeviceNumber;
  3449. PDEVNODE_LIST_ITEM pDevNodeListItem = NULL;
  3450. PLIST_ENTRY ple;
  3451. DPF( DL_TRACE|FA_SYSAUDIO, ("%08x", pWdmaContext));
  3452. for (DeviceType = 0; DeviceType < MAX_DEVICE_CLASS; DeviceType++)
  3453. {
  3454. for (DeviceNumber = 0; DeviceNumber < MAXNUMDEVS; DeviceNumber++)
  3455. {
  3456. PCOMMONDEVICE pDevice;
  3457. pDevice = pWdmaContext->apCommonDevice[DeviceType][DeviceNumber];
  3458. ASSERT(pDevice);
  3459. if (UNUSED_DEVICE != pDevice->Device)
  3460. {
  3461. LPWSTR DeviceInterface = NULL;
  3462. NTSTATUS Status;
  3463. ASSERT(pDevice->DeviceInterface);
  3464. if (pDevice->DeviceInterface) {
  3465. Status = AudioAllocateMemory_Paged((wcslen(pDevice->DeviceInterface)+1)*sizeof(WCHAR),
  3466. TAG_AudD_DEVICEINFO,
  3467. DEFAULT_MEMORY,
  3468. &DeviceInterface);
  3469. if (NT_SUCCESS(Status))
  3470. {
  3471. wcscpy( DeviceInterface, pDevice->DeviceInterface );
  3472. RemoveDevNode(pWdmaContext, DeviceInterface, DeviceType);
  3473. AudioFreeMemory_Unknown(&DeviceInterface);
  3474. }
  3475. }
  3476. }
  3477. }
  3478. }
  3479. //
  3480. // Cleanup any remaining devnode list items
  3481. //
  3482. while (!IsListEmpty(&pWdmaContext->DevNodeListHead))
  3483. {
  3484. ple = pWdmaContext->DevNodeListHead.Flink;
  3485. pDevNodeListItem = CONTAINING_RECORD(ple, DEVNODE_LIST_ITEM, Next);
  3486. DPF( DL_TRACE|FA_SYSAUDIO, ("Stray devnode list item = %08x", pDevNodeListItem));
  3487. RemoveHeadList(&pWdmaContext->DevNodeListHead);
  3488. pWdmaContext->DevNodeListCount--;
  3489. AudioFreeMemory_Unknown(&pDevNodeListItem->DeviceInterface);
  3490. AudioFreeMemory_Unknown(&pDevNodeListItem);
  3491. }
  3492. return;
  3493. }