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.

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