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.

780 lines
17 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 "pcmex.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. // This code is the same as AC97 sample intersection handler.
  94. //
  95. // Check the size of output buffer. Note that we are returning
  96. // WAVEFORMATPCMEX.
  97. //
  98. if (!OutputBufferLength)
  99. {
  100. *ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
  101. return STATUS_BUFFER_OVERFLOW;
  102. }
  103. if (OutputBufferLength < (sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX)))
  104. {
  105. return STATUS_BUFFER_TOO_SMALL;
  106. }
  107. // Fill in the structure the datarange structure.
  108. //
  109. RtlCopyMemory(ResultantFormat, MyDataRange, sizeof(KSDATAFORMAT));
  110. // Modify the size of the data format structure to fit the WAVEFORMATPCMEX
  111. // structure.
  112. //
  113. ((PKSDATAFORMAT)ResultantFormat)->FormatSize =
  114. sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
  115. // Append the WAVEFORMATPCMEX structure
  116. //
  117. PWAVEFORMATPCMEX pWfxExt =
  118. (PWAVEFORMATPCMEX)((PKSDATAFORMAT)ResultantFormat + 1);
  119. pWfxExt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  120. pWfxExt->Format.nChannels =
  121. (WORD)((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumChannels;
  122. pWfxExt->Format.nSamplesPerSec =
  123. ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumSampleFrequency;
  124. pWfxExt->Format.wBitsPerSample = (WORD)
  125. ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumBitsPerSample;
  126. pWfxExt->Format.nBlockAlign =
  127. (pWfxExt->Format.wBitsPerSample * pWfxExt->Format.nChannels) / 8;
  128. pWfxExt->Format.nAvgBytesPerSec =
  129. pWfxExt->Format.nSamplesPerSec * pWfxExt->Format.nBlockAlign;
  130. pWfxExt->Format.cbSize = 22;
  131. pWfxExt->Samples.wValidBitsPerSample = pWfxExt->Format.wBitsPerSample;
  132. pWfxExt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  133. // This should be set to wave port's channel config
  134. // MSVAD ds3dhw implements this properly.
  135. //
  136. pWfxExt->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
  137. // Now overwrite also the sample size in the ksdataformat structure.
  138. ((PKSDATAFORMAT)ResultantFormat)->SampleSize = pWfxExt->Format.nBlockAlign;
  139. // That we will return.
  140. //
  141. *ResultantFormatLength = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATPCMEX);
  142. return STATUS_SUCCESS;
  143. } // DataRangeIntersection
  144. //=============================================================================
  145. STDMETHODIMP_(NTSTATUS)
  146. CMiniportWaveCyclic::GetDescription
  147. (
  148. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  149. )
  150. /*++
  151. Routine Description:
  152. The GetDescription function gets a pointer to a filter description.
  153. It provides a location to deposit a pointer in miniport's description
  154. structure. This is the placeholder for the FromNode or ToNode fields in
  155. connections which describe connections to the filter's pins.
  156. Arguments:
  157. OutFilterDescriptor - Pointer to the filter description.
  158. Return Value:
  159. NT status code.
  160. --*/
  161. {
  162. PAGED_CODE();
  163. ASSERT(OutFilterDescriptor);
  164. return
  165. CMiniportWaveCyclicMSVAD::GetDescription(OutFilterDescriptor);
  166. } // GetDescription
  167. //=============================================================================
  168. STDMETHODIMP_(NTSTATUS)
  169. CMiniportWaveCyclic::Init
  170. (
  171. IN PUNKNOWN UnknownAdapter_,
  172. IN PRESOURCELIST ResourceList_,
  173. IN PPORTWAVECYCLIC Port_
  174. )
  175. /*++
  176. Routine Description:
  177. The Init function initializes the miniport. Callers of this function
  178. should run at IRQL PASSIVE_LEVEL
  179. Arguments:
  180. UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
  181. ResourceList - Pointer to the resource list to be supplied to the miniport
  182. during initialization. The port driver is free to examine the
  183. contents of the ResourceList. The port driver will not be
  184. modify the ResourceList contents.
  185. Port - Pointer to the topology port object that is linked with this miniport.
  186. Return Value:
  187. NT status code.
  188. --*/
  189. {
  190. PAGED_CODE();
  191. ASSERT(UnknownAdapter_);
  192. ASSERT(Port_);
  193. NTSTATUS ntStatus;
  194. DPF_ENTER(("[CMiniportWaveCyclic::Init]"));
  195. m_MaxOutputStreams = MAX_OUTPUT_STREAMS;
  196. m_MaxInputStreams = MAX_INPUT_STREAMS;
  197. m_MaxTotalStreams = MAX_TOTAL_STREAMS;
  198. m_MinChannels = MIN_CHANNELS;
  199. m_MaxChannelsPcm = MAX_CHANNELS_PCM;
  200. m_MinBitsPerSamplePcm = MIN_BITS_PER_SAMPLE_PCM;
  201. m_MaxBitsPerSamplePcm = MAX_BITS_PER_SAMPLE_PCM;
  202. m_MinSampleRatePcm = MIN_SAMPLE_RATE;
  203. m_MaxSampleRatePcm = MAX_SAMPLE_RATE;
  204. ntStatus =
  205. CMiniportWaveCyclicMSVAD::Init
  206. (
  207. UnknownAdapter_,
  208. ResourceList_,
  209. Port_
  210. );
  211. if (NT_SUCCESS(ntStatus))
  212. {
  213. // Set filter descriptor.
  214. m_FilterDescriptor = &MiniportFilterDescriptor;
  215. m_fCaptureAllocated = FALSE;
  216. m_fRenderAllocated = FALSE;
  217. }
  218. return ntStatus;
  219. } // Init
  220. //=============================================================================
  221. STDMETHODIMP_(NTSTATUS)
  222. CMiniportWaveCyclic::NewStream
  223. (
  224. OUT PMINIPORTWAVECYCLICSTREAM * OutStream,
  225. IN PUNKNOWN OuterUnknown,
  226. IN POOL_TYPE PoolType,
  227. IN ULONG Pin,
  228. IN BOOLEAN Capture,
  229. IN PKSDATAFORMAT DataFormat,
  230. OUT PDMACHANNEL * OutDmaChannel,
  231. OUT PSERVICEGROUP * OutServiceGroup
  232. )
  233. /*++
  234. Routine Description:
  235. The NewStream function creates a new instance of a logical stream
  236. associated with a specified physical channel. Callers of NewStream should
  237. run at IRQL PASSIVE_LEVEL.
  238. Arguments:
  239. OutStream -
  240. OuterUnknown -
  241. PoolType -
  242. Pin -
  243. Capture -
  244. DataFormat -
  245. OutDmaChannel -
  246. OutServiceGroup -
  247. Return Value:
  248. NT status code.
  249. --*/
  250. {
  251. PAGED_CODE();
  252. ASSERT(OutStream);
  253. ASSERT(DataFormat);
  254. ASSERT(OutDmaChannel);
  255. ASSERT(OutServiceGroup);
  256. DPF_ENTER(("[CMiniportWaveCyclic::NewStream]"));
  257. NTSTATUS ntStatus = STATUS_SUCCESS;
  258. PCMiniportWaveCyclicStream stream = NULL;
  259. // Check if we have enough streams.
  260. if (Capture)
  261. {
  262. if (m_fCaptureAllocated)
  263. {
  264. DPF(D_TERSE, ("[Only one capture stream supported]"));
  265. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  266. }
  267. }
  268. else
  269. {
  270. if (m_fRenderAllocated)
  271. {
  272. DPF(D_TERSE, ("[Only one render stream supported]"));
  273. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  274. }
  275. }
  276. // Determine if the format is valid.
  277. //
  278. if (NT_SUCCESS(ntStatus))
  279. {
  280. ntStatus = ValidateFormat(DataFormat);
  281. }
  282. // Instantiate a stream. Stream must be in
  283. // NonPagedPool because of file saving.
  284. //
  285. if (NT_SUCCESS(ntStatus))
  286. {
  287. stream = new (NonPagedPool, MSVAD_POOLTAG)
  288. CMiniportWaveCyclicStream(OuterUnknown);
  289. if (stream)
  290. {
  291. stream->AddRef();
  292. ntStatus =
  293. stream->Init
  294. (
  295. this,
  296. Pin,
  297. Capture,
  298. DataFormat
  299. );
  300. }
  301. else
  302. {
  303. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  304. }
  305. }
  306. if (NT_SUCCESS(ntStatus))
  307. {
  308. if (Capture)
  309. {
  310. m_fCaptureAllocated = TRUE;
  311. }
  312. else
  313. {
  314. m_fRenderAllocated = TRUE;
  315. }
  316. *OutStream = PMINIPORTWAVECYCLICSTREAM(stream);
  317. (*OutStream)->AddRef();
  318. *OutDmaChannel = PDMACHANNEL(stream);
  319. (*OutDmaChannel)->AddRef();
  320. *OutServiceGroup = m_ServiceGroup;
  321. (*OutServiceGroup)->AddRef();
  322. // The stream, the DMA channel, and the service group have
  323. // references now for the caller. The caller expects these
  324. // references to be there.
  325. }
  326. // This is our private reference to the stream. The caller has
  327. // its own, so we can release in any case.
  328. //
  329. if (stream)
  330. {
  331. stream->Release();
  332. }
  333. return ntStatus;
  334. } // NewStream
  335. //=============================================================================
  336. STDMETHODIMP_(NTSTATUS)
  337. CMiniportWaveCyclic::NonDelegatingQueryInterface
  338. (
  339. IN REFIID Interface,
  340. OUT PVOID * Object
  341. )
  342. /*++
  343. Routine Description:
  344. QueryInterface
  345. Arguments:
  346. Interface - GUID
  347. Object - interface pointer to be returned.
  348. Return Value:
  349. NT status code.
  350. --*/
  351. {
  352. PAGED_CODE();
  353. ASSERT(Object);
  354. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  355. {
  356. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
  357. }
  358. else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
  359. {
  360. *Object = PVOID(PMINIPORT(this));
  361. }
  362. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclic))
  363. {
  364. *Object = PVOID(PMINIPORTWAVECYCLIC(this));
  365. }
  366. else
  367. {
  368. *Object = NULL;
  369. }
  370. if (*Object)
  371. {
  372. // We reference the interface for the caller.
  373. PUNKNOWN(*Object)->AddRef();
  374. return STATUS_SUCCESS;
  375. }
  376. return STATUS_INVALID_PARAMETER;
  377. } // NonDelegatingQueryInterface
  378. //=============================================================================
  379. NTSTATUS
  380. CMiniportWaveCyclic::ValidateFormat
  381. (
  382. IN PKSDATAFORMAT pDataFormat
  383. )
  384. /*++
  385. Routine Description:
  386. Validates that the given dataformat is valid. This is for supporting
  387. WAVEFORMATEXTENSIBLE.
  388. Arguments:
  389. pDataFormat - The dataformat for validation.
  390. Return Value:
  391. NT status code.
  392. --*/
  393. {
  394. PAGED_CODE();
  395. ASSERT(pDataFormat);
  396. DPF_ENTER(("[CMiniportWaveCyclicMSVAD::ValidateFormat]"));
  397. NTSTATUS ntStatus;
  398. PWAVEFORMATEX pwfx;
  399. // Let the default Validator handle the request.
  400. //
  401. ntStatus = CMiniportWaveCyclicMSVAD::ValidateFormat(pDataFormat);
  402. if (NT_SUCCESS(ntStatus))
  403. {
  404. return ntStatus;
  405. }
  406. // If the format is not known check for WAVEFORMATEXTENSIBLE.
  407. //
  408. pwfx = GetWaveFormatEx(pDataFormat);
  409. if (pwfx)
  410. {
  411. if (IS_VALID_WAVEFORMATEX_GUID(&pDataFormat->SubFormat))
  412. {
  413. USHORT wfxID = EXTRACT_WAVEFORMATEX_ID(&pDataFormat->SubFormat);
  414. switch (wfxID)
  415. {
  416. // This is for WAVE_FORMAT_EXTENSIBLE support.
  417. //
  418. case WAVE_FORMAT_EXTENSIBLE:
  419. {
  420. PWAVEFORMATEXTENSIBLE pwfxExt =
  421. (PWAVEFORMATEXTENSIBLE) pwfx;
  422. ntStatus = ValidateWfxExt(pwfxExt);
  423. break;
  424. }
  425. default:
  426. DPF(D_TERSE, ("Invalid format EXTRACT_WAVEFORMATEX_ID!"));
  427. break;
  428. }
  429. }
  430. else
  431. {
  432. DPF(D_TERSE, ("Invalid pDataFormat->SubFormat!") );
  433. }
  434. }
  435. return ntStatus;
  436. } // ValidateFormat
  437. //=============================================================================
  438. NTSTATUS
  439. CMiniportWaveCyclic::ValidateWfxExt
  440. (
  441. IN PWAVEFORMATEXTENSIBLE pWfxExt
  442. )
  443. /*++
  444. Routine Description:
  445. Given a waveformatextensible, verifies that the format is in device
  446. datarange.
  447. Arguments:
  448. pWfxExt - wave format extensible structure
  449. Return Value:
  450. NT status code.
  451. --*/
  452. {
  453. PAGED_CODE();
  454. DPF_ENTER(("[CMiniportWaveCyclic::ValidateWfxExtPcm]"));
  455. // First verify that the subformat is OK
  456. //
  457. if (pWfxExt)
  458. {
  459. if(IsEqualGUIDAligned(pWfxExt->SubFormat, KSDATAFORMAT_SUBTYPE_PCM))
  460. {
  461. PWAVEFORMATEX pWfx = (PWAVEFORMATEX) pWfxExt;
  462. if
  463. (
  464. pWfx->cbSize ==
  465. sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
  466. )
  467. {
  468. // Do any channel specific stuff here.
  469. //
  470. return CMiniportWaveCyclicMSVAD::ValidatePcm(pWfx);
  471. }
  472. }
  473. }
  474. DPF(D_TERSE, ("Invalid PCM format"));
  475. return STATUS_INVALID_PARAMETER;
  476. } // ValidateWfxExtPcm
  477. //=============================================================================
  478. // CMiniportWaveStreamCyclicSimple
  479. //=============================================================================
  480. //=============================================================================
  481. CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream
  482. (
  483. void
  484. )
  485. /*++
  486. Routine Description:
  487. Destructor for wavecyclicstream
  488. Arguments:
  489. Return Value:
  490. NT status code.
  491. --*/
  492. {
  493. PAGED_CODE();
  494. DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
  495. if (NULL != m_pMiniportLocal)
  496. {
  497. if (m_fCapture)
  498. {
  499. m_pMiniportLocal->m_fCaptureAllocated = FALSE;
  500. }
  501. else
  502. {
  503. m_pMiniportLocal->m_fRenderAllocated = FALSE;
  504. }
  505. }
  506. } // ~CMiniportWaveCyclicStream
  507. //=============================================================================
  508. NTSTATUS
  509. CMiniportWaveCyclicStream::Init
  510. (
  511. IN PCMiniportWaveCyclic Miniport_,
  512. IN ULONG Pin_,
  513. IN BOOLEAN Capture_,
  514. IN PKSDATAFORMAT DataFormat_
  515. )
  516. /*++
  517. Routine Description:
  518. Initializes the stream object. Allocate a DMA buffer, timer and DPC
  519. Arguments:
  520. Miniport_ -
  521. Pin_ -
  522. Capture_ -
  523. DataFormat -
  524. DmaChannel_ -
  525. Return Value:
  526. NT status code.
  527. --*/
  528. {
  529. PAGED_CODE();
  530. m_pMiniportLocal = Miniport_;
  531. return
  532. CMiniportWaveCyclicStreamMSVAD::Init
  533. (
  534. Miniport_,
  535. Pin_,
  536. Capture_,
  537. DataFormat_
  538. );
  539. } // Init
  540. //=============================================================================
  541. STDMETHODIMP_(NTSTATUS)
  542. CMiniportWaveCyclicStream::NonDelegatingQueryInterface
  543. (
  544. IN REFIID Interface,
  545. OUT PVOID * Object
  546. )
  547. /*++
  548. Routine Description:
  549. QueryInterface
  550. Arguments:
  551. Interface - GUID
  552. Object - interface pointer to be returned
  553. Return Value:
  554. NT status code.
  555. --*/
  556. {
  557. PAGED_CODE();
  558. ASSERT(Object);
  559. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  560. {
  561. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
  562. }
  563. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream))
  564. {
  565. *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
  566. }
  567. else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel))
  568. {
  569. *Object = PVOID(PDMACHANNEL(this));
  570. }
  571. else
  572. {
  573. *Object = NULL;
  574. }
  575. if (*Object)
  576. {
  577. PUNKNOWN(*Object)->AddRef();
  578. return STATUS_SUCCESS;
  579. }
  580. return STATUS_INVALID_PARAMETER;
  581. } // NonDelegatingQueryInterface
  582. #pragma code_seg()