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.

1929 lines
54 KiB

  1. /*****************************************************************************
  2. * miniport.cpp - SB16 wave miniport implementation
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #include "minwave.h"
  7. #define STR_MODULENAME "sb16wave: "
  8. #pragma code_seg("PAGE")
  9. /*****************************************************************************
  10. * CreateMiniportWaveCyclicSB16()
  11. *****************************************************************************
  12. * Creates a cyclic wave miniport object for the SB16 adapter. This uses a
  13. * macro from STDUNK.H to do all the work.
  14. */
  15. NTSTATUS
  16. CreateMiniportWaveCyclicSB16
  17. (
  18. OUT PUNKNOWN * Unknown,
  19. IN REFCLSID,
  20. IN PUNKNOWN UnknownOuter OPTIONAL,
  21. IN POOL_TYPE PoolType
  22. )
  23. {
  24. PAGED_CODE();
  25. ASSERT(Unknown);
  26. STD_CREATE_BODY_(CMiniportWaveCyclicSB16,Unknown,UnknownOuter,PoolType,PMINIPORTWAVECYCLIC);
  27. }
  28. /*****************************************************************************
  29. * MapUsingTable()
  30. *****************************************************************************
  31. * Performs a table-based mapping, returning the table index of the indicated
  32. * value. -1 is returned if the value is not found.
  33. */
  34. int
  35. MapUsingTable
  36. (
  37. IN ULONG Value,
  38. IN PULONG Map,
  39. IN ULONG MapSize
  40. )
  41. {
  42. PAGED_CODE();
  43. ASSERT(Map);
  44. for (int result = 0; result < int(MapSize); result++)
  45. {
  46. if (*Map++ == Value)
  47. {
  48. return result;
  49. }
  50. }
  51. return -1;
  52. }
  53. /*****************************************************************************
  54. * CMiniportWaveCyclicSB16::ConfigureDevice()
  55. *****************************************************************************
  56. * Configures the hardware to use the indicated interrupt and DMA channels.
  57. * Returns FALSE iff the configuration is invalid.
  58. */
  59. BOOLEAN
  60. CMiniportWaveCyclicSB16::
  61. ConfigureDevice
  62. (
  63. IN ULONG Interrupt,
  64. IN ULONG Dma8Bit,
  65. IN ULONG Dma16Bit
  66. )
  67. {
  68. PAGED_CODE();
  69. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::ConfigureDevice]"));
  70. //
  71. // Tables mapping DMA and IRQ values to register bit offsets.
  72. //
  73. static ULONG validDma[] = { 0, 1, ULONG(-1), 3, ULONG(-1), 5, 6, 7 } ;
  74. static ULONG validIrq[] = { 9, 5, 7, 10 } ;
  75. //
  76. // Make sure we are using the right DMA channels.
  77. //
  78. if (Dma8Bit > 3)
  79. {
  80. return FALSE;
  81. }
  82. if (Dma16Bit < 5)
  83. {
  84. return FALSE;
  85. }
  86. //
  87. // Generate the register value for interrupts.
  88. //
  89. int bit = MapUsingTable(Interrupt,validIrq,SIZEOF_ARRAY(validIrq));
  90. if (bit == -1)
  91. {
  92. return FALSE;
  93. }
  94. BYTE irqConfig = BYTE(1 << bit);
  95. //
  96. // Generate the register value for DMA.
  97. //
  98. bit = MapUsingTable(Dma8Bit,validDma,SIZEOF_ARRAY(validDma));
  99. if (bit == -1)
  100. {
  101. return FALSE;
  102. }
  103. BYTE dmaConfig = BYTE(1 << bit);
  104. if (Dma16Bit != ULONG(-1))
  105. {
  106. bit = MapUsingTable(Dma16Bit,validDma,SIZEOF_ARRAY(validDma));
  107. if (bit == -1)
  108. {
  109. return FALSE;
  110. }
  111. dmaConfig |= BYTE(1 << bit);
  112. }
  113. //
  114. // Inform the hardware.
  115. //
  116. AdapterCommon->MixerRegWrite(DSP_MIX_IRQCONFIG,irqConfig);
  117. AdapterCommon->MixerRegWrite(DSP_MIX_DMACONFIG,dmaConfig);
  118. return TRUE;
  119. }
  120. /*****************************************************************************
  121. * CMiniportWaveCyclicSB16::ProcessResources()
  122. *****************************************************************************
  123. * Processes the resource list, setting up helper objects accordingly.
  124. */
  125. NTSTATUS
  126. CMiniportWaveCyclicSB16::
  127. ProcessResources
  128. (
  129. IN PRESOURCELIST ResourceList
  130. )
  131. {
  132. PAGED_CODE();
  133. ASSERT(ResourceList);
  134. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::ProcessResources]"));
  135. ULONG intNumber = ULONG(-1);
  136. ULONG dma8Bit = ULONG(-1);
  137. ULONG dma16Bit = ULONG(-1);
  138. //
  139. // Get counts for the types of resources.
  140. //
  141. ULONG countIO = ResourceList->NumberOfPorts();
  142. ULONG countIRQ = ResourceList->NumberOfInterrupts();
  143. ULONG countDMA = ResourceList->NumberOfDmas();
  144. #if (DBG)
  145. _DbgPrintF(DEBUGLVL_VERBOSE,("Starting SB16 wave on IRQ 0x%X",
  146. ResourceList->FindUntranslatedInterrupt(0)->u.Interrupt.Level) );
  147. _DbgPrintF(DEBUGLVL_VERBOSE,("Starting SB16 wave on Port 0x%X",
  148. ResourceList->FindTranslatedPort(0)->u.Port.Start.LowPart) );
  149. for (ULONG i = 0; i < countDMA; i++)
  150. {
  151. _DbgPrintF(DEBUGLVL_VERBOSE,("Starting SB16 wave on DMA 0x%X",
  152. ResourceList->FindUntranslatedDma(i)->u.Dma.Channel) );
  153. }
  154. #endif
  155. NTSTATUS ntStatus = STATUS_SUCCESS;
  156. //
  157. // Make sure we have the expected number of resources.
  158. //
  159. if ( (countIO != 1)
  160. || (countIRQ < 1)
  161. || (countDMA < 1)
  162. )
  163. {
  164. _DbgPrintF(DEBUGLVL_TERSE,("unknown configuraton; check your code!"));
  165. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  166. }
  167. if (NT_SUCCESS(ntStatus))
  168. {
  169. //
  170. // Instantiate a DMA channel for 8-bit transfers.
  171. //
  172. ntStatus =
  173. Port->NewSlaveDmaChannel
  174. (
  175. &DmaChannel8,
  176. NULL,
  177. ResourceList,
  178. 0,
  179. MAXLEN_DMA_BUFFER,
  180. FALSE, // DemandMode
  181. Compatible
  182. );
  183. //
  184. // Allocate the buffer for 8-bit transfers.
  185. //
  186. if (NT_SUCCESS(ntStatus))
  187. {
  188. ULONG lDMABufferLength = MAXLEN_DMA_BUFFER;
  189. do {
  190. ntStatus = DmaChannel8->AllocateBuffer(lDMABufferLength,NULL);
  191. lDMABufferLength >>= 1;
  192. } while (!NT_SUCCESS(ntStatus) && (lDMABufferLength > (PAGE_SIZE / 2)));
  193. }
  194. if (NT_SUCCESS(ntStatus))
  195. {
  196. dma8Bit = ResourceList->FindUntranslatedDma(0)->u.Dma.Channel;
  197. if (countDMA > 1)
  198. {
  199. //
  200. // Instantiate a DMA channel for 16-bit transfers.
  201. //
  202. ntStatus =
  203. Port->NewSlaveDmaChannel
  204. (
  205. &DmaChannel16,
  206. NULL,
  207. ResourceList,
  208. 1,
  209. MAXLEN_DMA_BUFFER,
  210. FALSE,
  211. Compatible
  212. );
  213. //
  214. // Allocate the buffer for 16-bit transfers.
  215. //
  216. if (NT_SUCCESS(ntStatus))
  217. {
  218. ULONG lDMABufferLength = MAXLEN_DMA_BUFFER;
  219. do {
  220. ntStatus = DmaChannel16->AllocateBuffer(lDMABufferLength,NULL);
  221. lDMABufferLength >>= 1;
  222. } while (!NT_SUCCESS(ntStatus) && (lDMABufferLength > (PAGE_SIZE / 2)));
  223. }
  224. if (NT_SUCCESS(ntStatus))
  225. {
  226. dma16Bit =
  227. ResourceList->FindUntranslatedDma(1)->u.Dma.Channel;
  228. }
  229. }
  230. if (NT_SUCCESS(ntStatus))
  231. {
  232. //
  233. // Get the interrupt number and configure the device.
  234. //
  235. intNumber =
  236. ResourceList->
  237. FindUntranslatedInterrupt(0)->u.Interrupt.Level;
  238. if (! ConfigureDevice(intNumber,dma8Bit,dma16Bit))
  239. {
  240. _DbgPrintF(DEBUGLVL_TERSE,("ConfigureDevice Failure"));
  241. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  242. }
  243. }
  244. else
  245. {
  246. _DbgPrintF(DEBUGLVL_TERSE,("NewSlaveDmaChannel 2 Failure %X", ntStatus ));
  247. }
  248. }
  249. else
  250. {
  251. _DbgPrintF(DEBUGLVL_TERSE,("NewSlaveDmaChannel 1 Failure %X", ntStatus ));
  252. }
  253. }
  254. //
  255. // In case of failure object gets destroyed and cleans up.
  256. //
  257. return ntStatus;
  258. }
  259. /*****************************************************************************
  260. * CMiniportWaveCyclicSB16::ValidateFormat()
  261. *****************************************************************************
  262. * Validates a wave format.
  263. */
  264. NTSTATUS
  265. CMiniportWaveCyclicSB16::
  266. ValidateFormat
  267. (
  268. IN PKSDATAFORMAT Format
  269. )
  270. {
  271. PAGED_CODE();
  272. ASSERT(Format);
  273. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::ValidateFormat]"));
  274. NTSTATUS ntStatus;
  275. //
  276. // A WAVEFORMATEX structure should appear after the generic KSDATAFORMAT
  277. // if the GUIDs turn out as we expect.
  278. //
  279. PWAVEFORMATEX waveFormat = PWAVEFORMATEX(Format + 1);
  280. //
  281. // KSDATAFORMAT contains three GUIDs to support extensible format. The
  282. // first two GUIDs identify the type of data. The third indicates the
  283. // type of specifier used to indicate format specifics. We are only
  284. // supporting PCM audio formats that use WAVEFORMATEX.
  285. //
  286. if ( (Format->FormatSize >= sizeof(KSDATAFORMAT_WAVEFORMATEX))
  287. && IsEqualGUIDAligned(Format->MajorFormat,KSDATAFORMAT_TYPE_AUDIO)
  288. && IsEqualGUIDAligned(Format->SubFormat,KSDATAFORMAT_SUBTYPE_PCM)
  289. && IsEqualGUIDAligned(Format->Specifier,KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
  290. && (waveFormat->wFormatTag == WAVE_FORMAT_PCM)
  291. && ((waveFormat->wBitsPerSample == 8) || (waveFormat->wBitsPerSample == 16))
  292. && ((waveFormat->nChannels == 1) || (waveFormat->nChannels == 2))
  293. && ((waveFormat->nSamplesPerSec >= 5000) && (waveFormat->nSamplesPerSec <= 44100))
  294. )
  295. {
  296. ntStatus = STATUS_SUCCESS;
  297. }
  298. else
  299. {
  300. ntStatus = STATUS_INVALID_PARAMETER;
  301. }
  302. return ntStatus;
  303. }
  304. /*****************************************************************************
  305. * CMiniportWaveCyclicSB16::NonDelegatingQueryInterface()
  306. *****************************************************************************
  307. * Obtains an interface. This function works just like a COM QueryInterface
  308. * call and is used if the object is not being aggregated.
  309. */
  310. STDMETHODIMP
  311. CMiniportWaveCyclicSB16::
  312. NonDelegatingQueryInterface
  313. (
  314. IN REFIID Interface,
  315. OUT PVOID * Object
  316. )
  317. {
  318. PAGED_CODE();
  319. ASSERT(Object);
  320. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::NonDelegatingQueryInterface]"));
  321. if (IsEqualGUIDAligned(Interface,IID_IUnknown))
  322. {
  323. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLIC(this)));
  324. }
  325. else
  326. if (IsEqualGUIDAligned(Interface,IID_IMiniport))
  327. {
  328. *Object = PVOID(PMINIPORT(this));
  329. }
  330. else
  331. if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveCyclic))
  332. {
  333. *Object = PVOID(PMINIPORTWAVECYCLIC(this));
  334. }
  335. else
  336. {
  337. *Object = NULL;
  338. }
  339. if (*Object)
  340. {
  341. //
  342. // We reference the interface for the caller.
  343. //
  344. PUNKNOWN(*Object)->AddRef();
  345. return STATUS_SUCCESS;
  346. }
  347. return STATUS_INVALID_PARAMETER;
  348. }
  349. /*****************************************************************************
  350. * CMiniportWaveCyclicSB16::~CMiniportWaveCyclicSB16()
  351. *****************************************************************************
  352. * Destructor.
  353. */
  354. CMiniportWaveCyclicSB16::
  355. ~CMiniportWaveCyclicSB16
  356. ( void
  357. )
  358. {
  359. PAGED_CODE();
  360. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::~CMiniportWaveCyclicSB16]"));
  361. if (AdapterCommon)
  362. {
  363. AdapterCommon->SetWaveMiniport (NULL);
  364. AdapterCommon->Release();
  365. AdapterCommon = NULL;
  366. }
  367. if (Port)
  368. {
  369. Port->Release();
  370. Port = NULL;
  371. }
  372. if (DmaChannel8)
  373. {
  374. DmaChannel8->Release();
  375. DmaChannel8 = NULL;
  376. }
  377. if (DmaChannel16)
  378. {
  379. DmaChannel16->Release();
  380. DmaChannel16 = NULL;
  381. }
  382. if (ServiceGroup)
  383. {
  384. ServiceGroup->Release();
  385. ServiceGroup = NULL;
  386. }
  387. }
  388. /*****************************************************************************
  389. * CMiniportWaveCyclicSB16::Init()
  390. *****************************************************************************
  391. * Initializes a the miniport.
  392. */
  393. STDMETHODIMP
  394. CMiniportWaveCyclicSB16::
  395. Init
  396. (
  397. IN PUNKNOWN UnknownAdapter,
  398. IN PRESOURCELIST ResourceList,
  399. IN PPORTWAVECYCLIC Port_
  400. )
  401. {
  402. PAGED_CODE();
  403. ASSERT(UnknownAdapter);
  404. ASSERT(ResourceList);
  405. ASSERT(Port_);
  406. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::init]"));
  407. //
  408. // AddRef() is required because we are keeping this pointer.
  409. //
  410. Port = Port_;
  411. Port->AddRef();
  412. //
  413. // Initialize the member variables.
  414. //
  415. ServiceGroup = NULL;
  416. DmaChannel8 = NULL;
  417. DmaChannel16 = NULL;
  418. //
  419. // We want the IAdapterCommon interface on the adapter common object,
  420. // which is given to us as a IUnknown. The QueryInterface call gives us
  421. // an AddRefed pointer to the interface we want.
  422. //
  423. NTSTATUS ntStatus =
  424. UnknownAdapter->QueryInterface
  425. (
  426. IID_IAdapterCommon,
  427. (PVOID *) &AdapterCommon
  428. );
  429. //
  430. // We need a service group for notifications. We will bind all the
  431. // streams that are created to this single service group. All interrupt
  432. // notifications ask for service on this group, so all streams will get
  433. // serviced. The PcNewServiceGroup() call returns an AddRefed pointer.
  434. // The adapter needs a copy of the service group since it is doing the
  435. // ISR.
  436. //
  437. if (NT_SUCCESS(ntStatus))
  438. {
  439. KeInitializeMutex(&SampleRateSync,1);
  440. ntStatus = PcNewServiceGroup(&ServiceGroup,NULL);
  441. }
  442. if (NT_SUCCESS(ntStatus))
  443. {
  444. AdapterCommon->SetWaveMiniport ((PWAVEMINIPORTSB16)this);
  445. ntStatus = ProcessResources(ResourceList);
  446. }
  447. //
  448. // In case of failure object gets destroyed and destructor cleans up.
  449. //
  450. return ntStatus;
  451. }
  452. /*****************************************************************************
  453. * PinDataRangesStream
  454. *****************************************************************************
  455. * Structures indicating range of valid format values for streaming pins.
  456. */
  457. static
  458. KSDATARANGE_AUDIO PinDataRangesStream[] =
  459. {
  460. {
  461. {
  462. sizeof(KSDATARANGE_AUDIO),
  463. 0,
  464. 0,
  465. 0,
  466. STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
  467. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
  468. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
  469. },
  470. 2, // Max number of channels.
  471. 8, // Minimum number of bits per sample.
  472. 16, // Maximum number of bits per channel.
  473. 5000, // Minimum rate.
  474. 44100 // Maximum rate.
  475. }
  476. };
  477. /*****************************************************************************
  478. * PinDataRangePointersStream
  479. *****************************************************************************
  480. * List of pointers to structures indicating range of valid format values
  481. * for streaming pins.
  482. */
  483. static
  484. PKSDATARANGE PinDataRangePointersStream[] =
  485. {
  486. PKSDATARANGE(&PinDataRangesStream[0])
  487. };
  488. /*****************************************************************************
  489. * PinDataRangesBridge
  490. *****************************************************************************
  491. * Structures indicating range of valid format values for bridge pins.
  492. */
  493. static
  494. KSDATARANGE PinDataRangesBridge[] =
  495. {
  496. {
  497. sizeof(KSDATARANGE),
  498. 0,
  499. 0,
  500. 0,
  501. STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
  502. STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
  503. STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
  504. }
  505. };
  506. /*****************************************************************************
  507. * PinDataRangePointersBridge
  508. *****************************************************************************
  509. * List of pointers to structures indicating range of valid format values
  510. * for bridge pins.
  511. */
  512. static
  513. PKSDATARANGE PinDataRangePointersBridge[] =
  514. {
  515. &PinDataRangesBridge[0]
  516. };
  517. /*****************************************************************************
  518. * MiniportPins
  519. *****************************************************************************
  520. * List of pins.
  521. */
  522. static
  523. PCPIN_DESCRIPTOR
  524. MiniportPins[] =
  525. {
  526. // Wave In Streaming Pin (Capture)
  527. {
  528. 1,1,0,
  529. NULL,
  530. {
  531. 0,
  532. NULL,
  533. 0,
  534. NULL,
  535. SIZEOF_ARRAY(PinDataRangePointersStream),
  536. PinDataRangePointersStream,
  537. KSPIN_DATAFLOW_OUT,
  538. KSPIN_COMMUNICATION_SINK,
  539. (GUID *) &PINNAME_CAPTURE,
  540. &KSAUDFNAME_RECORDING_CONTROL, // this name shows up as the recording panel name in SoundVol.
  541. 0
  542. }
  543. },
  544. // Wave In Bridge Pin (Capture - From Topology)
  545. {
  546. 0,0,0,
  547. NULL,
  548. {
  549. 0,
  550. NULL,
  551. 0,
  552. NULL,
  553. SIZEOF_ARRAY(PinDataRangePointersBridge),
  554. PinDataRangePointersBridge,
  555. KSPIN_DATAFLOW_IN,
  556. KSPIN_COMMUNICATION_NONE,
  557. (GUID *) &KSCATEGORY_AUDIO,
  558. NULL,
  559. 0
  560. }
  561. },
  562. // Wave Out Streaming Pin (Renderer)
  563. {
  564. 1,1,0,
  565. NULL,
  566. {
  567. 0,
  568. NULL,
  569. 0,
  570. NULL,
  571. SIZEOF_ARRAY(PinDataRangePointersStream),
  572. PinDataRangePointersStream,
  573. KSPIN_DATAFLOW_IN,
  574. KSPIN_COMMUNICATION_SINK,
  575. (GUID *) &KSCATEGORY_AUDIO,
  576. NULL,
  577. 0
  578. }
  579. },
  580. // Wave Out Bridge Pin (Renderer)
  581. {
  582. 0,0,0,
  583. NULL,
  584. {
  585. 0,
  586. NULL,
  587. 0,
  588. NULL,
  589. SIZEOF_ARRAY(PinDataRangePointersBridge),
  590. PinDataRangePointersBridge,
  591. KSPIN_DATAFLOW_OUT,
  592. KSPIN_COMMUNICATION_NONE,
  593. (GUID *) &KSCATEGORY_AUDIO,
  594. NULL,
  595. 0
  596. }
  597. }
  598. };
  599. /*****************************************************************************
  600. * TopologyNodes
  601. *****************************************************************************
  602. * List of nodes.
  603. */
  604. static
  605. PCNODE_DESCRIPTOR MiniportNodes[] =
  606. {
  607. {
  608. 0, // Flags
  609. NULL, // AutomationTable
  610. &KSNODETYPE_ADC, // Type
  611. NULL // Name
  612. },
  613. {
  614. 0, // Flags
  615. NULL, // AutomationTable
  616. &KSNODETYPE_DAC, // Type
  617. NULL // Name
  618. }
  619. };
  620. /*****************************************************************************
  621. * MiniportConnections
  622. *****************************************************************************
  623. * List of connections.
  624. */
  625. static
  626. PCCONNECTION_DESCRIPTOR MiniportConnections[] =
  627. {
  628. { PCFILTER_NODE, 1, 0, 1 }, // Bridge in to ADC.
  629. { 0, 0, PCFILTER_NODE, 0 }, // ADC to stream pin (capture).
  630. { PCFILTER_NODE, 2, 1, 1 }, // Stream in to DAC.
  631. { 1, 0, PCFILTER_NODE, 3 } // DAC to Bridge.
  632. };
  633. /*****************************************************************************
  634. * MiniportFilterDescriptor
  635. *****************************************************************************
  636. * Complete miniport description.
  637. */
  638. static
  639. PCFILTER_DESCRIPTOR
  640. MiniportFilterDescriptor =
  641. {
  642. 0, // Version
  643. &AutomationFilter, // AutomationTable
  644. sizeof(PCPIN_DESCRIPTOR), // PinSize
  645. SIZEOF_ARRAY(MiniportPins), // PinCount
  646. MiniportPins, // Pins
  647. sizeof(PCNODE_DESCRIPTOR), // NodeSize
  648. SIZEOF_ARRAY(MiniportNodes), // NodeCount
  649. MiniportNodes, // Nodes
  650. SIZEOF_ARRAY(MiniportConnections), // ConnectionCount
  651. MiniportConnections, // Connections
  652. 0, // CategoryCount
  653. NULL // Categories - use the default categories (audio, render, capture)
  654. };
  655. /*****************************************************************************
  656. * CMiniportWaveCyclicSB16::GetDescription()
  657. *****************************************************************************
  658. * Gets the topology.
  659. */
  660. STDMETHODIMP
  661. CMiniportWaveCyclicSB16::
  662. GetDescription
  663. (
  664. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  665. )
  666. {
  667. PAGED_CODE();
  668. ASSERT(OutFilterDescriptor);
  669. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::GetDescription]"));
  670. *OutFilterDescriptor = &MiniportFilterDescriptor;
  671. return STATUS_SUCCESS;
  672. }
  673. /*****************************************************************************
  674. * CMiniportWaveCyclicSB16::DataRangeIntersection()
  675. *****************************************************************************
  676. * Tests a data range intersection.
  677. */
  678. STDMETHODIMP
  679. CMiniportWaveCyclicSB16::
  680. DataRangeIntersection
  681. (
  682. IN ULONG PinId,
  683. IN PKSDATARANGE ClientDataRange,
  684. IN PKSDATARANGE MyDataRange,
  685. IN ULONG OutputBufferLength,
  686. OUT PVOID ResultantFormat,
  687. OUT PULONG ResultantFormatLength
  688. )
  689. {
  690. PAGED_CODE();
  691. BOOLEAN DigitalAudio;
  692. NTSTATUS Status;
  693. ULONG RequiredSize;
  694. ULONG SampleFrequency;
  695. USHORT BitsPerSample;
  696. //
  697. // Let's do the complete work here.
  698. //
  699. if (!IsEqualGUIDAligned(ClientDataRange->Specifier,KSDATAFORMAT_SPECIFIER_NONE))
  700. {
  701. //
  702. // The miniport did not resolve this format. If the dataformat
  703. // is not PCM audio and requires a specifier, bail out.
  704. //
  705. if ( !IsEqualGUIDAligned(ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO )
  706. || !IsEqualGUIDAligned(ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM ))
  707. {
  708. return STATUS_INVALID_PARAMETER;
  709. }
  710. DigitalAudio = TRUE;
  711. //
  712. // weird enough, the specifier here does not define the format of ClientDataRange
  713. // but the format that is expected to be returned in ResultantFormat.
  714. //
  715. if (IsEqualGUIDAligned(ClientDataRange->Specifier,KSDATAFORMAT_SPECIFIER_DSOUND))
  716. {
  717. RequiredSize = sizeof(KSDATAFORMAT_DSOUND);
  718. }
  719. else
  720. {
  721. RequiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
  722. }
  723. }
  724. else
  725. {
  726. DigitalAudio = FALSE;
  727. RequiredSize = sizeof(KSDATAFORMAT);
  728. }
  729. //
  730. // Validate return buffer size, if the request is only for the
  731. // size of the resultant structure, return it now.
  732. //
  733. if (!OutputBufferLength)
  734. {
  735. *ResultantFormatLength = RequiredSize;
  736. return STATUS_BUFFER_OVERFLOW;
  737. }
  738. else if (OutputBufferLength < RequiredSize)
  739. {
  740. return STATUS_BUFFER_TOO_SMALL;
  741. }
  742. // There was a specifier ...
  743. if (DigitalAudio)
  744. {
  745. PKSDATARANGE_AUDIO AudioRange;
  746. PWAVEFORMATEX WaveFormatEx;
  747. AudioRange = (PKSDATARANGE_AUDIO) MyDataRange;
  748. // Fill the structure
  749. if (IsEqualGUIDAligned(ClientDataRange->Specifier,KSDATAFORMAT_SPECIFIER_DSOUND))
  750. {
  751. PKSDATAFORMAT_DSOUND DSoundFormat;
  752. DSoundFormat = (PKSDATAFORMAT_DSOUND) ResultantFormat;
  753. _DbgPrintF(DEBUGLVL_VERBOSE,("returning KSDATAFORMAT_DSOUND format intersection"));
  754. DSoundFormat->BufferDesc.Flags = 0 ;
  755. DSoundFormat->BufferDesc.Control = 0 ;
  756. DSoundFormat->DataFormat = *ClientDataRange;
  757. DSoundFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;
  758. DSoundFormat->DataFormat.FormatSize = RequiredSize;
  759. WaveFormatEx = &DSoundFormat->BufferDesc.WaveFormatEx;
  760. *ResultantFormatLength = RequiredSize;
  761. }
  762. else
  763. {
  764. PKSDATAFORMAT_WAVEFORMATEX WaveFormat;
  765. WaveFormat = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;
  766. _DbgPrintF(DEBUGLVL_VERBOSE,("returning KSDATAFORMAT_WAVEFORMATEX format intersection") );
  767. WaveFormat->DataFormat = *ClientDataRange;
  768. WaveFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
  769. WaveFormat->DataFormat.FormatSize = RequiredSize;
  770. WaveFormatEx = &WaveFormat->WaveFormatEx;
  771. *ResultantFormatLength = RequiredSize;
  772. }
  773. //
  774. // Return a format that intersects the given audio range,
  775. // using our maximum support as the "best" format.
  776. //
  777. WaveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
  778. WaveFormatEx->nChannels =
  779. (USHORT) min( AudioRange->MaximumChannels,
  780. ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumChannels );
  781. //
  782. // Check if the pin is still free
  783. //
  784. if (!PinId)
  785. {
  786. if (AllocatedCapture)
  787. {
  788. return STATUS_NO_MATCH;
  789. }
  790. }
  791. else
  792. {
  793. if (AllocatedRender)
  794. {
  795. return STATUS_NO_MATCH;
  796. }
  797. }
  798. //
  799. // Check if one pin is in use -> use same sample frequency.
  800. //
  801. if (AllocatedCapture || AllocatedRender)
  802. {
  803. SampleFrequency = SamplingFrequency;
  804. if ( (SampleFrequency > ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumSampleFrequency)
  805. || (SampleFrequency < ((PKSDATARANGE_AUDIO) ClientDataRange)->MinimumSampleFrequency))
  806. {
  807. return STATUS_NO_MATCH;
  808. }
  809. }
  810. else
  811. {
  812. SampleFrequency =
  813. min( AudioRange->MaximumSampleFrequency,
  814. ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumSampleFrequency );
  815. }
  816. WaveFormatEx->nSamplesPerSec = SampleFrequency;
  817. //
  818. // Check if one pin is in use -> use other bits per sample.
  819. //
  820. if (AllocatedCapture || AllocatedRender)
  821. {
  822. if (Allocated8Bit)
  823. {
  824. BitsPerSample = 16;
  825. }
  826. else
  827. {
  828. BitsPerSample = 8;
  829. }
  830. if ((BitsPerSample > ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumBitsPerSample) ||
  831. (BitsPerSample < ((PKSDATARANGE_AUDIO) ClientDataRange)->MinimumBitsPerSample))
  832. {
  833. return STATUS_NO_MATCH;
  834. }
  835. }
  836. else
  837. {
  838. BitsPerSample =
  839. (USHORT) min( AudioRange->MaximumBitsPerSample,
  840. ((PKSDATARANGE_AUDIO) ClientDataRange)->MaximumBitsPerSample );
  841. }
  842. WaveFormatEx->wBitsPerSample = BitsPerSample;
  843. WaveFormatEx->nBlockAlign = (WaveFormatEx->wBitsPerSample * WaveFormatEx->nChannels) / 8;
  844. WaveFormatEx->nAvgBytesPerSec = (WaveFormatEx->nSamplesPerSec * WaveFormatEx->nBlockAlign);
  845. WaveFormatEx->cbSize = 0;
  846. ((PKSDATAFORMAT) ResultantFormat)->SampleSize = WaveFormatEx->nBlockAlign;
  847. _DbgPrintF(DEBUGLVL_VERBOSE,("Channels = %d", WaveFormatEx->nChannels) );
  848. _DbgPrintF(DEBUGLVL_VERBOSE,("Samples/sec = %d", WaveFormatEx->nSamplesPerSec) );
  849. _DbgPrintF(DEBUGLVL_VERBOSE,("Bits/sample = %d", WaveFormatEx->wBitsPerSample) );
  850. }
  851. else
  852. {
  853. // There was no specifier. Return only the KSDATAFORMAT structure.
  854. //
  855. // Copy the data format structure.
  856. //
  857. _DbgPrintF(DEBUGLVL_VERBOSE,("returning default format intersection") );
  858. RtlCopyMemory(ResultantFormat, ClientDataRange, sizeof( KSDATAFORMAT ) );
  859. *ResultantFormatLength = sizeof( KSDATAFORMAT );
  860. }
  861. return STATUS_SUCCESS;
  862. }
  863. /*****************************************************************************
  864. * CMiniportWaveCyclicSB16::NewStream()
  865. *****************************************************************************
  866. * Creates a new stream. This function is called when a streaming pin is
  867. * created.
  868. */
  869. STDMETHODIMP
  870. CMiniportWaveCyclicSB16::
  871. NewStream
  872. (
  873. OUT PMINIPORTWAVECYCLICSTREAM * OutStream,
  874. IN PUNKNOWN OuterUnknown,
  875. IN POOL_TYPE PoolType,
  876. IN ULONG Channel,
  877. IN BOOLEAN Capture,
  878. IN PKSDATAFORMAT DataFormat,
  879. OUT PDMACHANNEL * OutDmaChannel,
  880. OUT PSERVICEGROUP * OutServiceGroup
  881. )
  882. {
  883. PAGED_CODE();
  884. ASSERT(OutStream);
  885. ASSERT(DataFormat);
  886. ASSERT(OutDmaChannel);
  887. ASSERT(OutServiceGroup);
  888. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicSB16::NewStream]"));
  889. NTSTATUS ntStatus = STATUS_SUCCESS;
  890. //
  891. // Make sure the hardware is not already in use.
  892. //
  893. if (Capture)
  894. {
  895. if (AllocatedCapture)
  896. {
  897. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  898. }
  899. }
  900. else
  901. {
  902. if (AllocatedRender)
  903. {
  904. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  905. }
  906. }
  907. //
  908. // Determine if the format is valid.
  909. //
  910. if (NT_SUCCESS(ntStatus))
  911. {
  912. ntStatus = ValidateFormat(DataFormat);
  913. }
  914. if(NT_SUCCESS(ntStatus))
  915. {
  916. // if we're trying to start a full-duplex stream.
  917. if(AllocatedCapture || AllocatedRender)
  918. {
  919. // make sure the requested sampling rate is the
  920. // same as the currently running one...
  921. PWAVEFORMATEX waveFormat = PWAVEFORMATEX(DataFormat + 1);
  922. if( SamplingFrequency != waveFormat->nSamplesPerSec )
  923. {
  924. // Bad format....
  925. ntStatus = STATUS_INVALID_PARAMETER;
  926. }
  927. }
  928. }
  929. PDMACHANNELSLAVE dmaChannel = NULL;
  930. PWAVEFORMATEX waveFormat = PWAVEFORMATEX(DataFormat + 1);
  931. //
  932. // Get the required DMA channel if it's not already in use.
  933. //
  934. if (NT_SUCCESS(ntStatus))
  935. {
  936. if (waveFormat->wBitsPerSample == 8)
  937. {
  938. if (! Allocated8Bit)
  939. {
  940. dmaChannel = DmaChannel8;
  941. }
  942. }
  943. else
  944. {
  945. if (! Allocated16Bit)
  946. {
  947. dmaChannel = DmaChannel16;
  948. }
  949. }
  950. }
  951. if (! dmaChannel)
  952. {
  953. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  954. }
  955. else
  956. {
  957. //
  958. // Instantiate a stream.
  959. //
  960. CMiniportWaveCyclicStreamSB16 *stream =
  961. new(PoolType) CMiniportWaveCyclicStreamSB16(OuterUnknown);
  962. if (stream)
  963. {
  964. stream->AddRef();
  965. ntStatus =
  966. stream->Init
  967. (
  968. this,
  969. Channel,
  970. Capture,
  971. DataFormat,
  972. dmaChannel
  973. );
  974. if (NT_SUCCESS(ntStatus))
  975. {
  976. if (Capture)
  977. {
  978. AllocatedCapture = TRUE;
  979. }
  980. else
  981. {
  982. AllocatedRender = TRUE;
  983. }
  984. if (waveFormat->wBitsPerSample == 8)
  985. {
  986. Allocated8Bit = TRUE;
  987. }
  988. else
  989. {
  990. Allocated16Bit = TRUE;
  991. }
  992. *OutStream = PMINIPORTWAVECYCLICSTREAM(stream);
  993. stream->AddRef();
  994. #if OVERRIDE_DMA_CHANNEL
  995. *OutDmaChannel = PDMACHANNEL(stream);
  996. stream->AddRef();
  997. #else // OVERRIDE_DMA_CHANNEL
  998. *OutDmaChannel = dmaChannel;
  999. dmaChannel->AddRef();
  1000. #endif // OVERRIDE_DMA_CHANNEL
  1001. *OutServiceGroup = ServiceGroup;
  1002. ServiceGroup->AddRef();
  1003. //
  1004. // The stream, the DMA channel, and the service group have
  1005. // references now for the caller. The caller expects these
  1006. // references to be there.
  1007. //
  1008. }
  1009. //
  1010. // This is our private reference to the stream. The caller has
  1011. // its own, so we can release in any case.
  1012. //
  1013. stream->Release();
  1014. }
  1015. else
  1016. {
  1017. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1018. }
  1019. }
  1020. return ntStatus;
  1021. }
  1022. /*****************************************************************************
  1023. * CMiniportWaveCyclic::RestoreSampleRate()
  1024. *****************************************************************************
  1025. * Restores the sample rate.
  1026. */
  1027. STDMETHODIMP_(void) CMiniportWaveCyclicSB16::RestoreSampleRate (void)
  1028. {
  1029. if (AllocatedCapture)
  1030. {
  1031. _DbgPrintF(DEBUGLVL_VERBOSE, ("Restoring Capture Sample Rate"));
  1032. AdapterCommon->WriteController(DSP_CMD_SETADCRATE);
  1033. AdapterCommon->WriteController((BYTE)(SamplingFrequency >> 8));
  1034. AdapterCommon->WriteController((BYTE) SamplingFrequency);
  1035. }
  1036. if (AllocatedRender)
  1037. {
  1038. _DbgPrintF(DEBUGLVL_VERBOSE, ("Restoring Render Sample Rate"));
  1039. AdapterCommon->WriteController(DSP_CMD_SETDACRATE);
  1040. AdapterCommon->WriteController((BYTE)(SamplingFrequency >> 8));
  1041. AdapterCommon->WriteController((BYTE) SamplingFrequency);
  1042. }
  1043. }
  1044. /*****************************************************************************
  1045. * CMiniportWaveCyclicStreamSB16::NonDelegatingQueryInterface()
  1046. *****************************************************************************
  1047. * Obtains an interface. This function works just like a COM QueryInterface
  1048. * call and is used if the object is not being aggregated.
  1049. */
  1050. STDMETHODIMP
  1051. CMiniportWaveCyclicStreamSB16::
  1052. NonDelegatingQueryInterface
  1053. (
  1054. IN REFIID Interface,
  1055. OUT PVOID * Object
  1056. )
  1057. {
  1058. PAGED_CODE();
  1059. ASSERT(Object);
  1060. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::NonDelegatingQueryInterface]"));
  1061. if (IsEqualGUIDAligned(Interface,IID_IUnknown))
  1062. {
  1063. *Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
  1064. }
  1065. else
  1066. if (IsEqualGUIDAligned(Interface,IID_IMiniportWaveCyclicStream))
  1067. {
  1068. *Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
  1069. }
  1070. else
  1071. if (IsEqualGUIDAligned (Interface, IID_IDrmAudioStream))
  1072. {
  1073. *Object = (PVOID)(PDRMAUDIOSTREAM(this));
  1074. }
  1075. #if OVERRIDE_DMA_CHANNEL
  1076. else
  1077. if (IsEqualGUIDAligned (Interface, IID_IDmaChannel))
  1078. {
  1079. *Object = (PVOID)(PDMACHANNEL(this));
  1080. }
  1081. #endif // OVERRIDE_DMA_CHANNEL
  1082. else
  1083. {
  1084. *Object = NULL;
  1085. }
  1086. if (*Object)
  1087. {
  1088. PUNKNOWN(*Object)->AddRef();
  1089. return STATUS_SUCCESS;
  1090. }
  1091. return STATUS_INVALID_PARAMETER;
  1092. }
  1093. /*****************************************************************************
  1094. * CMiniportWaveCyclicStreamSB16::~CMiniportWaveCyclicStreamSB16()
  1095. *****************************************************************************
  1096. * Destructor.
  1097. */
  1098. CMiniportWaveCyclicStreamSB16::
  1099. ~CMiniportWaveCyclicStreamSB16
  1100. ( void
  1101. )
  1102. {
  1103. PAGED_CODE();
  1104. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::~CMiniportWaveCyclicStreamSB16]"));
  1105. if (DmaChannel)
  1106. {
  1107. DmaChannel->Release();
  1108. }
  1109. if (Miniport)
  1110. {
  1111. //
  1112. // Clear allocation flags in the miniport.
  1113. //
  1114. if (Capture)
  1115. {
  1116. Miniport->AllocatedCapture = FALSE;
  1117. }
  1118. else
  1119. {
  1120. Miniport->AllocatedRender = FALSE;
  1121. }
  1122. if (Format16Bit)
  1123. {
  1124. Miniport->Allocated16Bit = FALSE;
  1125. }
  1126. else
  1127. {
  1128. Miniport->Allocated8Bit = FALSE;
  1129. }
  1130. Miniport->AdapterCommon->SaveMixerSettingsToRegistry();
  1131. Miniport->Release();
  1132. }
  1133. }
  1134. /*****************************************************************************
  1135. * CMiniportWaveCyclicStreamSB16::Init()
  1136. *****************************************************************************
  1137. * Initializes a stream.
  1138. */
  1139. NTSTATUS
  1140. CMiniportWaveCyclicStreamSB16::
  1141. Init
  1142. (
  1143. IN CMiniportWaveCyclicSB16 * Miniport_,
  1144. IN ULONG Channel_,
  1145. IN BOOLEAN Capture_,
  1146. IN PKSDATAFORMAT DataFormat,
  1147. IN PDMACHANNELSLAVE DmaChannel_
  1148. )
  1149. {
  1150. PAGED_CODE();
  1151. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::Init]"));
  1152. ASSERT(Miniport_);
  1153. ASSERT(DataFormat);
  1154. ASSERT(NT_SUCCESS(Miniport_->ValidateFormat(DataFormat)));
  1155. ASSERT(DmaChannel_);
  1156. PWAVEFORMATEX waveFormat = PWAVEFORMATEX(DataFormat + 1);
  1157. //
  1158. // We must add references because the caller will not do it for us.
  1159. //
  1160. Miniport = Miniport_;
  1161. Miniport->AddRef();
  1162. DmaChannel = DmaChannel_;
  1163. DmaChannel->AddRef();
  1164. Channel = Channel_;
  1165. Capture = Capture_;
  1166. FormatStereo = (waveFormat->nChannels == 2);
  1167. Format16Bit = (waveFormat->wBitsPerSample == 16);
  1168. State = KSSTATE_STOP;
  1169. RestoreInputMixer = FALSE;
  1170. KeWaitForSingleObject
  1171. (
  1172. &Miniport->SampleRateSync,
  1173. Executive,
  1174. KernelMode,
  1175. FALSE,
  1176. NULL
  1177. );
  1178. Miniport->SamplingFrequency = waveFormat->nSamplesPerSec;
  1179. KeReleaseMutex(&Miniport->SampleRateSync,FALSE);
  1180. return SetFormat( DataFormat );
  1181. }
  1182. /*****************************************************************************
  1183. * CMiniportWaveCyclicStreamSB16::SetNotificationFreq()
  1184. *****************************************************************************
  1185. * Sets the notification frequency.
  1186. */
  1187. STDMETHODIMP_(ULONG)
  1188. CMiniportWaveCyclicStreamSB16::
  1189. SetNotificationFreq
  1190. (
  1191. IN ULONG Interval,
  1192. OUT PULONG FramingSize
  1193. )
  1194. {
  1195. PAGED_CODE();
  1196. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::SetNotificationFreq]"));
  1197. Miniport->NotificationInterval = Interval;
  1198. //
  1199. // This value needs to be sample block aligned for DMA to work correctly.
  1200. //
  1201. *FramingSize =
  1202. (1 << (FormatStereo + Format16Bit)) *
  1203. (Miniport->SamplingFrequency * Interval / 1000);
  1204. return Miniport->NotificationInterval;
  1205. }
  1206. /*****************************************************************************
  1207. * CMiniportWaveCyclicStreamSB16::SetFormat()
  1208. *****************************************************************************
  1209. * Sets the wave format.
  1210. */
  1211. STDMETHODIMP
  1212. CMiniportWaveCyclicStreamSB16::
  1213. SetFormat
  1214. (
  1215. IN PKSDATAFORMAT Format
  1216. )
  1217. {
  1218. PAGED_CODE();
  1219. ASSERT(Format);
  1220. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::SetFormat]"));
  1221. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1222. if(State != KSSTATE_RUN)
  1223. {
  1224. ntStatus = Miniport->ValidateFormat(Format);
  1225. PWAVEFORMATEX waveFormat = PWAVEFORMATEX(Format + 1);
  1226. KeWaitForSingleObject
  1227. (
  1228. &Miniport->SampleRateSync,
  1229. Executive,
  1230. KernelMode,
  1231. FALSE,
  1232. NULL
  1233. );
  1234. // check for full-duplex stuff
  1235. if( NT_SUCCESS(ntStatus)
  1236. && Miniport->AllocatedCapture
  1237. && Miniport->AllocatedRender
  1238. )
  1239. {
  1240. // no new formats.... bad...
  1241. if( Miniport->SamplingFrequency != waveFormat->nSamplesPerSec )
  1242. {
  1243. // Bad format....
  1244. ntStatus = STATUS_INVALID_PARAMETER;
  1245. }
  1246. }
  1247. // TODO: Validate sample size.
  1248. if (NT_SUCCESS(ntStatus))
  1249. {
  1250. Miniport->SamplingFrequency = waveFormat->nSamplesPerSec;
  1251. BYTE command =
  1252. ( Capture
  1253. ? DSP_CMD_SETADCRATE
  1254. : DSP_CMD_SETDACRATE
  1255. );
  1256. Miniport->AdapterCommon->WriteController
  1257. (
  1258. command
  1259. );
  1260. Miniport->AdapterCommon->WriteController
  1261. (
  1262. (BYTE)(waveFormat->nSamplesPerSec >> 8)
  1263. );
  1264. Miniport->AdapterCommon->WriteController
  1265. (
  1266. (BYTE) waveFormat->nSamplesPerSec
  1267. );
  1268. _DbgPrintF(DEBUGLVL_VERBOSE,(" SampleRate: %d",waveFormat->nSamplesPerSec));
  1269. }
  1270. KeReleaseMutex(&Miniport->SampleRateSync,FALSE);
  1271. }
  1272. return ntStatus;
  1273. }
  1274. /*****************************************************************************
  1275. * CMiniportWaveCyclicStreamSB16::SetState()
  1276. *****************************************************************************
  1277. * Sets the state of the channel.
  1278. */
  1279. STDMETHODIMP
  1280. CMiniportWaveCyclicStreamSB16::
  1281. SetState
  1282. (
  1283. IN KSSTATE NewState
  1284. )
  1285. {
  1286. PAGED_CODE();
  1287. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::SetState %x]", NewState));
  1288. NTSTATUS ntStatus = STATUS_SUCCESS;
  1289. //
  1290. // The acquire state is not distinguishable from the pause state for our
  1291. // purposes.
  1292. //
  1293. if (NewState == KSSTATE_ACQUIRE)
  1294. {
  1295. NewState = KSSTATE_PAUSE;
  1296. }
  1297. if (State != NewState)
  1298. {
  1299. switch (NewState)
  1300. {
  1301. case KSSTATE_PAUSE:
  1302. if (State == KSSTATE_RUN)
  1303. {
  1304. if (Capture)
  1305. {
  1306. // restore if previously setup for mono recording
  1307. // (this should really be done via the topology miniport)
  1308. if(RestoreInputMixer)
  1309. {
  1310. Miniport->AdapterCommon->MixerRegWrite( DSP_MIX_ADCMIXIDX_L,
  1311. InputMixerLeft );
  1312. RestoreInputMixer = FALSE;
  1313. }
  1314. }
  1315. // TODO: Wait for DMA to complete
  1316. if (Format16Bit)
  1317. {
  1318. Miniport->AdapterCommon->WriteController(DSP_CMD_HALTAUTODMA16);
  1319. // TODO: wait...
  1320. Miniport->AdapterCommon->WriteController(DSP_CMD_PAUSEDMA16);
  1321. }
  1322. else
  1323. {
  1324. Miniport->AdapterCommon->WriteController(DSP_CMD_HALTAUTODMA);
  1325. // TODO: wait...
  1326. Miniport->AdapterCommon->WriteController(DSP_CMD_PAUSEDMA);
  1327. }
  1328. Miniport->AdapterCommon->WriteController(DSP_CMD_SPKROFF);
  1329. DmaChannel->Stop();
  1330. }
  1331. break;
  1332. case KSSTATE_RUN:
  1333. {
  1334. BYTE mode;
  1335. if (Capture)
  1336. {
  1337. // setup for mono recording
  1338. // (this should really be done via the topology miniport)
  1339. if(! FormatStereo)
  1340. {
  1341. InputMixerLeft = Miniport->AdapterCommon->MixerRegRead( DSP_MIX_ADCMIXIDX_L );
  1342. UCHAR InputMixerRight = Miniport->AdapterCommon->MixerRegRead( DSP_MIX_ADCMIXIDX_R );
  1343. UCHAR TempMixerValue = InputMixerLeft | (InputMixerRight & 0x2A);
  1344. Miniport->AdapterCommon->MixerRegWrite( DSP_MIX_ADCMIXIDX_L,
  1345. TempMixerValue );
  1346. RestoreInputMixer = TRUE;
  1347. }
  1348. //
  1349. // Turn on capture.
  1350. //
  1351. Miniport->AdapterCommon->WriteController(DSP_CMD_SPKROFF);
  1352. if (Format16Bit)
  1353. {
  1354. Miniport->AdapterCommon->WriteController(DSP_CMD_STARTADC16);
  1355. mode = 0x10;
  1356. }
  1357. else
  1358. {
  1359. Miniport->AdapterCommon->WriteController(DSP_CMD_STARTADC8);
  1360. mode = 0x00;
  1361. }
  1362. }
  1363. else
  1364. {
  1365. Miniport->AdapterCommon->WriteController(DSP_CMD_SPKRON);
  1366. if (Format16Bit)
  1367. {
  1368. Miniport->AdapterCommon->WriteController(DSP_CMD_STARTDAC16);
  1369. mode = 0x10;
  1370. }
  1371. else
  1372. {
  1373. Miniport->AdapterCommon->WriteController(DSP_CMD_STARTDAC8);
  1374. mode = 0x00;
  1375. }
  1376. }
  1377. if (FormatStereo)
  1378. {
  1379. mode |= 0x20;
  1380. }
  1381. //
  1382. // Start DMA.
  1383. //
  1384. DmaChannel->Start(DmaChannel->BufferSize(),!Capture);
  1385. Miniport->AdapterCommon->WriteController(mode) ;
  1386. //
  1387. // Calculate sample count for interrupts.
  1388. //
  1389. ULONG bufferSizeInFrames = DmaChannel->BufferSize();
  1390. if( Format16Bit )
  1391. {
  1392. bufferSizeInFrames /= 2;
  1393. }
  1394. if( FormatStereo )
  1395. {
  1396. bufferSizeInFrames /= 2;
  1397. }
  1398. ULONG frameCount =
  1399. ((Miniport->SamplingFrequency * Miniport->NotificationInterval) / 1000);
  1400. if (frameCount > bufferSizeInFrames)
  1401. {
  1402. frameCount = bufferSizeInFrames;
  1403. }
  1404. frameCount--;
  1405. _DbgPrintF( DEBUGLVL_VERBOSE, ("Run. Setting frame count to %X",frameCount));
  1406. Miniport->AdapterCommon->WriteController((BYTE) frameCount) ;
  1407. Miniport->AdapterCommon->WriteController((BYTE) (frameCount >> 8));
  1408. }
  1409. break;
  1410. case KSSTATE_STOP:
  1411. break;
  1412. }
  1413. State = NewState;
  1414. }
  1415. return ntStatus;
  1416. }
  1417. /*****************************************************************************
  1418. * CMiniportWaveCyclicStreamSB16::SetContentId
  1419. *****************************************************************************
  1420. * This routine gets called by drmk.sys to pass the content to the driver.
  1421. * The driver has to enforce the rights passed.
  1422. */
  1423. STDMETHODIMP_(NTSTATUS)
  1424. CMiniportWaveCyclicStreamSB16::SetContentId
  1425. (
  1426. IN ULONG contentId,
  1427. IN PCDRMRIGHTS drmRights
  1428. )
  1429. {
  1430. PAGED_CODE ();
  1431. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportWaveCyclicStreamSB16::SetContentId]"));
  1432. //
  1433. // if (drmRights.CopyProtect==TRUE)
  1434. // Mute waveout capture.
  1435. // Sb16 does not have waveout capture path. Therefore
  1436. // the sample driver is not using this attribute.
  1437. // Also if the driver is writing data to other types of media (disk, etc), it
  1438. // should stop doing it.
  1439. // (MSVAD\simple stops writing to disk).
  1440. // (AC97 disables waveout capture)
  1441. //
  1442. // if (drmRights.DigitalOutputDisable == TRUE)
  1443. // Mute S/PDIF out.
  1444. // If the device cannot mute S/PDIF out properly, it should return an error
  1445. // code.
  1446. // Sb16 does not have S/PDIF out. Therefore the sample driver is not using
  1447. // this attribute.
  1448. //
  1449. //
  1450. // To learn more about enforcing rights, please look at AC97 sample.
  1451. //
  1452. // To learn more about managing multiple streams, please look at MSVAD.
  1453. //
  1454. return STATUS_SUCCESS;
  1455. }
  1456. #pragma code_seg()
  1457. /*****************************************************************************
  1458. * CMiniportWaveCyclicStreamSB16::GetPosition()
  1459. *****************************************************************************
  1460. * Gets the current position. May be called at dispatch level.
  1461. */
  1462. STDMETHODIMP
  1463. CMiniportWaveCyclicStreamSB16::
  1464. GetPosition
  1465. (
  1466. OUT PULONG Position
  1467. )
  1468. {
  1469. ASSERT(Position);
  1470. ULONG transferCount = DmaChannel->TransferCount();
  1471. if (DmaChannel && transferCount)
  1472. {
  1473. *Position = DmaChannel->ReadCounter();
  1474. ASSERT(*Position <= transferCount);
  1475. if (*Position != 0)
  1476. {
  1477. *Position = transferCount - *Position;
  1478. }
  1479. }
  1480. else
  1481. {
  1482. *Position = 0;
  1483. }
  1484. return STATUS_SUCCESS;
  1485. }
  1486. STDMETHODIMP
  1487. CMiniportWaveCyclicStreamSB16::NormalizePhysicalPosition(
  1488. IN OUT PLONGLONG PhysicalPosition
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. Given a physical position based on the actual number of bytes transferred,
  1493. this function converts the position to a time-based value of 100ns units.
  1494. Arguments:
  1495. IN OUT PLONGLONG PhysicalPosition -
  1496. value to convert.
  1497. Return:
  1498. STATUS_SUCCESS or an appropriate error code.
  1499. --*/
  1500. {
  1501. *PhysicalPosition =
  1502. (_100NS_UNITS_PER_SECOND /
  1503. (1 << (FormatStereo + Format16Bit)) * *PhysicalPosition) /
  1504. Miniport->SamplingFrequency;
  1505. return STATUS_SUCCESS;
  1506. }
  1507. /*****************************************************************************
  1508. * CMiniportWaveCyclicStreamSB16::Silence()
  1509. *****************************************************************************
  1510. * Fills a buffer with silence.
  1511. */
  1512. STDMETHODIMP_(void)
  1513. CMiniportWaveCyclicStreamSB16::
  1514. Silence
  1515. (
  1516. IN PVOID Buffer,
  1517. IN ULONG ByteCount
  1518. )
  1519. {
  1520. RtlFillMemory(Buffer,ByteCount,Format16Bit ? 0 : 0x80);
  1521. }
  1522. /*****************************************************************************
  1523. * CMiniportWaveCyclicStreamSB16::ServiceWaveISR()
  1524. *****************************************************************************
  1525. * Service the ISR - notify the port.
  1526. */
  1527. STDMETHODIMP_(void) CMiniportWaveCyclicSB16::ServiceWaveISR (void)
  1528. {
  1529. if (Port && ServiceGroup)
  1530. {
  1531. Port->Notify (ServiceGroup);
  1532. }
  1533. }
  1534. #if OVERRIDE_DMA_CHANNEL
  1535. #pragma code_seg("PAGE")
  1536. /*****************************************************************************
  1537. * CMiniportWaveCyclicStreamSB16::AllocateBuffer()
  1538. *****************************************************************************
  1539. * Allocate a buffer for this DMA channel.
  1540. */
  1541. STDMETHODIMP
  1542. CMiniportWaveCyclicStreamSB16::AllocateBuffer
  1543. (
  1544. IN ULONG BufferSize,
  1545. IN PPHYSICAL_ADDRESS PhysicalAddressConstraint OPTIONAL
  1546. )
  1547. {
  1548. PAGED_CODE();
  1549. return DmaChannel->AllocateBuffer(BufferSize,PhysicalAddressConstraint);
  1550. }
  1551. /*****************************************************************************
  1552. * CMiniportWaveCyclicStreamSB16::FreeBuffer()
  1553. *****************************************************************************
  1554. * Free the buffer for this DMA channel.
  1555. */
  1556. STDMETHODIMP_(void)
  1557. CMiniportWaveCyclicStreamSB16::FreeBuffer(void)
  1558. {
  1559. PAGED_CODE();
  1560. DmaChannel->FreeBuffer();
  1561. }
  1562. #pragma code_seg()
  1563. /*****************************************************************************
  1564. * CMiniportWaveCyclicStreamSB16::TransferCount()
  1565. *****************************************************************************
  1566. * Return the amount of data to be transfered via DMA.
  1567. */
  1568. STDMETHODIMP_(ULONG)
  1569. CMiniportWaveCyclicStreamSB16::TransferCount(void)
  1570. {
  1571. return DmaChannel->TransferCount();
  1572. }
  1573. /*****************************************************************************
  1574. * CMiniportWaveCyclicStreamSB16::MaximumBufferSize()
  1575. *****************************************************************************
  1576. * Return the maximum size that can be allocated to this DMA buffer.
  1577. */
  1578. STDMETHODIMP_(ULONG)
  1579. CMiniportWaveCyclicStreamSB16::MaximumBufferSize(void)
  1580. {
  1581. return DmaChannel->MaximumBufferSize();
  1582. }
  1583. /*****************************************************************************
  1584. * CMiniportWaveCyclicStreamSB16::AllocatedBufferSize()
  1585. *****************************************************************************
  1586. * Return the original size allocated to this DMA buffer -- the maximum value
  1587. * that can be sent to SetBufferSize().
  1588. */
  1589. STDMETHODIMP_(ULONG)
  1590. CMiniportWaveCyclicStreamSB16::AllocatedBufferSize(void)
  1591. {
  1592. return DmaChannel->AllocatedBufferSize();
  1593. }
  1594. /*****************************************************************************
  1595. * CMiniportWaveCyclicStreamSB16::BufferSize()
  1596. *****************************************************************************
  1597. * Return the current size of the DMA buffer.
  1598. */
  1599. STDMETHODIMP_(ULONG)
  1600. CMiniportWaveCyclicStreamSB16::BufferSize(void)
  1601. {
  1602. return DmaChannel->BufferSize();
  1603. }
  1604. /*****************************************************************************
  1605. * CMiniportWaveCyclicStreamSB16::SetBufferSize()
  1606. *****************************************************************************
  1607. * Change the size of the DMA buffer. This cannot exceed the initial
  1608. * buffer size returned by AllocatedBufferSize().
  1609. */
  1610. STDMETHODIMP_(void)
  1611. CMiniportWaveCyclicStreamSB16::SetBufferSize(IN ULONG BufferSize)
  1612. {
  1613. DmaChannel->SetBufferSize(BufferSize);
  1614. }
  1615. /*****************************************************************************
  1616. * CMiniportWaveCyclicStreamSB16::SystemAddress()
  1617. *****************************************************************************
  1618. * Return the virtual address of this DMA buffer.
  1619. */
  1620. STDMETHODIMP_(PVOID)
  1621. CMiniportWaveCyclicStreamSB16::SystemAddress(void)
  1622. {
  1623. return DmaChannel->SystemAddress();
  1624. }
  1625. /*****************************************************************************
  1626. * CMiniportWaveCyclicStreamSB16::PhysicalAddress()
  1627. *****************************************************************************
  1628. * Return the actual physical address of this DMA buffer.
  1629. */
  1630. STDMETHODIMP_(PHYSICAL_ADDRESS)
  1631. CMiniportWaveCyclicStreamSB16::PhysicalAddress(void)
  1632. {
  1633. return DmaChannel->PhysicalAddress();
  1634. }
  1635. /*****************************************************************************
  1636. * CMiniportWaveCyclicStreamSB16::GetAdapterObject()
  1637. *****************************************************************************
  1638. * Return the DMA adapter object (defined in wdm.h).
  1639. */
  1640. STDMETHODIMP_(PADAPTER_OBJECT)
  1641. CMiniportWaveCyclicStreamSB16::GetAdapterObject(void)
  1642. {
  1643. return DmaChannel->GetAdapterObject();
  1644. }
  1645. /*****************************************************************************
  1646. * CMiniportWaveCyclicStreamSB16::CopyTo()
  1647. *****************************************************************************
  1648. * Copy data into the DMA buffer. If you need to modify data on render
  1649. * (playback), modify this routine to taste.
  1650. */
  1651. STDMETHODIMP_(void)
  1652. CMiniportWaveCyclicStreamSB16::CopyTo
  1653. (
  1654. IN PVOID Destination,
  1655. IN PVOID Source,
  1656. IN ULONG ByteCount
  1657. )
  1658. {
  1659. DmaChannel->CopyTo(Destination, Source, ByteCount);
  1660. }
  1661. /*****************************************************************************
  1662. * CMiniportWaveCyclicStreamSB16::CopyFrom()
  1663. *****************************************************************************
  1664. * Copy data out of the DMA buffer. If you need to modify data on capture
  1665. * (recording), modify this routine to taste.
  1666. */
  1667. STDMETHODIMP_(void)
  1668. CMiniportWaveCyclicStreamSB16::CopyFrom
  1669. (
  1670. IN PVOID Destination,
  1671. IN PVOID Source,
  1672. IN ULONG ByteCount
  1673. )
  1674. {
  1675. DmaChannel->CopyFrom(Destination, Source, ByteCount);
  1676. }
  1677. #endif // OVERRIDE_DMA_CHANNEL