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.

798 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved
  3. Module Name:
  4. minwave.cpp
  5. Abstract:
  6. Implementation of wavecyclic miniport.
  7. --*/
  8. #include <msvad.h>
  9. #include <common.h>
  10. #include "ac3.h"
  11. #include "minwave.h"
  12. #include "wavtable.h"
  13. #pragma code_seg("PAGE")
  14. //=============================================================================
  15. // CMiniportWaveCyclic
  16. //=============================================================================
  17. //=============================================================================
  18. NTSTATUS
  19. CreateMiniportWaveCyclicMSVAD
  20. (
  21. OUT PUNKNOWN * Unknown,
  22. IN REFCLSID,
  23. IN PUNKNOWN UnknownOuter OPTIONAL,
  24. IN POOL_TYPE PoolType
  25. )
  26. /*++
  27. Routine Description:
  28. Create the wavecyclic miniport.
  29. Arguments:
  30. Unknown -
  31. RefClsId -
  32. UnknownOuter -
  33. PoolType -
  34. Return Value:
  35. NT status code.
  36. --*/
  37. {
  38. PAGED_CODE();
  39. ASSERT(Unknown);
  40. STD_CREATE_BODY(CMiniportWaveCyclic, Unknown, UnknownOuter, PoolType);
  41. }
  42. //=============================================================================
  43. CMiniportWaveCyclic::~CMiniportWaveCyclic
  44. (
  45. void
  46. )
  47. /*++
  48. Routine Description:
  49. Destructor for wavecyclic miniport
  50. Arguments:
  51. Return Value:
  52. NT status code.
  53. --*/
  54. {
  55. PAGED_CODE();
  56. DPF_ENTER(("[CMiniportWaveCyclic::~CMiniportWaveCyclic]"));
  57. } // ~CMiniportWaveCyclic
  58. //=============================================================================
  59. STDMETHODIMP_(NTSTATUS)
  60. CMiniportWaveCyclic::DataRangeIntersection
  61. (
  62. IN ULONG PinId,
  63. IN PKSDATARANGE ClientDataRange,
  64. IN PKSDATARANGE MyDataRange,
  65. IN ULONG OutputBufferLength,
  66. OUT PVOID ResultantFormat,
  67. OUT PULONG ResultantFormatLength
  68. )
  69. /*++
  70. Routine Description:
  71. The DataRangeIntersection function determines the highest quality
  72. intersection of two data ranges.
  73. Arguments:
  74. PinId - Pin for which data intersection is being determined.
  75. ClientDataRange - Pointer to KSDATARANGE structure which contains the data
  76. range submitted by client in the data range intersection
  77. property request.
  78. MyDataRange - Pin's data range to be compared with client's data
  79. range. In this case we actually ignore our own data
  80. range, because we know that we only support one range.
  81. OutputBufferLength - Size of the buffer pointed to by the resultant format
  82. parameter.
  83. ResultantFormat - Pointer to value where the resultant format should be
  84. returned.
  85. ResultantFormatLength - Actual length of the resultant format placed in
  86. ResultantFormat. This should be less than or equal
  87. to OutputBufferLength.
  88. Return Value:
  89. NT status code.
  90. --*/
  91. {
  92. PAGED_CODE();
  93. // For all other pins, let PortCls handle the request (PCM only).
  94. //
  95. if (KSPIN_WAVE_AC3_RENDER_SINK != PinId)
  96. {
  97. return STATUS_NOT_IMPLEMENTED;
  98. }
  99. // The client's DataRange should be AC3.
  100. // Otherwise, there is no intersection.
  101. //
  102. if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat,
  103. KSDATAFORMAT_TYPE_AUDIO) &&
  104. !IsEqualGUIDAligned(ClientDataRange->MajorFormat,
  105. KSDATAFORMAT_TYPE_WILDCARD))
  106. {
  107. return STATUS_NO_MATCH;
  108. }
  109. if (!IsEqualGUIDAligned(ClientDataRange->SubFormat,
  110. KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF) &&
  111. !IsEqualGUIDAligned(ClientDataRange->SubFormat,
  112. KSDATAFORMAT_SUBTYPE_WILDCARD))
  113. {
  114. return STATUS_NO_MATCH;
  115. }
  116. if (IsEqualGUIDAligned(ClientDataRange->Specifier,
  117. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
  118. IsEqualGUIDAligned(ClientDataRange->Specifier,
  119. KSDATAFORMAT_SPECIFIER_WILDCARD))
  120. {
  121. *ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
  122. }
  123. else if (IsEqualGUIDAligned(ClientDataRange->Specifier,
  124. KSDATAFORMAT_SPECIFIER_DSOUND))
  125. {
  126. *ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);
  127. }
  128. else
  129. {
  130. return STATUS_NO_MATCH;
  131. }
  132. // Validate return buffer size, if the request is only for the
  133. // size of the resultant structure, return it now.
  134. //
  135. if (!OutputBufferLength)
  136. {
  137. *ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);
  138. return STATUS_BUFFER_OVERFLOW;
  139. }
  140. else if (OutputBufferLength < sizeof(KSDATAFORMAT_WAVEFORMATEX))
  141. {
  142. return STATUS_BUFFER_TOO_SMALL;
  143. }
  144. PKSDATAFORMAT_WAVEFORMATEX resultantFormatWFX;
  145. PWAVEFORMATEX pWaveFormatEx;
  146. resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
  147. // Return the best (only) available format.
  148. //
  149. resultantFormatWFX->DataFormat.FormatSize = *ResultantFormatLength;
  150. resultantFormatWFX->DataFormat.Flags = 0;
  151. resultantFormatWFX->DataFormat.SampleSize = 4; // must match nBlockAlign
  152. resultantFormatWFX->DataFormat.Reserved = 0;
  153. resultantFormatWFX->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
  154. INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat,
  155. WAVE_FORMAT_DOLBY_AC3_SPDIF );
  156. // Extra space for the DSound specifier
  157. //
  158. if (IsEqualGUIDAligned(ClientDataRange->Specifier,
  159. KSDATAFORMAT_SPECIFIER_DSOUND))
  160. {
  161. PKSDATAFORMAT_DSOUND resultantFormatDSound;
  162. resultantFormatDSound = (PKSDATAFORMAT_DSOUND) ResultantFormat;
  163. resultantFormatDSound->DataFormat.Specifier =
  164. KSDATAFORMAT_SPECIFIER_DSOUND;
  165. // DSound format capabilities are not expressed
  166. // this way in KS, so we express no capabilities.
  167. //
  168. resultantFormatDSound->BufferDesc.Flags = 0 ;
  169. resultantFormatDSound->BufferDesc.Control = 0 ;
  170. pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;
  171. }
  172. else // WAVEFORMATEX or WILDCARD (WAVEFORMATEX)
  173. {
  174. resultantFormatWFX->DataFormat.Specifier =
  175. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
  176. pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)resultantFormatWFX + 1);
  177. }
  178. pWaveFormatEx->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
  179. pWaveFormatEx->nChannels = 2;
  180. pWaveFormatEx->nSamplesPerSec = 48000;
  181. pWaveFormatEx->wBitsPerSample = 16;
  182. pWaveFormatEx->cbSize = 0;
  183. pWaveFormatEx->nBlockAlign =
  184. pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample / 8;
  185. pWaveFormatEx->nAvgBytesPerSec =
  186. pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;
  187. return STATUS_SUCCESS;
  188. } // DataRangeIntersection
  189. //=============================================================================
  190. STDMETHODIMP_(NTSTATUS)
  191. CMiniportWaveCyclic::GetDescription
  192. (
  193. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  194. )
  195. /*++
  196. Routine Description:
  197. The GetDescription function gets a pointer to a filter description.
  198. It provides a location to deposit a pointer in miniport's description
  199. structure. This is the placeholder for the FromNode or ToNode fields in
  200. connections which describe connections to the filter's pins.
  201. Arguments:
  202. OutFilterDescriptor - Pointer to the filter description.
  203. Return Value:
  204. NT status code.
  205. --*/
  206. {
  207. PAGED_CODE();
  208. ASSERT(OutFilterDescriptor);
  209. return
  210. CMiniportWaveCyclicMSVAD::GetDescription(OutFilterDescriptor);
  211. } // GetDescription
  212. //=============================================================================
  213. STDMETHODIMP_(NTSTATUS)
  214. CMiniportWaveCyclic::Init
  215. (
  216. IN PUNKNOWN UnknownAdapter_,
  217. IN PRESOURCELIST ResourceList_,
  218. IN PPORTWAVECYCLIC Port_
  219. )
  220. /*++
  221. Routine Description:
  222. The Init function initializes the miniport. Callers of this function
  223. should run at IRQL PASSIVE_LEVEL
  224. Arguments:
  225. UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
  226. ResourceList - Pointer to the resource list to be supplied to the miniport
  227. during initialization. The port driver is free to examine the
  228. contents of the ResourceList. The port driver will not be
  229. modify the ResourceList contents.
  230. Port - Pointer to the topology port object that is linked with this miniport.
  231. Return Value:
  232. NT status code.
  233. --*/
  234. {
  235. PAGED_CODE();
  236. ASSERT(UnknownAdapter_);
  237. ASSERT(Port_);
  238. NTSTATUS ntStatus;
  239. DPF_ENTER(("[CMiniportWaveCyclic::Init]"));
  240. m_MaxOutputStreams = MAX_OUTPUT_STREAMS;
  241. m_MaxInputStreams = MAX_INPUT_STREAMS;
  242. m_MaxTotalStreams = MAX_TOTAL_STREAMS;
  243. m_MinChannels = MIN_CHANNELS;
  244. m_MaxChannelsPcm = MAX_CHANNELS_PCM;
  245. m_MinBitsPerSamplePcm = MIN_BITS_PER_SAMPLE_PCM;
  246. m_MaxBitsPerSamplePcm = MAX_BITS_PER_SAMPLE_PCM;
  247. m_MinSampleRatePcm = MIN_SAMPLE_RATE;
  248. m_MaxSampleRatePcm = MAX_SAMPLE_RATE;
  249. ntStatus =
  250. CMiniportWaveCyclicMSVAD::Init
  251. (
  252. UnknownAdapter_,
  253. ResourceList_,
  254. Port_
  255. );
  256. if (NT_SUCCESS(ntStatus))
  257. {
  258. // Set filter descriptor.
  259. m_FilterDescriptor = &MiniportFilterDescriptor;
  260. m_fCaptureAllocated = FALSE;
  261. m_fPcmRenderAllocated = FALSE;
  262. m_fAc3RenderAllocated = FALSE;
  263. }
  264. return ntStatus;
  265. } // Init
  266. //=============================================================================
  267. STDMETHODIMP_(NTSTATUS)
  268. CMiniportWaveCyclic::NewStream
  269. (
  270. OUT PMINIPORTWAVECYCLICSTREAM * OutStream,
  271. IN PUNKNOWN OuterUnknown,
  272. IN POOL_TYPE PoolType,
  273. IN ULONG Pin,
  274. IN BOOLEAN Capture,
  275. IN PKSDATAFORMAT DataFormat,
  276. OUT PDMACHANNEL * OutDmaChannel,
  277. OUT PSERVICEGROUP * OutServiceGroup
  278. )
  279. /*++
  280. Routine Description:
  281. The NewStream function creates a new instance of a logical stream
  282. associated with a specified physical channel. Callers of NewStream should
  283. run at IRQL PASSIVE_LEVEL.
  284. Arguments:
  285. OutStream -
  286. OuterUnknown -
  287. PoolType -
  288. Pin -
  289. Capture -
  290. DataFormat -
  291. OutDmaChannel -
  292. OutServiceGroup -
  293. Return Value:
  294. NT status code.
  295. --*/
  296. {
  297. PAGED_CODE();
  298. ASSERT(OutStream);
  299. ASSERT(DataFormat);
  300. ASSERT(OutDmaChannel);
  301. ASSERT(OutServiceGroup);
  302. DPF_ENTER(("[CMiniportWaveCyclic::NewStream]"));
  303. NTSTATUS ntStatus = STATUS_SUCCESS;
  304. PCMiniportWaveCyclicStream stream = NULL;
  305. // Determine if the format is valid.
  306. //
  307. if (NT_SUCCESS(ntStatus))
  308. {
  309. ntStatus = ValidateFormat(DataFormat);
  310. }
  311. // Check if we have enough streams.
  312. if (Capture)
  313. {
  314. if (m_fCaptureAllocated)
  315. {
  316. DPF(D_TERSE, ("[Only one capture stream supported]"));
  317. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  318. }
  319. }
  320. else
  321. {
  322. if (m_fAc3RenderAllocated && IsFormatAc3(DataFormat))
  323. {
  324. DPF(D_TERSE, ("[Only one Ac3 render stream supported]"));
  325. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  326. }
  327. if (m_fPcmRenderAllocated && !IsFormatAc3(DataFormat))
  328. {
  329. DPF(D_TERSE, ("[Only one Pcm render stream supported]"));
  330. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  331. }
  332. }
  333. // Instantiate a stream. Stream must be in
  334. // NonPagedPool because of file saving.
  335. //
  336. if (NT_SUCCESS(ntStatus))
  337. {
  338. stream = new (NonPagedPool, MSVAD_POOLTAG)
  339. CMiniportWaveCyclicStream(OuterUnknown);
  340. if (stream)
  341. {
  342. stream->AddRef();
  343. ntStatus =
  344. stream->Init
  345. (
  346. this,
  347. Pin,
  348. Capture,
  349. DataFormat
  350. );
  351. }
  352. else
  353. {
  354. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  355. }
  356. }
  357. if (NT_SUCCESS(ntStatus))
  358. {
  359. if (Capture)
  360. {
  361. m_fCaptureAllocated = TRUE;
  362. }
  363. else
  364. {
  365. if (IsFormatAc3(DataFormat))
  366. {
  367. m_fAc3RenderAllocated = TRUE;
  368. }
  369. else
  370. {
  371. m_fPcmRenderAllocated = TRUE;
  372. }
  373. }
  374. *OutStream = PMINIPORTWAVECYCLICSTREAM(stream);
  375. (*OutStream)->AddRef();
  376. *OutDmaChannel = PDMACHANNEL(stream);
  377. (*OutDmaChannel)->AddRef();
  378. *OutServiceGroup = m_ServiceGroup;
  379. (*OutServiceGroup)->AddRef();
  380. // The stream, the DMA channel, and the service group have
  381. // references now for the caller. The caller expects these
  382. // references to be there.
  383. }
  384. // This is our private reference to the stream. The caller has
  385. // its own, so we can release in any case.
  386. //
  387. if (stream)
  388. {
  389. stream->Release();
  390. }
  391. return ntStatus;
  392. } // NewStream
  393. //=============================================================================
  394. STDMETHODIMP_(NTSTATUS)
  395. CMiniportWaveCyclic::NonDelegatingQueryInterface
  396. (
  397. IN REFIID Interface,
  398. OUT PVOID * Object
  399. )
  400. /*++
  401. Routine Description:
  402. QueryInterface
  403. Arguments:
  404. Interface - GUID
  405. Object - interface pointer to be returned.
  406. Return Value:
  407. NT status code.
  408. --*/
  409. {
  410. PAGED_CODE();
  411. ASSERT(Object);
  412. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  413. {
  414. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
  415. }
  416. else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
  417. {
  418. *Object = PVOID(PMINIPORT(this));
  419. }
  420. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclic))
  421. {
  422. *Object = PVOID(PMINIPORTWAVECYCLIC(this));
  423. }
  424. else
  425. {
  426. *Object = NULL;
  427. }
  428. if (*Object)
  429. {
  430. // We reference the interface for the caller.
  431. PUNKNOWN(*Object)->AddRef();
  432. return STATUS_SUCCESS;
  433. }
  434. return STATUS_INVALID_PARAMETER;
  435. } // NonDelegatingQueryInterface
  436. //=============================================================================
  437. NTSTATUS
  438. CMiniportWaveCyclic::ValidateFormat
  439. (
  440. IN PKSDATAFORMAT pDataFormat
  441. )
  442. /*++
  443. Routine Description:
  444. Validates that the given dataformat is valid. This overwrites BaseWave's
  445. ValidateFormat and includes checks for AC3 format.
  446. Arguments:
  447. pDataFormat - The dataformat for validation.
  448. Return Value:
  449. NT status code.
  450. --*/
  451. {
  452. PAGED_CODE();
  453. DPF_ENTER(("[CMiniportWaveCyclic::ValidateFormat]"));
  454. NTSTATUS ntStatus;
  455. ntStatus = CMiniportWaveCyclicMSVAD::ValidateFormat(pDataFormat);
  456. if (!NT_SUCCESS(ntStatus))
  457. {
  458. PWAVEFORMATEX pwfx;
  459. pwfx = GetWaveFormatEx(pDataFormat);
  460. if (pwfx)
  461. {
  462. if (IS_VALID_WAVEFORMATEX_GUID(&pDataFormat->SubFormat))
  463. {
  464. USHORT wfxID = EXTRACT_WAVEFORMATEX_ID(&pDataFormat->SubFormat);
  465. switch (wfxID)
  466. {
  467. case WAVE_FORMAT_DOLBY_AC3_SPDIF:
  468. {
  469. if
  470. (
  471. (pDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX)) &&
  472. (pwfx->cbSize == 0) &&
  473. (pwfx->nChannels <= MAX_CHANNELS_AC3 ) &&
  474. (pwfx->wBitsPerSample >= MIN_BITS_PER_SAMPLE_AC3)&&
  475. (pwfx->wBitsPerSample <= MAX_BITS_PER_SAMPLE_AC3)&&
  476. (pwfx->nSamplesPerSec >= MIN_SAMPLE_RATE_AC3) &&
  477. (pwfx->nSamplesPerSec <= MAX_SAMPLE_RATE_AC3)
  478. )
  479. {
  480. ntStatus = STATUS_SUCCESS;
  481. }
  482. else
  483. {
  484. DPF(D_TERSE, ("Invalid WAVE_FORMAT_DOLBY_AC3_SPDIF format"));
  485. }
  486. break;
  487. }
  488. }
  489. }
  490. else
  491. {
  492. DPF(D_TERSE, ("Invalid pDataFormat->SubFormat!") );
  493. }
  494. }
  495. }
  496. return ntStatus;
  497. } // ValidateFormat
  498. //=============================================================================
  499. // CMiniportWaveStreamCyclicSimple
  500. //=============================================================================
  501. //=============================================================================
  502. CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream
  503. (
  504. void
  505. )
  506. /*++
  507. Routine Description:
  508. Destructor for wavecyclicstream
  509. Arguments:
  510. Return Value:
  511. NT status code.
  512. --*/
  513. {
  514. PAGED_CODE();
  515. DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
  516. if (NULL != m_pMiniportLocal)
  517. {
  518. if (m_fCapture)
  519. {
  520. m_pMiniportLocal->m_fCaptureAllocated = FALSE;
  521. }
  522. else
  523. {
  524. if (m_fFormatAc3)
  525. {
  526. m_pMiniportLocal->m_fAc3RenderAllocated = FALSE;
  527. }
  528. else
  529. {
  530. m_pMiniportLocal->m_fPcmRenderAllocated = FALSE;
  531. }
  532. }
  533. }
  534. } // ~CMiniportWaveCyclicStream
  535. //=============================================================================
  536. NTSTATUS
  537. CMiniportWaveCyclicStream::Init
  538. (
  539. IN PCMiniportWaveCyclic Miniport_,
  540. IN ULONG Pin_,
  541. IN BOOLEAN Capture_,
  542. IN PKSDATAFORMAT DataFormat_
  543. )
  544. /*++
  545. Routine Description:
  546. Initializes the stream object. Allocate a DMA buffer, timer and DPC
  547. Arguments:
  548. Miniport_ -
  549. Pin_ -
  550. Capture_ -
  551. DataFormat -
  552. DmaChannel_ -
  553. Return Value:
  554. NT status code.
  555. --*/
  556. {
  557. PAGED_CODE();
  558. m_pMiniportLocal = Miniport_;
  559. m_fFormatAc3 = IsFormatAc3(DataFormat_);
  560. return
  561. CMiniportWaveCyclicStreamMSVAD::Init
  562. (
  563. Miniport_,
  564. Pin_,
  565. Capture_,
  566. DataFormat_
  567. );
  568. } // Init
  569. //=============================================================================
  570. STDMETHODIMP_(NTSTATUS)
  571. CMiniportWaveCyclicStream::NonDelegatingQueryInterface
  572. (
  573. IN REFIID Interface,
  574. OUT PVOID * Object
  575. )
  576. /*++
  577. Routine Description:
  578. QueryInterface
  579. Arguments:
  580. Interface - GUID
  581. Object - interface pointer to be returned
  582. Return Value:
  583. NT status code.
  584. --*/
  585. {
  586. PAGED_CODE();
  587. ASSERT(Object);
  588. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  589. {
  590. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
  591. }
  592. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream))
  593. {
  594. *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
  595. }
  596. else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel))
  597. {
  598. *Object = PVOID(PDMACHANNEL(this));
  599. }
  600. else
  601. {
  602. *Object = NULL;
  603. }
  604. if (*Object)
  605. {
  606. PUNKNOWN(*Object)->AddRef();
  607. return STATUS_SUCCESS;
  608. }
  609. return STATUS_INVALID_PARAMETER;
  610. } // NonDelegatingQueryInterface
  611. #pragma code_seg()