Leaked source code of windows server 2003
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.

1878 lines
59 KiB

  1. /*****************************************************************************
  2. * porthelp.cpp - WDM Streaming port class driver port helper functions
  3. *****************************************************************************
  4. * Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #include "private.h"
  7. /*****************************************************************************
  8. * Functions.
  9. */
  10. #pragma code_seg("PAGE")
  11. static
  12. KSPIN_MEDIUM PinMediums[] =
  13. {
  14. {
  15. STATICGUIDOF(KSMEDIUMSETID_Standard),
  16. KSMEDIUM_STANDARD_DEVIO,
  17. 0
  18. }
  19. };
  20. #define UPTOQUAD(x) (((x)+7)&~7)
  21. /*****************************************************************************
  22. * PrivateHeap
  23. *****************************************************************************
  24. * Class for managing a private heap.
  25. */
  26. class PrivateHeap
  27. {
  28. private:
  29. PBYTE m_pbTop;
  30. PBYTE m_pbCurrent;
  31. ULONG m_ulSize;
  32. public:
  33. PrivateHeap(void) : m_pbTop(NULL),
  34. m_pbCurrent(NULL),
  35. m_ulSize(NULL)
  36. {
  37. }
  38. //
  39. // Increase the number of bytes that will be allocated for the heap.
  40. //
  41. ULONG Reserve(ULONG ulBytes)
  42. {
  43. ASSERT(! m_pbTop);
  44. ASSERT(! m_pbCurrent);
  45. m_ulSize += UPTOQUAD(ulBytes);
  46. return m_ulSize;
  47. }
  48. //
  49. // Allocate memory for the private heap from a pool.
  50. //
  51. NTSTATUS AllocateFromPool(POOL_TYPE poolType,ULONG ulTag)
  52. {
  53. ASSERT(! m_pbTop);
  54. ASSERT(! m_pbCurrent);
  55. ASSERT(m_ulSize);
  56. m_pbTop = new(poolType,ulTag) BYTE[m_ulSize];
  57. if (! m_pbTop)
  58. {
  59. return STATUS_INSUFFICIENT_RESOURCES;
  60. }
  61. m_pbCurrent = m_pbTop;
  62. return STATUS_SUCCESS;
  63. }
  64. //
  65. // Allocate memory from the heap.
  66. //
  67. PVOID Alloc(ULONG ulSize)
  68. {
  69. ASSERT(ulSize);
  70. ASSERT(m_pbTop);
  71. ASSERT(m_pbCurrent);
  72. ASSERT(m_pbCurrent + UPTOQUAD(ulSize) <= m_pbTop + m_ulSize);
  73. PVOID pvResult = PVOID(m_pbCurrent);
  74. m_pbCurrent += UPTOQUAD(ulSize);
  75. return pvResult;
  76. }
  77. //
  78. // Determine the amount of space remaining in the heap.
  79. //
  80. ULONG BytesRemaining(void)
  81. {
  82. ASSERT(m_pbTop);
  83. ASSERT(m_pbCurrent);
  84. ASSERT(m_pbCurrent <= m_pbTop + m_ulSize);
  85. return ULONG((m_pbTop + m_ulSize) - m_pbCurrent);
  86. }
  87. };
  88. /*****************************************************************************
  89. * ::new()
  90. *****************************************************************************
  91. * New function for creating objects with private heap.
  92. */
  93. inline PVOID operator new
  94. (
  95. size_t iSize,
  96. PrivateHeap& privateHeap
  97. )
  98. {
  99. return privateHeap.Alloc(ULONG(iSize));
  100. }
  101. /*****************************************************************************
  102. * MeasureDataRanges()
  103. *****************************************************************************
  104. * Determine how much a set of data ranges will expand as a result
  105. * of cloning WAVEFORMATEX ranges into identical DSOUND ranges.
  106. *
  107. * As of WinME, we also clone non-PCM ranges.
  108. */
  109. static
  110. ULONG
  111. MeasureDataRanges
  112. (
  113. IN PrivateHeap * pPrivateHeap OPTIONAL,
  114. IN ULONG ulDataRangeCountIn,
  115. IN KSDATARANGE *const * ppKsDataRangeIn
  116. )
  117. {
  118. ULONG ulNewDataRangeCount = ulDataRangeCountIn;
  119. for (ULONG ul = ulDataRangeCountIn; ul--; )
  120. {
  121. ASSERT(ppKsDataRangeIn);
  122. if ( ( (*ppKsDataRangeIn)->FormatSize
  123. >= sizeof(KSDATAFORMAT_WAVEFORMATEX)
  124. )
  125. && IsEqualGUIDAligned
  126. ( (*ppKsDataRangeIn)->MajorFormat,
  127. KSDATAFORMAT_TYPE_AUDIO
  128. )
  129. && IsEqualGUIDAligned
  130. ( (*ppKsDataRangeIn)->Specifier,
  131. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
  132. )
  133. )
  134. {
  135. ulNewDataRangeCount++;
  136. if (pPrivateHeap)
  137. {
  138. pPrivateHeap->Reserve((*ppKsDataRangeIn)->FormatSize);
  139. }
  140. }
  141. ppKsDataRangeIn++;
  142. }
  143. if (pPrivateHeap && (ulNewDataRangeCount != ulDataRangeCountIn))
  144. {
  145. pPrivateHeap->Reserve(ulNewDataRangeCount * sizeof(PKSDATARANGE));
  146. }
  147. return ulNewDataRangeCount;
  148. }
  149. /*****************************************************************************
  150. * CloneDataRanges()
  151. *****************************************************************************
  152. * Expand data ranges to include DSound formats.
  153. */
  154. static
  155. const PKSDATARANGE *
  156. CloneDataRanges
  157. (
  158. IN PrivateHeap& privateHeap,
  159. OUT PULONG pulDataRangeCountOut,
  160. IN ULONG ulDataRangeCountIn,
  161. IN KSDATARANGE *const * ppKsDataRangeIn
  162. )
  163. {
  164. ASSERT(pulDataRangeCountOut);
  165. //
  166. // Determine how many data ranges there will be and how much space will be
  167. // required for the new ones.
  168. //
  169. ULONG ulDataRangeCountOut =
  170. MeasureDataRanges(NULL,ulDataRangeCountIn,ppKsDataRangeIn);
  171. const PKSDATARANGE *ppKsDataRangeOut;
  172. if (ulDataRangeCountOut == ulDataRangeCountIn)
  173. {
  174. //
  175. // No new data ranges. Use the array we were given.
  176. //
  177. ppKsDataRangeOut = ppKsDataRangeIn;
  178. }
  179. else
  180. {
  181. //
  182. // Allocate some space for the new array.
  183. //
  184. ppKsDataRangeOut = new(privateHeap) PKSDATARANGE[ulDataRangeCountOut];
  185. //
  186. // Build the new array.
  187. //
  188. PKSDATARANGE *ppKsDataRange = (PKSDATARANGE *) ppKsDataRangeOut;
  189. while (ulDataRangeCountIn--)
  190. {
  191. ASSERT(ppKsDataRangeIn);
  192. //
  193. // All the data ranges get copied.
  194. //
  195. *ppKsDataRange++ = *ppKsDataRangeIn;
  196. //
  197. // Check for WaveFormatEx datarange
  198. // This includes non-PCM subformats....
  199. //
  200. if ( ( (*ppKsDataRangeIn)->FormatSize
  201. >= sizeof(KSDATAFORMAT_WAVEFORMATEX)
  202. )
  203. && IsEqualGUIDAligned
  204. ( (*ppKsDataRangeIn)->MajorFormat,
  205. KSDATAFORMAT_TYPE_AUDIO
  206. )
  207. && IsEqualGUIDAligned
  208. ( (*ppKsDataRangeIn)->Specifier,
  209. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
  210. )
  211. )
  212. {
  213. //
  214. // WaveFormatEx datarange will require DSound clone.
  215. // Allocate memory for it and copy.
  216. //
  217. *ppKsDataRange =
  218. PKSDATARANGE
  219. (
  220. new(privateHeap) BYTE[(*ppKsDataRangeIn)->FormatSize]
  221. );
  222. RtlCopyMemory
  223. (
  224. *ppKsDataRange,
  225. *ppKsDataRangeIn,
  226. (*ppKsDataRangeIn)->FormatSize
  227. );
  228. //
  229. // Update the specifier.
  230. //
  231. (*ppKsDataRange++)->Specifier =
  232. KSDATAFORMAT_SPECIFIER_DSOUND;
  233. }
  234. //
  235. // Increment input position
  236. //
  237. ppKsDataRangeIn++;
  238. }
  239. }
  240. *pulDataRangeCountOut = ulDataRangeCountOut;
  241. return ppKsDataRangeOut;
  242. }
  243. /*****************************************************************************
  244. * PcCreateSubdeviceDescriptor()
  245. *****************************************************************************
  246. * Creates a subdevice descriptor.
  247. */
  248. PORTCLASSAPI
  249. NTSTATUS
  250. NTAPI
  251. PcCreateSubdeviceDescriptor
  252. (
  253. IN PPCFILTER_DESCRIPTOR pPcFilterDescriptor,
  254. IN ULONG CategoriesCount,
  255. IN GUID * Categories,
  256. IN ULONG StreamInterfacesCount,
  257. IN PKSPIN_INTERFACE StreamInterfaces,
  258. IN ULONG FilterPropertySetCount,
  259. IN PKSPROPERTY_SET FilterPropertySets,
  260. IN ULONG FilterEventSetCount,
  261. IN PKSEVENT_SET FilterEventSets,
  262. IN ULONG PinPropertySetCount,
  263. IN PKSPROPERTY_SET PinPropertySets,
  264. IN ULONG PinEventSetCount,
  265. IN PKSEVENT_SET PinEventSets,
  266. OUT PSUBDEVICE_DESCRIPTOR * OutDescriptor
  267. )
  268. {
  269. PAGED_CODE();
  270. ASSERT(pPcFilterDescriptor);
  271. ASSERT(OutDescriptor);
  272. NTSTATUS ntStatus = STATUS_SUCCESS;
  273. //
  274. // Calculate how much memory we will need.
  275. //
  276. PrivateHeap privateHeap;
  277. privateHeap.Reserve(sizeof(SUBDEVICE_DESCRIPTOR));
  278. privateHeap.Reserve(sizeof(KSTOPOLOGY));
  279. privateHeap.Reserve(sizeof(KSPIN_DESCRIPTOR) * pPcFilterDescriptor->PinCount);
  280. privateHeap.Reserve(sizeof(PIN_CINSTANCES) * pPcFilterDescriptor->PinCount);
  281. privateHeap.Reserve(sizeof(PROPERTY_TABLE) * pPcFilterDescriptor->PinCount);
  282. privateHeap.Reserve(sizeof(EVENT_TABLE) * pPcFilterDescriptor->PinCount);
  283. if (pPcFilterDescriptor->NodeCount)
  284. {
  285. privateHeap.Reserve(sizeof(GUID) * pPcFilterDescriptor->NodeCount);
  286. privateHeap.Reserve(sizeof(GUID) * pPcFilterDescriptor->NodeCount);
  287. }
  288. const PCPIN_DESCRIPTOR *pPcPinDescriptor = pPcFilterDescriptor->Pins;
  289. for (ULONG ul = pPcFilterDescriptor->PinCount; ul--; )
  290. {
  291. if (pPcPinDescriptor->KsPinDescriptor.DataRanges)
  292. {
  293. MeasureDataRanges( &privateHeap,
  294. pPcPinDescriptor->KsPinDescriptor.DataRangesCount,
  295. pPcPinDescriptor->KsPinDescriptor.DataRanges );
  296. pPcPinDescriptor = PPCPIN_DESCRIPTOR( PBYTE(pPcPinDescriptor) + pPcFilterDescriptor->PinSize );
  297. }
  298. else
  299. {
  300. ntStatus = STATUS_RANGE_NOT_FOUND; // DataRanges field is NULL
  301. break; // Don't even bother, just exit
  302. }
  303. }
  304. if (NT_SUCCESS(ntStatus)) // if fail above, fall through the rest
  305. {
  306. //
  307. // Allocate the required memory.
  308. //
  309. ntStatus = privateHeap.AllocateFromPool(PagedPool,'pFcP');
  310. }
  311. if (NT_SUCCESS(ntStatus))
  312. {
  313. PSUBDEVICE_DESCRIPTOR descr = new(privateHeap) SUBDEVICE_DESCRIPTOR;
  314. //
  315. // Set up pointers into one big chunk of memory.
  316. //
  317. descr->PinCount = pPcFilterDescriptor->PinCount;
  318. descr->Topology = new(privateHeap) KSTOPOLOGY;
  319. descr->PinDescriptors = new(privateHeap) KSPIN_DESCRIPTOR[descr->PinCount];
  320. descr->PinInstances = new(privateHeap) PIN_CINSTANCES[descr->PinCount];
  321. descr->PinPropertyTables = new(privateHeap) PROPERTY_TABLE[descr->PinCount];
  322. descr->PinEventTables = new(privateHeap) EVENT_TABLE[descr->PinCount];
  323. if (pPcFilterDescriptor->NodeCount)
  324. {
  325. descr->Topology->TopologyNodes =
  326. new(privateHeap) GUID[pPcFilterDescriptor->NodeCount];
  327. descr->Topology->TopologyNodesNames =
  328. new(privateHeap) GUID[pPcFilterDescriptor->NodeCount];
  329. }
  330. else
  331. {
  332. descr->Topology->TopologyNodes = NULL;
  333. descr->Topology->TopologyNodesNames = NULL;
  334. }
  335. //
  336. // Prefer the categories from the filter descriptor.
  337. //
  338. if (pPcFilterDescriptor->CategoryCount != 0)
  339. {
  340. descr->Topology->CategoriesCount = pPcFilterDescriptor->CategoryCount;
  341. descr->Topology->Categories = pPcFilterDescriptor->Categories;
  342. }
  343. else
  344. {
  345. descr->Topology->CategoriesCount = CategoriesCount;
  346. descr->Topology->Categories = Categories;
  347. }
  348. descr->Topology->TopologyNodesCount = pPcFilterDescriptor->NodeCount;
  349. descr->Topology->TopologyConnectionsCount = pPcFilterDescriptor->ConnectionCount;
  350. descr->Topology->TopologyConnections = pPcFilterDescriptor->Connections;
  351. //
  352. // Initialize filter properties.
  353. //
  354. descr->FilterPropertyTable.PropertySetCount = FilterPropertySetCount;
  355. descr->FilterPropertyTable.PropertySets = FilterPropertySets;
  356. descr->FilterPropertyTable.StaticSets = TRUE;
  357. //
  358. // Initialize filter events.
  359. //
  360. descr->FilterEventTable.EventSetCount = FilterEventSetCount;
  361. descr->FilterEventTable.EventSets = FilterEventSets;
  362. descr->FilterEventTable.StaticSets = TRUE;
  363. //
  364. // Copy node type and name and merge node properties and events.
  365. //
  366. const PCNODE_DESCRIPTOR *pPcNodeDescriptor = pPcFilterDescriptor->Nodes;
  367. GUID *pGuidType = (GUID *) descr->Topology->TopologyNodes;
  368. GUID *pGuidName = (GUID *) descr->Topology->TopologyNodesNames;
  369. for (ULONG node = pPcFilterDescriptor->NodeCount; node--; )
  370. {
  371. *pGuidType++ = *pPcNodeDescriptor->Type;
  372. if (pPcNodeDescriptor->Name)
  373. {
  374. *pGuidName++ = *pPcNodeDescriptor->Name;
  375. }
  376. else
  377. {
  378. *pGuidName++ = *pPcNodeDescriptor->Type;
  379. }
  380. if ( (pPcNodeDescriptor->AutomationTable)
  381. && (pPcNodeDescriptor->AutomationTable->PropertyCount)
  382. )
  383. {
  384. PcAddToPropertyTable
  385. (
  386. &descr->FilterPropertyTable,
  387. pPcNodeDescriptor->AutomationTable->PropertyCount,
  388. pPcNodeDescriptor->AutomationTable->Properties,
  389. pPcNodeDescriptor->AutomationTable->PropertyItemSize,
  390. TRUE
  391. );
  392. }
  393. if ( (pPcNodeDescriptor->AutomationTable)
  394. && (pPcNodeDescriptor->AutomationTable->EventCount)
  395. )
  396. {
  397. PcAddToEventTable
  398. (
  399. &descr->FilterEventTable,
  400. pPcNodeDescriptor->AutomationTable->EventCount,
  401. pPcNodeDescriptor->AutomationTable->Events,
  402. pPcNodeDescriptor->AutomationTable->EventItemSize,
  403. TRUE
  404. );
  405. }
  406. pPcNodeDescriptor =
  407. PPCNODE_DESCRIPTOR
  408. ( PBYTE(pPcNodeDescriptor) + pPcFilterDescriptor->NodeSize
  409. );
  410. }
  411. //
  412. // Merge filter properties.
  413. //
  414. if ( (pPcFilterDescriptor->AutomationTable)
  415. && (pPcFilterDescriptor->AutomationTable->PropertyCount)
  416. )
  417. {
  418. PcAddToPropertyTable
  419. (
  420. &descr->FilterPropertyTable,
  421. pPcFilterDescriptor->AutomationTable->PropertyCount,
  422. pPcFilterDescriptor->AutomationTable->Properties,
  423. pPcFilterDescriptor->AutomationTable->PropertyItemSize,
  424. FALSE
  425. );
  426. }
  427. //
  428. // Merge filter events.
  429. //
  430. if ( (pPcFilterDescriptor->AutomationTable)
  431. && (pPcFilterDescriptor->AutomationTable->EventCount)
  432. )
  433. {
  434. PcAddToEventTable
  435. (
  436. &descr->FilterEventTable,
  437. pPcFilterDescriptor->AutomationTable->EventCount,
  438. pPcFilterDescriptor->AutomationTable->Events,
  439. pPcFilterDescriptor->AutomationTable->EventItemSize,
  440. FALSE
  441. );
  442. }
  443. //
  444. // Do per-pin stuff.
  445. //
  446. PPROPERTY_TABLE pt = descr->PinPropertyTables;
  447. PEVENT_TABLE et = descr->PinEventTables;
  448. PKSPIN_DESCRIPTOR p = descr->PinDescriptors;
  449. PPIN_CINSTANCES i = descr->PinInstances;
  450. pPcPinDescriptor = PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
  451. for
  452. (
  453. ULONG pin = 0;
  454. pin < pPcFilterDescriptor->PinCount;
  455. pin++
  456. )
  457. {
  458. //
  459. // Find a pin that has the same property set.
  460. //
  461. PPROPERTY_TABLE twinPt = descr->PinPropertyTables;
  462. PPCPIN_DESCRIPTOR pPcPinDescriptorTwin =
  463. PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
  464. for
  465. (
  466. ULONG twinPin = 0;
  467. twinPin < pin;
  468. twinPin++, twinPt++
  469. )
  470. {
  471. if ( ( pPcPinDescriptor->AutomationTable
  472. == pPcPinDescriptorTwin->AutomationTable
  473. )
  474. || ( pPcPinDescriptor->AutomationTable
  475. && pPcPinDescriptorTwin->AutomationTable
  476. && ( pPcPinDescriptor->AutomationTable->PropertyCount
  477. == pPcPinDescriptorTwin->AutomationTable->PropertyCount
  478. )
  479. && ( pPcPinDescriptor->AutomationTable->Properties
  480. == pPcPinDescriptorTwin->AutomationTable->Properties
  481. )
  482. && ( pPcPinDescriptor->AutomationTable->PropertyItemSize
  483. == pPcPinDescriptorTwin->AutomationTable->PropertyItemSize
  484. )
  485. )
  486. )
  487. {
  488. *pt = *twinPt;
  489. break;
  490. }
  491. pPcPinDescriptorTwin =
  492. PPCPIN_DESCRIPTOR
  493. ( PBYTE(pPcPinDescriptorTwin) + pPcFilterDescriptor->PinSize
  494. );
  495. }
  496. //
  497. // Create a new table if we have to.
  498. //
  499. if (twinPin == pin)
  500. {
  501. pt->PropertySetCount = PinPropertySetCount;
  502. pt->PropertySets = PinPropertySets;
  503. pt->StaticSets = TRUE;
  504. if ( (pPcPinDescriptor->AutomationTable)
  505. && (pPcPinDescriptor->AutomationTable->PropertyCount)
  506. )
  507. {
  508. PcAddToPropertyTable
  509. (
  510. pt,
  511. pPcPinDescriptor->AutomationTable->PropertyCount,
  512. pPcPinDescriptor->AutomationTable->Properties,
  513. pPcPinDescriptor->AutomationTable->PropertyItemSize,
  514. FALSE
  515. );
  516. }
  517. const PCNODE_DESCRIPTOR *pPcNodeDescriptor2 = pPcFilterDescriptor->Nodes;
  518. for (ULONG node = pPcFilterDescriptor->NodeCount; node--; )
  519. {
  520. if ( (pPcNodeDescriptor2->AutomationTable)
  521. && (pPcNodeDescriptor2->AutomationTable->PropertyCount)
  522. )
  523. {
  524. PcAddToPropertyTable
  525. (
  526. pt,
  527. pPcNodeDescriptor2->AutomationTable->PropertyCount,
  528. pPcNodeDescriptor2->AutomationTable->Properties,
  529. pPcNodeDescriptor2->AutomationTable->PropertyItemSize,
  530. TRUE
  531. );
  532. }
  533. pPcNodeDescriptor2 =
  534. PPCNODE_DESCRIPTOR
  535. ( PBYTE(pPcNodeDescriptor2) + pPcFilterDescriptor->NodeSize
  536. );
  537. }
  538. }
  539. pt++;
  540. //
  541. // Find a pin that has the same event set.
  542. //
  543. PEVENT_TABLE twinEt = descr->PinEventTables;
  544. pPcPinDescriptorTwin = PPCPIN_DESCRIPTOR(pPcFilterDescriptor->Pins);
  545. for
  546. (
  547. ULONG twinEPin = 0;
  548. twinEPin < pin;
  549. twinEPin++, twinEt++
  550. )
  551. {
  552. if ( ( pPcPinDescriptor->AutomationTable
  553. == pPcPinDescriptorTwin->AutomationTable
  554. )
  555. || ( pPcPinDescriptor->AutomationTable
  556. && pPcPinDescriptorTwin->AutomationTable
  557. && ( pPcPinDescriptor->AutomationTable->EventCount
  558. == pPcPinDescriptorTwin->AutomationTable->EventCount
  559. )
  560. && ( pPcPinDescriptor->AutomationTable->Events
  561. == pPcPinDescriptorTwin->AutomationTable->Events
  562. )
  563. && ( pPcPinDescriptor->AutomationTable->EventItemSize
  564. == pPcPinDescriptorTwin->AutomationTable->EventItemSize
  565. )
  566. )
  567. )
  568. {
  569. *et = *twinEt;
  570. break;
  571. }
  572. pPcPinDescriptorTwin =
  573. PPCPIN_DESCRIPTOR
  574. ( PBYTE(pPcPinDescriptorTwin) + pPcFilterDescriptor->PinSize
  575. );
  576. }
  577. //
  578. // Create a new table if we have to.
  579. //
  580. if (twinEPin == pin)
  581. {
  582. et->EventSetCount = PinEventSetCount;
  583. et->EventSets = PinEventSets;
  584. et->StaticSets = TRUE;
  585. if ( (pPcPinDescriptor->AutomationTable)
  586. && (pPcPinDescriptor->AutomationTable->EventCount)
  587. )
  588. {
  589. PcAddToEventTable
  590. (
  591. et,
  592. pPcPinDescriptor->AutomationTable->EventCount,
  593. pPcPinDescriptor->AutomationTable->Events,
  594. pPcPinDescriptor->AutomationTable->EventItemSize,
  595. FALSE
  596. );
  597. }
  598. const PCNODE_DESCRIPTOR *pPcNodeDescriptor2 = pPcFilterDescriptor->Nodes;
  599. for( ULONG node = pPcFilterDescriptor->NodeCount; node--; )
  600. {
  601. if ( (pPcNodeDescriptor2->AutomationTable)
  602. && (pPcNodeDescriptor2->AutomationTable->EventCount)
  603. )
  604. {
  605. PcAddToEventTable
  606. (
  607. et,
  608. pPcNodeDescriptor2->AutomationTable->EventCount,
  609. pPcNodeDescriptor2->AutomationTable->Events,
  610. pPcNodeDescriptor2->AutomationTable->EventItemSize,
  611. TRUE
  612. );
  613. }
  614. pPcNodeDescriptor2 = PPCNODE_DESCRIPTOR( PBYTE(pPcNodeDescriptor2) + pPcFilterDescriptor->NodeSize );
  615. }
  616. }
  617. et++;
  618. //
  619. // Copy the KS descriptor.
  620. //
  621. *p = pPcPinDescriptor->KsPinDescriptor;
  622. //
  623. // Provide default mediums if necessary.
  624. //
  625. if (p->Mediums == NULL)
  626. {
  627. p->MediumsCount = SIZEOF_ARRAY(PinMediums);
  628. p->Mediums = PinMediums;
  629. }
  630. //
  631. // Massage the data ranges.
  632. //
  633. p->DataRanges =
  634. CloneDataRanges
  635. (
  636. privateHeap,
  637. &p->DataRangesCount,
  638. pPcPinDescriptor->KsPinDescriptor.DataRangesCount,
  639. pPcPinDescriptor->KsPinDescriptor.DataRanges
  640. );
  641. //
  642. // Provide default interfaces if necessary.
  643. //
  644. if ( (p->Communication & KSPIN_COMMUNICATION_BOTH)
  645. && (p->Interfaces == NULL)
  646. )
  647. {
  648. p->InterfacesCount = StreamInterfacesCount;
  649. p->Interfaces = StreamInterfaces;
  650. }
  651. p++;
  652. i->FilterPossible = pPcPinDescriptor->MaxFilterInstanceCount;
  653. i->FilterNecessary = pPcPinDescriptor->MinFilterInstanceCount;
  654. i->GlobalPossible = pPcPinDescriptor->MaxGlobalInstanceCount;
  655. i->GlobalCurrent = 0;
  656. i++;
  657. pPcPinDescriptor =
  658. PPCPIN_DESCRIPTOR
  659. ( PBYTE(pPcPinDescriptor) + pPcFilterDescriptor->PinSize
  660. );
  661. }
  662. *OutDescriptor = descr;
  663. ASSERT(privateHeap.BytesRemaining() == 0);
  664. }
  665. return ntStatus;
  666. }
  667. /*****************************************************************************
  668. * PcDeleteSubdeviceDescriptor()
  669. *****************************************************************************
  670. * Deletes a subdevice descriptor.
  671. */
  672. PORTCLASSAPI
  673. void
  674. NTAPI
  675. PcDeleteSubdeviceDescriptor
  676. (
  677. IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
  678. )
  679. {
  680. //
  681. // Free allocated memory for filter property and event tables.
  682. //
  683. PcFreePropertyTable(&pSubdeviceDescriptor->FilterPropertyTable);
  684. PcFreeEventTable(&pSubdeviceDescriptor->FilterEventTable);
  685. //
  686. // Free allocated memory for pin property tables.
  687. //
  688. PPROPERTY_TABLE pPropertyTable = pSubdeviceDescriptor->PinPropertyTables;
  689. for (ULONG ul = pSubdeviceDescriptor->PinCount; ul--; pPropertyTable++)
  690. {
  691. //
  692. // Find and clear any references to the same property set.
  693. //
  694. for
  695. ( PPROPERTY_TABLE pPropertyTableTwin =
  696. ( pSubdeviceDescriptor->PinPropertyTables
  697. + ( pSubdeviceDescriptor->PinCount
  698. - 1
  699. )
  700. )
  701. ; pPropertyTableTwin != pPropertyTable
  702. ; pPropertyTableTwin--
  703. )
  704. {
  705. if
  706. ( pPropertyTableTwin->PropertySets
  707. == pPropertyTable->PropertySets
  708. )
  709. {
  710. pPropertyTableTwin->PropertySetCount = 0;
  711. pPropertyTableTwin->PropertySets = NULL;
  712. pPropertyTableTwin->StaticSets = TRUE;
  713. pPropertyTableTwin->StaticItems = NULL;
  714. }
  715. }
  716. PcFreePropertyTable(pPropertyTable);
  717. }
  718. //
  719. // Free allocated memory for pin event tables.
  720. //
  721. PEVENT_TABLE pEventTable = pSubdeviceDescriptor->PinEventTables;
  722. for (ul = pSubdeviceDescriptor->PinCount; ul--; pEventTable++)
  723. {
  724. //
  725. // Find and clear any references to the same event set.
  726. //
  727. for
  728. ( PEVENT_TABLE pEventTableTwin =
  729. ( pSubdeviceDescriptor->PinEventTables
  730. + ( pSubdeviceDescriptor->PinCount
  731. - 1
  732. )
  733. )
  734. ; pEventTableTwin != pEventTable
  735. ; pEventTableTwin--
  736. )
  737. {
  738. if
  739. ( pEventTableTwin->EventSets
  740. == pEventTable->EventSets
  741. )
  742. {
  743. pEventTableTwin->EventSetCount = 0;
  744. pEventTableTwin->EventSets = NULL;
  745. pEventTableTwin->StaticSets = TRUE;
  746. pEventTableTwin->StaticItems = NULL;
  747. }
  748. }
  749. PcFreeEventTable(pEventTable);
  750. }
  751. //
  752. // The rest is one big chunk.
  753. //
  754. delete [] PBYTE(pSubdeviceDescriptor);
  755. }
  756. /*****************************************************************************
  757. * PcValidateConnectRequest()
  758. *****************************************************************************
  759. * Validate attempt to create a pin.
  760. */
  761. PORTCLASSAPI
  762. NTSTATUS
  763. NTAPI
  764. PcValidateConnectRequest
  765. ( IN PIRP pIrp
  766. , IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
  767. , OUT PKSPIN_CONNECT * ppKsPinConnect
  768. )
  769. {
  770. PAGED_CODE();
  771. ASSERT(pIrp);
  772. ASSERT(pSubdeviceDescriptor);
  773. ASSERT(ppKsPinConnect);
  774. NTSTATUS ntStatus =
  775. KsValidateConnectRequest
  776. ( pIrp
  777. , pSubdeviceDescriptor->PinCount
  778. , pSubdeviceDescriptor->PinDescriptors
  779. , ppKsPinConnect
  780. );
  781. return ntStatus;
  782. }
  783. /*****************************************************************************
  784. * PcValidatePinCount()
  785. *****************************************************************************
  786. * Validate pin count.
  787. */
  788. PORTCLASSAPI
  789. NTSTATUS
  790. NTAPI
  791. PcValidatePinCount
  792. ( IN ULONG ulPinId
  793. , IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
  794. , IN PULONG pulPinInstanceCounts
  795. )
  796. {
  797. PAGED_CODE();
  798. ASSERT(pSubdeviceDescriptor);
  799. ASSERT(pulPinInstanceCounts);
  800. NTSTATUS ntStatus = STATUS_SUCCESS;
  801. if
  802. ( ( pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
  803. < pSubdeviceDescriptor->PinInstances[ulPinId].GlobalPossible
  804. )
  805. || ( pulPinInstanceCounts[ulPinId]
  806. < pSubdeviceDescriptor->PinInstances[ulPinId].FilterPossible
  807. )
  808. )
  809. {
  810. pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent++;
  811. pulPinInstanceCounts[ulPinId]++;
  812. _DbgPrintF( DEBUGLVL_VERBOSE,
  813. ( "Create pin %d: global=%d local=%d"
  814. , ulPinId
  815. , pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
  816. , pulPinInstanceCounts[ulPinId]
  817. ));
  818. }
  819. else
  820. {
  821. // TODO: What code?
  822. ntStatus = STATUS_UNSUCCESSFUL;
  823. }
  824. return ntStatus;
  825. }
  826. /*****************************************************************************
  827. * PcValidateDeviceContext()
  828. *****************************************************************************
  829. * Probes DeviceContext for writing.
  830. */
  831. PORTCLASSAPI
  832. NTSTATUS
  833. NTAPI
  834. PcValidateDeviceContext
  835. ( IN PDEVICE_CONTEXT pDeviceContext,
  836. IN PIRP pIrp
  837. )
  838. {
  839. PAGED_CODE();
  840. NTSTATUS ntStatus = STATUS_SUCCESS;
  841. if (NULL == pDeviceContext)
  842. {
  843. _DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : pDeviceContext = NULL"));
  844. return STATUS_INVALID_PARAMETER;
  845. }
  846. // validate the pointers if we don't trust the client
  847. //
  848. /*
  849. // ISSUE ALPERS 2000/12/20 - The Probe call is disabled because it always generates an exception.
  850. // Therefore it is disabled.
  851. if (KernelMode != pIrp->RequestorMode)
  852. {
  853. __try
  854. {
  855. ProbeForRead( pDeviceContext,
  856. sizeof(*pDeviceContext),
  857. sizeof(BYTE));
  858. }
  859. __except (EXCEPTION_EXECUTE_HANDLER)
  860. {
  861. ntStatus = GetExceptionCode();
  862. _DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : ProbeForWrite failed %X", ntStatus));
  863. }
  864. }
  865. */
  866. if (NT_SUCCESS(ntStatus))
  867. {
  868. if (PORTCLS_DEVICE_EXTENSION_SIGNATURE != pDeviceContext->Signature )
  869. {
  870. ntStatus = STATUS_INVALID_PARAMETER;
  871. _DbgPrintF(DEBUGLVL_TERSE, ("PcValidateDeviceContext : Invalid Extension Signature"));
  872. }
  873. }
  874. return ntStatus;
  875. } // PcValidateDeviceContext
  876. /*****************************************************************************
  877. * PcTerminateConnection()
  878. *****************************************************************************
  879. * Decrement instance counts associated with a pin.
  880. */
  881. PORTCLASSAPI
  882. void
  883. NTAPI
  884. PcTerminateConnection
  885. ( IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
  886. , IN PULONG pulPinInstanceCounts
  887. , IN ULONG ulPinId
  888. )
  889. {
  890. PAGED_CODE();
  891. ASSERT(pSubdeviceDescriptor);
  892. ASSERT(pulPinInstanceCounts);
  893. ASSERT(ulPinId <= pSubdeviceDescriptor->PinCount);
  894. pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent--;
  895. pulPinInstanceCounts[ulPinId]--;
  896. _DbgPrintF( DEBUGLVL_VERBOSE,
  897. ( "Delete pin %d: global=%d local=%d"
  898. , ulPinId
  899. , pSubdeviceDescriptor->PinInstances[ulPinId].GlobalCurrent
  900. , pulPinInstanceCounts[ulPinId]
  901. ));
  902. }
  903. /*****************************************************************************
  904. * PcVerifyFilterIsReady()
  905. *****************************************************************************
  906. * Verify necessary pins are connected.
  907. */
  908. PORTCLASSAPI
  909. NTSTATUS
  910. NTAPI
  911. PcVerifyFilterIsReady
  912. ( IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor
  913. , IN PULONG pulPinInstanceCounts
  914. )
  915. {
  916. PAGED_CODE();
  917. ASSERT(pSubdeviceDescriptor);
  918. ASSERT(pulPinInstanceCounts);
  919. NTSTATUS ntStatus = STATUS_SUCCESS;
  920. for
  921. ( ULONG ulPinId = 0
  922. ; ulPinId < pSubdeviceDescriptor->PinCount
  923. ; ulPinId++
  924. )
  925. {
  926. if
  927. ( pulPinInstanceCounts[ulPinId]
  928. < pSubdeviceDescriptor->PinInstances[ulPinId].FilterNecessary
  929. )
  930. {
  931. // TODO: What code?
  932. ntStatus = STATUS_UNSUCCESSFUL;
  933. break;
  934. }
  935. }
  936. return ntStatus;
  937. }
  938. #define END_NONE 0
  939. #define END_FROM 1
  940. #define END_TO 2
  941. #define END_BOTH 3
  942. /*****************************************************************************
  943. * FindConnectionToPin()
  944. *****************************************************************************
  945. * Find a connection that connects to a given node or filter pin.
  946. *
  947. * ulNode - node number of KSFILTER_NODE
  948. * ulConnection - in: connection to start with
  949. * out: found connection or ULONG(-1) if not found
  950. *
  951. * return - 0 for no connection found
  952. * END_FROM for outgoing connection
  953. * END_TO for incoming connection
  954. */
  955. ULONG
  956. FindConnectionToPin
  957. (
  958. IN ULONG ulNode,
  959. IN ULONG ulPin,
  960. IN PKSTOPOLOGY pKsTopology,
  961. IN OUT PULONG ulConnection,
  962. OUT PKSTOPOLOGY_CONNECTION * ppKsTopologyConnection OPTIONAL
  963. )
  964. {
  965. ASSERT(pKsTopology);
  966. ASSERT(ulConnection);
  967. ASSERT(*ulConnection < pKsTopology->TopologyConnectionsCount);
  968. ULONG ulEnd;
  969. PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
  970. PKSTOPOLOGY_CONNECTION
  971. (
  972. &pKsTopology->TopologyConnections[*ulConnection]
  973. );
  974. while (1)
  975. {
  976. ASSERT(*ulConnection <= pKsTopology->TopologyConnectionsCount);
  977. if (*ulConnection == pKsTopology->TopologyConnectionsCount)
  978. {
  979. ulEnd = END_NONE;
  980. *ulConnection = ULONG(-1);
  981. pKsTopologyConnection = NULL;
  982. break;
  983. }
  984. else
  985. if ( (pKsTopologyConnection->FromNode == ulNode)
  986. && (pKsTopologyConnection->FromNodePin == ulPin)
  987. )
  988. {
  989. ulEnd = END_FROM;
  990. break;
  991. }
  992. else
  993. if ( (pKsTopologyConnection->ToNode == ulNode)
  994. && (pKsTopologyConnection->ToNodePin == ulPin)
  995. )
  996. {
  997. ulEnd = END_TO;
  998. break;
  999. }
  1000. (*ulConnection)++;
  1001. pKsTopologyConnection++;
  1002. }
  1003. if (ppKsTopologyConnection)
  1004. {
  1005. *ppKsTopologyConnection = pKsTopologyConnection;
  1006. }
  1007. return ulEnd;
  1008. }
  1009. /*****************************************************************************
  1010. * FindConnectionToNode()
  1011. *****************************************************************************
  1012. * Find a connection that connects to a given node or to the filter.
  1013. *
  1014. * ulNode - node number of KSFILTER_NODE
  1015. * ulEnd - 0 for any direction
  1016. * END_FROM for outgoing connection
  1017. * END_TO for incoming connection
  1018. * ulConnection - in: connection to start with
  1019. * out: found connection or ULONG(-1) if not found
  1020. *
  1021. * return - 0 for no connection found
  1022. * END_FROM for outgoing connection
  1023. * END_TO for incoming connection
  1024. */
  1025. ULONG
  1026. FindConnectionToNode
  1027. (
  1028. IN ULONG ulNode,
  1029. IN ULONG ulEnd,
  1030. IN PKSTOPOLOGY pKsTopology,
  1031. IN OUT PULONG ulConnection,
  1032. OUT PKSTOPOLOGY_CONNECTION * ppKsTopologyConnection OPTIONAL
  1033. )
  1034. {
  1035. ASSERT(pKsTopology);
  1036. ASSERT
  1037. ( (ulNode == KSFILTER_NODE)
  1038. || (ulNode < pKsTopology->TopologyNodesCount)
  1039. );
  1040. ASSERT(ulConnection);
  1041. ASSERT(*ulConnection < pKsTopology->TopologyConnectionsCount);
  1042. PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
  1043. PKSTOPOLOGY_CONNECTION
  1044. (
  1045. &pKsTopology->TopologyConnections[*ulConnection]
  1046. );
  1047. while (1)
  1048. {
  1049. ASSERT(*ulConnection <= pKsTopology->TopologyConnectionsCount);
  1050. if (*ulConnection == pKsTopology->TopologyConnectionsCount)
  1051. {
  1052. ulEnd = END_NONE;
  1053. *ulConnection = ULONG(-1);
  1054. pKsTopologyConnection = NULL;
  1055. break;
  1056. }
  1057. else
  1058. if ( (pKsTopologyConnection->FromNode == ulNode)
  1059. && (ulEnd != END_TO)
  1060. )
  1061. {
  1062. ulEnd = END_FROM;
  1063. break;
  1064. }
  1065. else
  1066. if ( (pKsTopologyConnection->ToNode == ulNode)
  1067. && (ulEnd != END_FROM)
  1068. )
  1069. {
  1070. ulEnd = END_TO;
  1071. break;
  1072. }
  1073. (*ulConnection)++;
  1074. pKsTopologyConnection++;
  1075. }
  1076. if (ppKsTopologyConnection)
  1077. {
  1078. *ppKsTopologyConnection = pKsTopologyConnection;
  1079. }
  1080. return ulEnd;
  1081. }
  1082. /*****************************************************************************
  1083. * NodeIsTransform()
  1084. *****************************************************************************
  1085. * Determines if a node is a transform. KSFILTER_NODE is handled (FALSE).
  1086. */
  1087. BOOLEAN
  1088. NodeIsTransform
  1089. (
  1090. IN ULONG ulNode,
  1091. IN PKSTOPOLOGY pKsTopology
  1092. )
  1093. {
  1094. ASSERT(pKsTopology);
  1095. ASSERT
  1096. ( (ulNode == KSFILTER_NODE)
  1097. || (ulNode < pKsTopology->TopologyNodesCount)
  1098. );
  1099. ULONG ulEnd = END_NONE;
  1100. if (ulNode != KSFILTER_NODE)
  1101. {
  1102. PKSTOPOLOGY_CONNECTION pKsTopologyConnection =
  1103. PKSTOPOLOGY_CONNECTION(pKsTopology->TopologyConnections);
  1104. for
  1105. (
  1106. ULONG ul = pKsTopology->TopologyConnectionsCount;
  1107. ul--;
  1108. pKsTopologyConnection++
  1109. )
  1110. {
  1111. if (pKsTopologyConnection->FromNode == ulNode)
  1112. {
  1113. ulEnd += END_FROM;
  1114. if ( (ulEnd != END_FROM)
  1115. && (ulEnd != END_BOTH)
  1116. )
  1117. {
  1118. break;
  1119. }
  1120. }
  1121. if (pKsTopologyConnection->ToNode == ulNode)
  1122. {
  1123. ulEnd += END_TO;
  1124. if ( (ulEnd != END_TO)
  1125. && (ulEnd != END_BOTH)
  1126. )
  1127. {
  1128. break;
  1129. }
  1130. }
  1131. }
  1132. }
  1133. return ulEnd == END_BOTH;
  1134. }
  1135. /*****************************************************************************
  1136. * NodeAtThisEnd()
  1137. *****************************************************************************
  1138. * Node at indicated end of the connection.
  1139. */
  1140. inline
  1141. ULONG
  1142. NodeAtThisEnd
  1143. (
  1144. IN ULONG ulEnd,
  1145. IN PKSTOPOLOGY_CONNECTION pKsTopologyConnection
  1146. )
  1147. {
  1148. return
  1149. ( (ulEnd == END_FROM)
  1150. ? pKsTopologyConnection->FromNode
  1151. : pKsTopologyConnection->ToNode
  1152. );
  1153. }
  1154. /*****************************************************************************
  1155. * NodeAtOtherEnd()
  1156. *****************************************************************************
  1157. * Node at opposite end of the connection.
  1158. */
  1159. inline
  1160. ULONG
  1161. NodeAtOtherEnd
  1162. (
  1163. IN ULONG ulEnd,
  1164. IN PKSTOPOLOGY_CONNECTION pKsTopologyConnection
  1165. )
  1166. {
  1167. return
  1168. ( (ulEnd == END_FROM)
  1169. ? pKsTopologyConnection->ToNode
  1170. : pKsTopologyConnection->FromNode
  1171. );
  1172. }
  1173. /*****************************************************************************
  1174. * PcCaptureFormat()
  1175. *****************************************************************************
  1176. * Capture a data format in an allocated buffer, possibly changing offensive
  1177. * formats.
  1178. */
  1179. PORTCLASSAPI
  1180. NTSTATUS
  1181. NTAPI
  1182. PcCaptureFormat
  1183. (
  1184. OUT PKSDATAFORMAT * ppKsDataFormatOut,
  1185. IN PKSDATAFORMAT pKsDataFormatIn,
  1186. IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor,
  1187. IN ULONG ulPinId
  1188. )
  1189. {
  1190. ASSERT(ppKsDataFormatOut);
  1191. ASSERT(pKsDataFormatIn);
  1192. ASSERT(pSubdeviceDescriptor);
  1193. ASSERT(ulPinId < pSubdeviceDescriptor->PinCount);
  1194. NTSTATUS ntStatus = STATUS_SUCCESS;
  1195. if( (pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_DSOUND)) &&
  1196. IsEqualGUIDAligned( pKsDataFormatIn->MajorFormat, KSDATAFORMAT_TYPE_AUDIO ) &&
  1197. IsEqualGUIDAligned( pKsDataFormatIn->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND ) )
  1198. {
  1199. //
  1200. // This is the dread DSound format. Check to see if we have the
  1201. // required topology and convert to WaveFormatEx if we do.
  1202. //
  1203. // Note: DSound format does not have to be PCM....
  1204. //
  1205. PKSDATAFORMAT_DSOUND pKsDataFormatDSound =
  1206. PKSDATAFORMAT_DSOUND(pKsDataFormatIn);
  1207. //
  1208. // Fail if the client has asked for a software buffer.
  1209. //
  1210. if ( pKsDataFormatDSound->BufferDesc.Flags
  1211. & KSDSOUND_BUFFER_LOCSOFTWARE
  1212. )
  1213. {
  1214. _DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed because client requested software buffer."));
  1215. return STATUS_INVALID_PARAMETER;
  1216. }
  1217. //
  1218. // Find a connection involving the filter pin.
  1219. //
  1220. ULONG ulConnection = 0;
  1221. PKSTOPOLOGY_CONNECTION pKsTopologyConnection;
  1222. ULONG ulEnd =
  1223. FindConnectionToPin
  1224. (
  1225. KSFILTER_NODE,
  1226. ulPinId,
  1227. pSubdeviceDescriptor->Topology,
  1228. &ulConnection,
  1229. &pKsTopologyConnection
  1230. );
  1231. //
  1232. // Trace the topology until we find a non-transform or all the
  1233. // required nodes have been found. Position notification is
  1234. // always supported.
  1235. //
  1236. ULONG ulMissing =
  1237. ( pKsDataFormatDSound->BufferDesc.Control
  1238. & ~KSDSOUND_BUFFER_CTRL_POSITIONNOTIFY
  1239. );
  1240. while (ulMissing && ulEnd)
  1241. {
  1242. //
  1243. // Found a connection. Follow the topology.
  1244. //
  1245. ULONG ulNode = NodeAtOtherEnd(ulEnd,pKsTopologyConnection);
  1246. if (! NodeIsTransform(ulNode,pSubdeviceDescriptor->Topology))
  1247. {
  1248. //
  1249. // The new node is not a simple transform (1 in, 1 out).
  1250. //
  1251. break;
  1252. }
  1253. //
  1254. // Drop 'missing' bits as appropriate based on the node GUID.
  1255. //
  1256. ASSERT(ulNode < pSubdeviceDescriptor->Topology->TopologyNodesCount);
  1257. const GUID *pGuid = &pSubdeviceDescriptor->Topology->TopologyNodes[ulNode];
  1258. if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_3D_EFFECTS))
  1259. {
  1260. ulMissing &=~ KSDSOUND_BUFFER_CTRL_3D;
  1261. }
  1262. else
  1263. if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_SRC))
  1264. {
  1265. ulMissing &=~ KSDSOUND_BUFFER_CTRL_FREQUENCY;
  1266. }
  1267. else
  1268. if ( IsEqualGUIDAligned(*pGuid,KSNODETYPE_SUPERMIX)
  1269. || IsEqualGUIDAligned(*pGuid,KSNODETYPE_VOLUME)
  1270. )
  1271. {
  1272. ulMissing &=~ KSDSOUND_BUFFER_CTRL_PAN;
  1273. ulMissing &=~ KSDSOUND_BUFFER_CTRL_VOLUME;
  1274. }
  1275. //
  1276. // Find the next connection in line.
  1277. //
  1278. ulConnection = 0;
  1279. ulEnd =
  1280. FindConnectionToNode
  1281. (
  1282. ulNode,
  1283. ulEnd,
  1284. pSubdeviceDescriptor->Topology,
  1285. &ulConnection,
  1286. &pKsTopologyConnection
  1287. );
  1288. }
  1289. //
  1290. // Make sure no nodes were missing.
  1291. //
  1292. if (! ulMissing)
  1293. {
  1294. //
  1295. // We have the capabilities required. Build the new format.
  1296. //
  1297. ULONG ulSize =
  1298. ( sizeof(KSDATAFORMAT_WAVEFORMATEX)
  1299. + ( pKsDataFormatIn->FormatSize
  1300. - sizeof(KSDATAFORMAT_DSOUND)
  1301. )
  1302. );
  1303. *ppKsDataFormatOut =
  1304. PKSDATAFORMAT
  1305. (
  1306. ExAllocatePoolWithTag
  1307. (
  1308. PagedPool,
  1309. ulSize,
  1310. 'fDcP'
  1311. )
  1312. );
  1313. if (*ppKsDataFormatOut)
  1314. {
  1315. //
  1316. // Copy KSDATAFORMAT part.
  1317. //
  1318. RtlCopyMemory
  1319. (
  1320. *ppKsDataFormatOut,
  1321. pKsDataFormatIn,
  1322. sizeof(KSDATAFORMAT)
  1323. );
  1324. //
  1325. // Copy WAVEFORMATEX part including appended stuff.
  1326. //
  1327. RtlCopyMemory
  1328. (
  1329. *ppKsDataFormatOut + 1,
  1330. &pKsDataFormatDSound->BufferDesc.WaveFormatEx,
  1331. ulSize - sizeof(KSDATAFORMAT)
  1332. );
  1333. //
  1334. // Adjust size and specifier.
  1335. //
  1336. (*ppKsDataFormatOut)->FormatSize = ulSize;
  1337. (*ppKsDataFormatOut)->Specifier =
  1338. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
  1339. }
  1340. else
  1341. {
  1342. _DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed to allocate memory for format."));
  1343. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1344. }
  1345. }
  1346. else
  1347. {
  1348. _DbgPrintF(DEBUGLVL_VERBOSE,("PcCaptureFormat Failed due to lack of feature support (0x%08x).",ulMissing));
  1349. //
  1350. // Don't have the required nodes...fail.
  1351. //
  1352. ntStatus = STATUS_INVALID_PARAMETER;
  1353. }
  1354. }
  1355. else
  1356. {
  1357. _DbgPrintF(DEBUGLVL_VERBOSE,("PcCaptureFormat Format captured as-is."));
  1358. //
  1359. // Some other format. Just capture it.
  1360. //
  1361. *ppKsDataFormatOut = PKSDATAFORMAT(ExAllocatePoolWithTag(PagedPool,
  1362. pKsDataFormatIn->FormatSize,
  1363. 'fDcP'));
  1364. if (*ppKsDataFormatOut)
  1365. {
  1366. RtlCopyMemory
  1367. (
  1368. *ppKsDataFormatOut,
  1369. pKsDataFormatIn,
  1370. pKsDataFormatIn->FormatSize
  1371. );
  1372. }
  1373. else
  1374. {
  1375. _DbgPrintF(DEBUGLVL_TERSE,("PcCaptureFormat Failed to allocate memory for format."));
  1376. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1377. }
  1378. }
  1379. // check to verify SampleSize is set properly on waveformatex formats
  1380. if( NT_SUCCESS(ntStatus) &&
  1381. (pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_WAVEFORMATEX)) &&
  1382. IsEqualGUIDAligned((*ppKsDataFormatOut)->MajorFormat,KSDATAFORMAT_TYPE_AUDIO) &&
  1383. IsEqualGUIDAligned((*ppKsDataFormatOut)->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
  1384. {
  1385. PKSDATAFORMAT_WAVEFORMATEX pWaveFormat = PKSDATAFORMAT_WAVEFORMATEX(*ppKsDataFormatOut);
  1386. if( 0 == pWaveFormat->DataFormat.SampleSize )
  1387. {
  1388. pWaveFormat->DataFormat.SampleSize = pWaveFormat->WaveFormatEx.nBlockAlign;
  1389. }
  1390. }
  1391. return ntStatus;
  1392. }
  1393. /*****************************************************************************
  1394. * PcAcquireFormatResources()
  1395. *****************************************************************************
  1396. * Acquire resources specified in a format.
  1397. */
  1398. PORTCLASSAPI
  1399. void
  1400. NTAPI
  1401. PcAcquireFormatResources
  1402. (
  1403. IN PKSDATAFORMAT pKsDataFormatIn,
  1404. IN PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor,
  1405. IN ULONG ulPinId,
  1406. IN PPROPERTY_CONTEXT pPropertyContext
  1407. )
  1408. {
  1409. ASSERT(pKsDataFormatIn);
  1410. ASSERT(pSubdeviceDescriptor);
  1411. ASSERT(ulPinId < pSubdeviceDescriptor->PinCount);
  1412. ASSERT(pPropertyContext);
  1413. KSP_NODE ksPNode;
  1414. ksPNode.Property.Set = KSPROPSETID_TopologyNode;
  1415. ksPNode.Property.Id = KSPROPERTY_TOPOLOGYNODE_ENABLE;
  1416. ksPNode.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
  1417. ksPNode.NodeId = 0; // Fill in later
  1418. ksPNode.Reserved = 0;
  1419. if ( (pKsDataFormatIn->FormatSize >= sizeof(KSDATAFORMAT_DSOUND))
  1420. && IsEqualGUIDAligned
  1421. ( pKsDataFormatIn->MajorFormat,
  1422. KSDATAFORMAT_TYPE_AUDIO
  1423. )
  1424. && IsEqualGUIDAligned
  1425. ( pKsDataFormatIn->Specifier,
  1426. KSDATAFORMAT_SPECIFIER_DSOUND
  1427. )
  1428. )
  1429. {
  1430. //
  1431. // This is the dreaded DSound format. Turn on all the nodes
  1432. // that are specified in the caps bits.
  1433. //
  1434. PKSDATAFORMAT_DSOUND pKsDataFormatDSound =
  1435. PKSDATAFORMAT_DSOUND(pKsDataFormatIn);
  1436. //
  1437. // Find a connection involving the filter pin.
  1438. //
  1439. ULONG ulConnection = 0;
  1440. PKSTOPOLOGY_CONNECTION pKsTopologyConnection;
  1441. ULONG ulEnd =
  1442. FindConnectionToPin
  1443. (
  1444. KSFILTER_NODE,
  1445. ulPinId,
  1446. pSubdeviceDescriptor->Topology,
  1447. &ulConnection,
  1448. &pKsTopologyConnection
  1449. );
  1450. //
  1451. // Trace the topology until we find a non-transform or all the
  1452. // required nodes have been found. Position notification is
  1453. // always supported.
  1454. //
  1455. ULONG ulMissing =
  1456. ( pKsDataFormatDSound->BufferDesc.Control
  1457. & ( KSDSOUND_BUFFER_CTRL_3D
  1458. | KSDSOUND_BUFFER_CTRL_FREQUENCY
  1459. )
  1460. );
  1461. while (ulMissing && ulEnd)
  1462. {
  1463. //
  1464. // Found a connection. Follow the topology.
  1465. //
  1466. ULONG ulNode = NodeAtOtherEnd(ulEnd,pKsTopologyConnection);
  1467. if (! NodeIsTransform(ulNode,pSubdeviceDescriptor->Topology))
  1468. {
  1469. //
  1470. // The new node is not a simple transform (1 in, 1 out).
  1471. //
  1472. break;
  1473. }
  1474. //
  1475. // Turn on nodes as appropriate based on the node GUID.
  1476. //
  1477. ASSERT(ulNode < pSubdeviceDescriptor->Topology->TopologyNodesCount);
  1478. const GUID *pGuid = &pSubdeviceDescriptor->Topology->TopologyNodes[ulNode];
  1479. if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_3D_EFFECTS))
  1480. {
  1481. if (ulMissing & KSDSOUND_BUFFER_CTRL_3D)
  1482. {
  1483. //
  1484. // Turn on the 3D node.
  1485. //
  1486. ULONG ulPropertyValue = TRUE;
  1487. ULONG ulPropertyValueSize = sizeof(ULONG);
  1488. ksPNode.NodeId = ulNode;
  1489. PcDispatchProperty
  1490. ( NULL // pIrp
  1491. , pPropertyContext
  1492. , NULL // pKsPropertySet
  1493. , sizeof(KSP_NODE)
  1494. , &ksPNode.Property
  1495. , &ulPropertyValueSize
  1496. , &ulPropertyValue
  1497. );
  1498. ulMissing &=~ KSDSOUND_BUFFER_CTRL_3D;
  1499. }
  1500. }
  1501. else
  1502. if (IsEqualGUIDAligned(*pGuid,KSNODETYPE_SRC))
  1503. {
  1504. if (ulMissing & KSDSOUND_BUFFER_CTRL_FREQUENCY)
  1505. {
  1506. //
  1507. // Turn on the SRC node.
  1508. //
  1509. ULONG ulPropertyValue = TRUE;
  1510. ULONG ulPropertyValueSize = sizeof(ULONG);
  1511. ksPNode.NodeId = ulNode;
  1512. PcDispatchProperty
  1513. ( NULL // pIrp
  1514. , pPropertyContext
  1515. , NULL // pKsPropertySet
  1516. , sizeof(KSP_NODE)
  1517. , &ksPNode.Property
  1518. , &ulPropertyValueSize
  1519. , &ulPropertyValue
  1520. );
  1521. ulMissing &=~ KSDSOUND_BUFFER_CTRL_FREQUENCY;
  1522. }
  1523. }
  1524. //
  1525. // Find the next connection in line.
  1526. //
  1527. ulConnection = 0;
  1528. ulEnd =
  1529. FindConnectionToNode
  1530. (
  1531. ulNode,
  1532. ulEnd,
  1533. pSubdeviceDescriptor->Topology,
  1534. &ulConnection,
  1535. &pKsTopologyConnection
  1536. );
  1537. }
  1538. }
  1539. }
  1540. #pragma code_seg()
  1541. /*****************************************************************************
  1542. * PcRegisterIoTimeout()
  1543. *****************************************************************************
  1544. * Registers an IoTimeout callback.
  1545. */
  1546. PORTCLASSAPI
  1547. NTSTATUS
  1548. NTAPI
  1549. PcRegisterIoTimeout
  1550. (
  1551. IN PDEVICE_OBJECT pDeviceObject,
  1552. IN PIO_TIMER_ROUTINE pTimerRoutine,
  1553. IN PVOID pContext
  1554. )
  1555. {
  1556. KIRQL OldIrql;
  1557. PTIMEOUTCALLBACK TimeoutCallback;
  1558. NTSTATUS ntStatus = STATUS_SUCCESS;
  1559. ASSERT(pDeviceObject);
  1560. ASSERT(pTimerRoutine);
  1561. ASSERT( PASSIVE_LEVEL == KeGetCurrentIrql() );
  1562. //
  1563. // Validate Parameters.
  1564. //
  1565. if (NULL == pDeviceObject ||
  1566. NULL == pTimerRoutine ||
  1567. NULL == pDeviceObject->DeviceExtension)
  1568. {
  1569. _DbgPrintF(DEBUGLVL_TERSE, ("PcRegisterIoTimeout : Invalid Parameter"));
  1570. return STATUS_INVALID_PARAMETER;
  1571. }
  1572. // get the device context
  1573. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1574. // allocate a timeout callback structure -- 'PcTc'
  1575. TimeoutCallback = PTIMEOUTCALLBACK(ExAllocatePoolWithTag( NonPagedPool, sizeof(TIMEOUTCALLBACK),'cTcP' ));
  1576. if( TimeoutCallback )
  1577. {
  1578. // initialize the entry
  1579. TimeoutCallback->TimerRoutine = pTimerRoutine;
  1580. TimeoutCallback->Context = pContext;
  1581. // grab the list spin lock
  1582. KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
  1583. // walk the list to see if the entry is already registered
  1584. if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
  1585. {
  1586. PLIST_ENTRY ListEntry;
  1587. PTIMEOUTCALLBACK pCallback;
  1588. for( ListEntry = pDeviceContext->TimeoutList.Flink;
  1589. ListEntry != &(pDeviceContext->TimeoutList);
  1590. ListEntry = ListEntry->Flink )
  1591. {
  1592. pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
  1593. TIMEOUTCALLBACK,
  1594. ListEntry );
  1595. if( (pCallback->TimerRoutine == pTimerRoutine) &&
  1596. (pCallback->Context == pContext) )
  1597. {
  1598. // entry already exists in the list, so fail this request
  1599. ntStatus = STATUS_UNSUCCESSFUL;
  1600. }
  1601. }
  1602. }
  1603. if( NT_SUCCESS(ntStatus) )
  1604. {
  1605. // add the entry to the list
  1606. InsertTailList( &(pDeviceContext->TimeoutList), &(TimeoutCallback->ListEntry) );
  1607. }
  1608. else
  1609. {
  1610. // free the entry
  1611. ExFreePool( TimeoutCallback );
  1612. }
  1613. // release the spin lock
  1614. KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
  1615. }
  1616. else
  1617. {
  1618. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1619. }
  1620. return ntStatus;
  1621. }
  1622. /*****************************************************************************
  1623. * PcUnregisterIoTimeout()
  1624. *****************************************************************************
  1625. * Unregisters an IoTimeout callback.
  1626. */
  1627. PORTCLASSAPI
  1628. NTSTATUS
  1629. NTAPI
  1630. PcUnregisterIoTimeout
  1631. (
  1632. IN PDEVICE_OBJECT pDeviceObject,
  1633. IN PIO_TIMER_ROUTINE pTimerRoutine,
  1634. IN PVOID pContext
  1635. )
  1636. {
  1637. KIRQL OldIrql;
  1638. ASSERT(pDeviceObject);
  1639. ASSERT(pTimerRoutine);
  1640. ASSERT( PASSIVE_LEVEL == KeGetCurrentIrql() );
  1641. //
  1642. // Validate Parameters.
  1643. //
  1644. if (NULL == pDeviceObject ||
  1645. NULL == pTimerRoutine ||
  1646. NULL == pDeviceObject->DeviceExtension)
  1647. {
  1648. _DbgPrintF(DEBUGLVL_TERSE, ("PcUnregisterIoTimeout : Invalid Parameter"));
  1649. return STATUS_INVALID_PARAMETER;
  1650. }
  1651. // get the device context
  1652. PDEVICE_CONTEXT pDeviceContext = PDEVICE_CONTEXT(pDeviceObject->DeviceExtension);
  1653. // grab the spin lock
  1654. KeAcquireSpinLock( &(pDeviceContext->TimeoutLock), &OldIrql );
  1655. // walk the list
  1656. if( !IsListEmpty( &(pDeviceContext->TimeoutList) ) )
  1657. {
  1658. PLIST_ENTRY ListEntry;
  1659. PTIMEOUTCALLBACK pCallback;
  1660. for( ListEntry = pDeviceContext->TimeoutList.Flink;
  1661. ListEntry != &(pDeviceContext->TimeoutList);
  1662. ListEntry = ListEntry->Flink )
  1663. {
  1664. pCallback = (PTIMEOUTCALLBACK) CONTAINING_RECORD( ListEntry,
  1665. TIMEOUTCALLBACK,
  1666. ListEntry );
  1667. if( (pCallback->TimerRoutine == pTimerRoutine) &&
  1668. (pCallback->Context == pContext) )
  1669. {
  1670. RemoveEntryList(ListEntry);
  1671. KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
  1672. ExFreePool(pCallback);
  1673. return STATUS_SUCCESS;
  1674. }
  1675. }
  1676. }
  1677. // release the spinlock
  1678. KeReleaseSpinLock( &(pDeviceContext->TimeoutLock), OldIrql );
  1679. return STATUS_NOT_FOUND;
  1680. }