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.

797 lines
18 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 "drmmult.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. if (m_pDrmPort)
  57. {
  58. m_pDrmPort->Release();
  59. }
  60. DPF_ENTER(("[CMiniportWaveCyclic::~CMiniportWaveCyclic]"));
  61. } // ~CMiniportWaveCyclic
  62. //=============================================================================
  63. STDMETHODIMP_(NTSTATUS)
  64. CMiniportWaveCyclic::DataRangeIntersection
  65. (
  66. IN ULONG PinId,
  67. IN PKSDATARANGE ClientDataRange,
  68. IN PKSDATARANGE MyDataRange,
  69. IN ULONG OutputBufferLength,
  70. OUT PVOID ResultantFormat,
  71. OUT PULONG ResultantFormatLength
  72. )
  73. /*++
  74. Routine Description:
  75. The DataRangeIntersection function determines the highest quality
  76. intersection of two data ranges.
  77. Arguments:
  78. PinId - Pin for which data intersection is being determined.
  79. ClientDataRange - Pointer to KSDATARANGE structure which contains the data
  80. range submitted by client in the data range intersection
  81. property request.
  82. MyDataRange - Pin's data range to be compared with client's data
  83. range. In this case we actually ignore our own data
  84. range, because we know that we only support one range.
  85. OutputBufferLength - Size of the buffer pointed to by the resultant format
  86. parameter.
  87. ResultantFormat - Pointer to value where the resultant format should be
  88. returned.
  89. ResultantFormatLength - Actual length of the resultant format placed in
  90. ResultantFormat. This should be less than or equal
  91. to OutputBufferLength.
  92. Return Value:
  93. NT status code.
  94. --*/
  95. {
  96. PAGED_CODE();
  97. // This driver only supports PCM formats.
  98. // Portcls will handle the request for us.
  99. //
  100. return STATUS_NOT_IMPLEMENTED;
  101. } // DataRangeIntersection
  102. //=============================================================================
  103. STDMETHODIMP_(NTSTATUS)
  104. CMiniportWaveCyclic::GetDescription
  105. (
  106. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  107. )
  108. /*++
  109. Routine Description:
  110. The GetDescription function gets a pointer to a filter description.
  111. It provides a location to deposit a pointer in miniport's description
  112. structure. This is the placeholder for the FromNode or ToNode fields in
  113. connections which describe connections to the filter's pins.
  114. Arguments:
  115. OutFilterDescriptor - Pointer to the filter description.
  116. Return Value:
  117. NT status code.
  118. --*/
  119. {
  120. PAGED_CODE();
  121. ASSERT(OutFilterDescriptor);
  122. return
  123. CMiniportWaveCyclicMSVAD::GetDescription(OutFilterDescriptor);
  124. } // GetDescription
  125. //=============================================================================
  126. STDMETHODIMP_(NTSTATUS)
  127. CMiniportWaveCyclic::Init
  128. (
  129. IN PUNKNOWN UnknownAdapter_,
  130. IN PRESOURCELIST ResourceList_,
  131. IN PPORTWAVECYCLIC Port_
  132. )
  133. /*++
  134. Routine Description:
  135. The Init function initializes the miniport. Callers of this function
  136. should run at IRQL PASSIVE_LEVEL
  137. Arguments:
  138. UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
  139. ResourceList - Pointer to the resource list to be supplied to the miniport
  140. during initialization. The port driver is free to examine the
  141. contents of the ResourceList. The port driver will not be
  142. modify the ResourceList contents.
  143. Port - Pointer to the topology port object that is linked with this miniport.
  144. Return Value:
  145. NT status code.
  146. --*/
  147. {
  148. PAGED_CODE();
  149. ASSERT(UnknownAdapter_);
  150. ASSERT(Port_);
  151. NTSTATUS ntStatus;
  152. DPF_ENTER(("[CMiniportWaveCyclic::Init]"));
  153. m_MaxOutputStreams = MAX_OUTPUT_STREAMS;
  154. m_MaxInputStreams = MAX_INPUT_STREAMS;
  155. m_MaxTotalStreams = MAX_TOTAL_STREAMS;
  156. m_MinChannels = MIN_CHANNELS;
  157. m_MaxChannelsPcm = MAX_CHANNELS_PCM;
  158. m_MinBitsPerSamplePcm = MIN_BITS_PER_SAMPLE_PCM;
  159. m_MaxBitsPerSamplePcm = MAX_BITS_PER_SAMPLE_PCM;
  160. m_MinSampleRatePcm = MIN_SAMPLE_RATE;
  161. m_MaxSampleRatePcm = MAX_SAMPLE_RATE;
  162. m_ulMixDrmContentId = 0;
  163. RtlZeroMemory(&m_MixDrmRights, sizeof(m_MixDrmRights));
  164. ntStatus =
  165. CMiniportWaveCyclicMSVAD::Init
  166. (
  167. UnknownAdapter_,
  168. ResourceList_,
  169. Port_
  170. );
  171. if (NT_SUCCESS(ntStatus))
  172. {
  173. // Set filter descriptor.
  174. m_FilterDescriptor = &MiniportFilterDescriptor;
  175. m_fCaptureAllocated = FALSE;
  176. RtlZeroMemory
  177. (
  178. m_pStream,
  179. MAX_INPUT_STREAMS * sizeof(PCMiniportWaveCyclicStream)
  180. );
  181. if (!NT_SUCCESS(
  182. Port_->QueryInterface(IID_IDrmPort, (PVOID *) &m_pDrmPort)))
  183. {
  184. m_pDrmPort = NULL;
  185. }
  186. }
  187. return ntStatus;
  188. } // Init
  189. //=============================================================================
  190. STDMETHODIMP_(NTSTATUS)
  191. CMiniportWaveCyclic::NewStream
  192. (
  193. OUT PMINIPORTWAVECYCLICSTREAM * OutStream,
  194. IN PUNKNOWN OuterUnknown,
  195. IN POOL_TYPE PoolType,
  196. IN ULONG Pin,
  197. IN BOOLEAN Capture,
  198. IN PKSDATAFORMAT DataFormat,
  199. OUT PDMACHANNEL * OutDmaChannel,
  200. OUT PSERVICEGROUP * OutServiceGroup
  201. )
  202. /*++
  203. Routine Description:
  204. The NewStream function creates a new instance of a logical stream
  205. associated with a specified physical channel. Callers of NewStream should
  206. run at IRQL PASSIVE_LEVEL.
  207. Arguments:
  208. OutStream -
  209. OuterUnknown -
  210. PoolType -
  211. Pin -
  212. Capture -
  213. DataFormat -
  214. OutDmaChannel -
  215. OutServiceGroup -
  216. Return Value:
  217. NT status code.
  218. --*/
  219. {
  220. PAGED_CODE();
  221. ASSERT(OutStream);
  222. ASSERT(DataFormat);
  223. ASSERT(OutDmaChannel);
  224. ASSERT(OutServiceGroup);
  225. DPF_ENTER(("[CMiniportWaveCyclic::NewStream]"));
  226. NTSTATUS ntStatus = STATUS_SUCCESS;
  227. PCMiniportWaveCyclicStream stream = NULL;
  228. ULONG streamIndex;
  229. // MSVAD supports one capture stream.
  230. //
  231. if (Capture)
  232. {
  233. if (m_fCaptureAllocated)
  234. {
  235. DPF(D_TERSE, ("[Only one capture stream supported]"));
  236. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  237. }
  238. }
  239. // This version supports multiple playback streams.
  240. //
  241. else
  242. {
  243. for (streamIndex = 0; streamIndex < m_MaxInputStreams; streamIndex++)
  244. {
  245. if (!m_pStream[streamIndex])
  246. {
  247. break;
  248. }
  249. }
  250. if (streamIndex == m_MaxInputStreams)
  251. {
  252. DPF(D_TERSE, ("[All render streams are in use]"));
  253. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  254. }
  255. }
  256. // Determine if the format is valid.
  257. //
  258. if (NT_SUCCESS(ntStatus))
  259. {
  260. ntStatus = ValidateFormat(DataFormat);
  261. }
  262. // Instantiate a stream. Stream must be in
  263. // NonPagedPool because of file saving.
  264. //
  265. if (NT_SUCCESS(ntStatus))
  266. {
  267. stream = new (NonPagedPool, MSVAD_POOLTAG)
  268. CMiniportWaveCyclicStream(OuterUnknown);
  269. if (stream)
  270. {
  271. stream->AddRef();
  272. ntStatus =
  273. stream->Init
  274. (
  275. this,
  276. Pin,
  277. Capture,
  278. DataFormat
  279. );
  280. }
  281. else
  282. {
  283. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  284. }
  285. }
  286. if (NT_SUCCESS(ntStatus))
  287. {
  288. if (Capture)
  289. {
  290. m_fCaptureAllocated = TRUE;
  291. }
  292. else
  293. {
  294. m_pStream[streamIndex] = stream;
  295. }
  296. *OutStream = PMINIPORTWAVECYCLICSTREAM(stream);
  297. (*OutStream)->AddRef();
  298. *OutDmaChannel = PDMACHANNEL(stream);
  299. (*OutDmaChannel)->AddRef();
  300. *OutServiceGroup = m_ServiceGroup;
  301. (*OutServiceGroup)->AddRef();
  302. // The stream, the DMA channel, and the service group have
  303. // references now for the caller. The caller expects these
  304. // references to be there.
  305. }
  306. // This is our private reference to the stream. The caller has
  307. // its own, so we can release in any case.
  308. //
  309. if (stream)
  310. {
  311. stream->Release();
  312. }
  313. return ntStatus;
  314. } // NewStream
  315. //=============================================================================
  316. STDMETHODIMP_(NTSTATUS)
  317. CMiniportWaveCyclic::NonDelegatingQueryInterface
  318. (
  319. IN REFIID Interface,
  320. OUT PVOID * Object
  321. )
  322. /*++
  323. Routine Description:
  324. QueryInterface
  325. Arguments:
  326. Interface - GUID
  327. Object - interface pointer to be returned.
  328. Return Value:
  329. NT status code.
  330. --*/
  331. {
  332. PAGED_CODE();
  333. ASSERT(Object);
  334. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  335. {
  336. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
  337. }
  338. else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
  339. {
  340. *Object = PVOID(PMINIPORT(this));
  341. }
  342. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclic))
  343. {
  344. *Object = PVOID(PMINIPORTWAVECYCLIC(this));
  345. }
  346. else
  347. {
  348. *Object = NULL;
  349. }
  350. if (*Object)
  351. {
  352. // We reference the interface for the caller.
  353. PUNKNOWN(*Object)->AddRef();
  354. return STATUS_SUCCESS;
  355. }
  356. return STATUS_INVALID_PARAMETER;
  357. } // NonDelegatingQueryInterface
  358. //=============================================================================
  359. NTSTATUS
  360. CMiniportWaveCyclic::UpdateDrmRights
  361. (
  362. void
  363. )
  364. /*++
  365. Routine Description:
  366. Updates the mixed DrmRights. This is done by creating an array of existing
  367. content ids and asking DrmPort to create a new contend id with a mixed
  368. DrmRights structure.
  369. The new DrmRights structure should be enforced, if everything goes well.
  370. Arguments:
  371. Return Value:
  372. NT status code.
  373. --*/
  374. {
  375. PAGED_CODE();
  376. DPF_ENTER(("[CMiniportWaveCyclic::UpdateDrmRights]"));
  377. NTSTATUS ntStatus;
  378. ULONG ulContentIndex = 0;
  379. ULONG ulContentIds[MAX_INPUT_STREAMS];
  380. ULONG ulMixDrmContentId = 0;
  381. BOOL fCreatedContentId = FALSE;
  382. DRMRIGHTS MixDrmRights = {FALSE, 0, FALSE};
  383. // This function only runs if IID_DrmPort is implemented in Wave port.
  384. //
  385. if (!m_pDrmPort)
  386. {
  387. return STATUS_UNSUCCESSFUL;
  388. }
  389. // Create an array of all StreamIds.
  390. //
  391. for (ULONG i = 0; i < MAX_INPUT_STREAMS; i++)
  392. {
  393. if (m_pStream[i])
  394. {
  395. ulContentIds[ulContentIndex] = m_pStream[i]->m_ulContentId;
  396. ulContentIndex++;
  397. }
  398. }
  399. // Create the new contentId.
  400. //
  401. if (ulContentIndex)
  402. {
  403. ntStatus =
  404. m_pDrmPort->CreateContentMixed
  405. (
  406. ulContentIds,
  407. ulContentIndex,
  408. &ulMixDrmContentId
  409. );
  410. if (NT_SUCCESS(ntStatus))
  411. {
  412. fCreatedContentId = TRUE;
  413. ntStatus =
  414. m_pDrmPort->GetContentRights
  415. (
  416. ulMixDrmContentId,
  417. &MixDrmRights
  418. );
  419. }
  420. }
  421. // If successful, destroy the old ContentId and update global rights.
  422. //
  423. if (NT_SUCCESS(ntStatus))
  424. {
  425. m_pDrmPort->DestroyContent(m_ulMixDrmContentId);
  426. m_ulMixDrmContentId = ulMixDrmContentId;
  427. RtlCopyMemory(&m_MixDrmRights, &MixDrmRights, sizeof(m_MixDrmRights));
  428. // At this point the driver should enforce the new DrmRights.
  429. // MSVAD does not have loopback capture caps and does not support
  430. // S/PDIF out, therefore the new MixedRights is ignored.
  431. // MSVAD handles DrmRights per stream basis, and stops writing
  432. // the stream to disk, if CopyProtect = TRUE.
  433. //
  434. }
  435. // Cleanup if failed
  436. //
  437. if (!NT_SUCCESS(ntStatus) && fCreatedContentId)
  438. {
  439. m_pDrmPort->DestroyContent(ulMixDrmContentId);
  440. }
  441. return ntStatus;
  442. } // UpdateDrmRights
  443. //=============================================================================
  444. // CMiniportWaveStreamCyclicSimple
  445. //=============================================================================
  446. //=============================================================================
  447. CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream
  448. (
  449. void
  450. )
  451. /*++
  452. Routine Description:
  453. Destructor for wavecyclicstream
  454. Arguments:
  455. Return Value:
  456. NT status code.
  457. --*/
  458. {
  459. PAGED_CODE();
  460. DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
  461. if (NULL != m_pMiniportLocal)
  462. {
  463. // Tell the Miniport that the slot is freed now.
  464. //
  465. if (m_fCapture)
  466. {
  467. m_pMiniportLocal->m_fCaptureAllocated = FALSE;
  468. }
  469. else
  470. {
  471. for (ULONG i = 0; i < m_pMiniportLocal->m_MaxInputStreams; i++)
  472. {
  473. if (this == m_pMiniportLocal->m_pStream[i])
  474. {
  475. m_pMiniportLocal->m_pStream[i] = NULL;
  476. break;
  477. }
  478. }
  479. // Tell the wave miniport to update mixed drm rights.
  480. //
  481. m_pMiniportLocal->UpdateDrmRights();
  482. }
  483. }
  484. } // ~CMiniportWaveCyclicStream
  485. //=============================================================================
  486. NTSTATUS
  487. CMiniportWaveCyclicStream::Init
  488. (
  489. IN PCMiniportWaveCyclic Miniport_,
  490. IN ULONG Pin_,
  491. IN BOOLEAN Capture_,
  492. IN PKSDATAFORMAT DataFormat_
  493. )
  494. /*++
  495. Routine Description:
  496. Initializes the stream object. Allocate a DMA buffer, timer and DPC
  497. Arguments:
  498. Miniport_ -
  499. Pin_ -
  500. Capture_ -
  501. DataFormat -
  502. DmaChannel_ -
  503. Return Value:
  504. NT status code.
  505. --*/
  506. {
  507. PAGED_CODE();
  508. m_pMiniportLocal = Miniport_;
  509. m_ulContentId = 0;
  510. return
  511. CMiniportWaveCyclicStreamMSVAD::Init
  512. (
  513. Miniport_,
  514. Pin_,
  515. Capture_,
  516. DataFormat_
  517. );
  518. } // Init
  519. //=============================================================================
  520. STDMETHODIMP_(NTSTATUS)
  521. CMiniportWaveCyclicStream::NonDelegatingQueryInterface
  522. (
  523. IN REFIID Interface,
  524. OUT PVOID * Object
  525. )
  526. /*++
  527. Routine Description:
  528. QueryInterface
  529. Arguments:
  530. Interface - GUID
  531. Object - interface pointer to be returned
  532. Return Value:
  533. NT status code.
  534. --*/
  535. {
  536. PAGED_CODE();
  537. ASSERT(Object);
  538. if (IsEqualGUIDAligned(Interface, IID_IUnknown))
  539. {
  540. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
  541. }
  542. else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream))
  543. {
  544. *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
  545. }
  546. else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel))
  547. {
  548. *Object = PVOID(PDMACHANNEL(this));
  549. }
  550. else if (IsEqualGUIDAligned(Interface, IID_IDrmAudioStream))
  551. {
  552. *Object = (PVOID)(PDRMAUDIOSTREAM)this;
  553. }
  554. else
  555. {
  556. *Object = NULL;
  557. }
  558. if (*Object)
  559. {
  560. PUNKNOWN(*Object)->AddRef();
  561. return STATUS_SUCCESS;
  562. }
  563. return STATUS_INVALID_PARAMETER;
  564. } // NonDelegatingQueryInterface
  565. //=============================================================================
  566. STDMETHODIMP_(NTSTATUS)
  567. CMiniportWaveCyclicStream::SetContentId
  568. (
  569. IN ULONG contentId,
  570. IN PCDRMRIGHTS drmRights
  571. )
  572. /*++
  573. Routine Description:
  574. Sets DRM content Id for this stream. Also updates the Mixed content Id.
  575. Arguments:
  576. contentId - new content id
  577. drmRights - rights for this stream.
  578. Return Value:
  579. NT status code.
  580. --*/
  581. {
  582. PAGED_CODE();
  583. DPF_ENTER(("[CMiniportWaveCyclicStream::SetContentId]"));
  584. NTSTATUS ntStatus;
  585. ULONG ulOldContentId = contentId;
  586. m_ulContentId = contentId;
  587. // Miniport should create a mixed DrmRights.
  588. //
  589. ntStatus = m_pMiniportLocal->UpdateDrmRights();
  590. // Restore the old content Id.
  591. //
  592. if (!NT_SUCCESS(ntStatus))
  593. {
  594. m_ulContentId = ulOldContentId;
  595. }
  596. // MSVAD rights each stream seperately to disk. If the rights for this
  597. // stream indicates that the stream is CopyProtected, stop writing to disk.
  598. //
  599. m_SaveData.Disable(drmRights->CopyProtect);
  600. return ntStatus;
  601. } // SetContentId
  602. #pragma code_seg()