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

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