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.

1521 lines
48 KiB

  1. /*****************************************************************************
  2. * property.cpp - property support
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #include "private.h"
  7. /*****************************************************************************
  8. * Functions
  9. */
  10. #pragma code_seg("PAGE")
  11. /*****************************************************************************
  12. * PcHandlePropertyWithTable()
  13. *****************************************************************************
  14. * Uses a property table to handle a property request IOCTL.
  15. */
  16. PORTCLASSAPI
  17. NTSTATUS
  18. NTAPI
  19. PcHandlePropertyWithTable
  20. ( IN PIRP pIrp
  21. , IN ULONG ulPropertySetsCount
  22. , IN const KSPROPERTY_SET* pKsPropertySet
  23. , IN PPROPERTY_CONTEXT pPropertyContext
  24. )
  25. {
  26. ASSERT(pIrp);
  27. ASSERT(pPropertyContext);
  28. pIrp->Tail.Overlay.DriverContext[3] = pPropertyContext;
  29. NTSTATUS ntStatus =
  30. KsPropertyHandler
  31. (
  32. pIrp,
  33. ulPropertySetsCount,
  34. pKsPropertySet
  35. );
  36. return ntStatus;
  37. }
  38. /*****************************************************************************
  39. * PcDispatchProperty()
  40. *****************************************************************************
  41. * Dispatch a property via a PCPROPERTY_ITEM entry.
  42. */
  43. PORTCLASSAPI
  44. NTSTATUS
  45. NTAPI
  46. PcDispatchProperty
  47. (
  48. IN PIRP pIrp OPTIONAL,
  49. IN PPROPERTY_CONTEXT pPropertyContext,
  50. IN const KSPROPERTY_SET * pKsPropertySet OPTIONAL,
  51. IN ULONG ulIdentifierSize,
  52. IN PKSIDENTIFIER pKsIdentifier,
  53. IN OUT PULONG pulDataSize,
  54. IN OUT PVOID pvData OPTIONAL
  55. )
  56. {
  57. PAGED_CODE();
  58. ASSERT(pPropertyContext);
  59. ASSERT(pKsIdentifier);
  60. ASSERT(pulDataSize);
  61. PPCPROPERTY_REQUEST pPcPropertyRequest =
  62. new(NonPagedPool,'rPcP') PCPROPERTY_REQUEST;
  63. NTSTATUS ntStatus;
  64. if (! pPcPropertyRequest)
  65. {
  66. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  67. }
  68. else
  69. {
  70. //
  71. // Copy target information from the context structure.
  72. //
  73. pPcPropertyRequest->MajorTarget =
  74. pPropertyContext->pUnknownMajorTarget;
  75. pPcPropertyRequest->MinorTarget =
  76. pPropertyContext->pUnknownMinorTarget;
  77. pPcPropertyRequest->Node =
  78. pPropertyContext->ulNodeId;
  79. //
  80. // Determine the value size.
  81. //
  82. pPcPropertyRequest->ValueSize = *pulDataSize;
  83. //
  84. // If the node number is in the instance data, extract it.
  85. // TODO: Remove this when node objects rule.
  86. //
  87. if ( (pKsIdentifier->Flags & KSPROPERTY_TYPE_TOPOLOGY)
  88. && (pPcPropertyRequest->Node == ULONG(-1))
  89. )
  90. {
  91. //
  92. // Get the node id and remaining instance.
  93. //
  94. if (ulIdentifierSize < sizeof(KSP_NODE))
  95. {
  96. delete pPcPropertyRequest;
  97. return STATUS_INVALID_BUFFER_SIZE;
  98. }
  99. PKSP_NODE pKsPNode = PKSP_NODE(pKsIdentifier);
  100. pPcPropertyRequest->Node = pKsPNode->NodeId;
  101. pPcPropertyRequest->InstanceSize =
  102. ulIdentifierSize - sizeof(KSP_NODE);
  103. pPcPropertyRequest->Instance =
  104. ( (pPcPropertyRequest->InstanceSize == 0)
  105. ? NULL
  106. : PVOID(pKsPNode + 1)
  107. );
  108. }
  109. else
  110. {
  111. //
  112. // No node in the instance...get generic instance if any.
  113. //
  114. pPcPropertyRequest->InstanceSize =
  115. ulIdentifierSize - sizeof(KSIDENTIFIER);
  116. pPcPropertyRequest->Instance =
  117. ( (pPcPropertyRequest->InstanceSize == 0)
  118. ? NULL
  119. : PVOID(pKsIdentifier + 1)
  120. );
  121. }
  122. if (pKsPropertySet)
  123. {
  124. ASSERT(pKsPropertySet->PropertyItem);
  125. //
  126. // Find the property item in the KS-style list.
  127. //
  128. #if (DBG)
  129. ULONG dbgCount = pKsPropertySet->PropertiesCount;
  130. #endif
  131. for
  132. ( const KSPROPERTY_ITEM *pKsPropertyItem =
  133. pKsPropertySet->PropertyItem
  134. ; pKsPropertyItem->PropertyId != pKsIdentifier->Id
  135. ; pKsPropertyItem++
  136. )
  137. {
  138. ASSERT(--dbgCount);
  139. }
  140. //
  141. // The property item is stashed in the Relations field if this is not
  142. // a node property. If it is, we have to find the node property in
  143. // the original list.
  144. //
  145. pPcPropertyRequest->PropertyItem =
  146. PPCPROPERTY_ITEM(pKsPropertyItem->Relations);
  147. }
  148. else
  149. {
  150. //
  151. // No KS set was supplied. We need to look in the original list
  152. // associated with the node.
  153. //
  154. pPcPropertyRequest->PropertyItem = NULL;
  155. }
  156. if (! pPcPropertyRequest->PropertyItem)
  157. {
  158. PPCFILTER_DESCRIPTOR pPcFilterDescriptor =
  159. pPropertyContext->pPcFilterDescriptor;
  160. if ( pPcFilterDescriptor
  161. && ( pPcPropertyRequest->Node
  162. < pPcFilterDescriptor->NodeCount
  163. )
  164. && pPcFilterDescriptor->
  165. Nodes[pPcPropertyRequest->Node].AutomationTable
  166. )
  167. {
  168. //
  169. // Valid node...search the original property item list.
  170. //
  171. const PCAUTOMATION_TABLE *pPcAutomationTable =
  172. pPcFilterDescriptor->
  173. Nodes[pPcPropertyRequest->Node].AutomationTable;
  174. const PCPROPERTY_ITEM *pPcPropertyItem =
  175. pPcAutomationTable->Properties;
  176. for (ULONG ul = pPcAutomationTable->PropertyCount; ul--; )
  177. {
  178. if ( IsEqualGUIDAligned
  179. ( *pPcPropertyItem->Set
  180. , pKsIdentifier->Set
  181. )
  182. && (pPcPropertyItem->Id == pKsIdentifier->Id)
  183. )
  184. {
  185. pPcPropertyRequest->PropertyItem = pPcPropertyItem;
  186. break;
  187. }
  188. pPcPropertyItem =
  189. PPCPROPERTY_ITEM
  190. ( PBYTE(pPcPropertyItem)
  191. + pPcAutomationTable->PropertyItemSize
  192. );
  193. }
  194. }
  195. else
  196. {
  197. //
  198. // The node ID was invalid.
  199. //
  200. ntStatus = STATUS_NOT_FOUND;
  201. }
  202. }
  203. //
  204. // Call the handler if we have a property item with a handler.
  205. //
  206. if ( pPcPropertyRequest->PropertyItem
  207. && pPcPropertyRequest->PropertyItem->Handler
  208. )
  209. {
  210. pPcPropertyRequest->Verb = pKsIdentifier->Flags;
  211. pPcPropertyRequest->Value = pvData;
  212. pPcPropertyRequest->Irp = pIrp;
  213. //
  214. // Call the handler.
  215. //
  216. ntStatus =
  217. pPcPropertyRequest->PropertyItem->Handler
  218. (
  219. pPcPropertyRequest
  220. );
  221. *pulDataSize = pPcPropertyRequest->ValueSize;
  222. }
  223. else
  224. {
  225. ntStatus = STATUS_NOT_FOUND;
  226. }
  227. //
  228. // Delete the request structure unless we are pending.
  229. //
  230. if (ntStatus != STATUS_PENDING)
  231. {
  232. delete pPcPropertyRequest;
  233. }
  234. else
  235. {
  236. //
  237. // Only requests with IRPs can be pending.
  238. //
  239. ASSERT(pIrp);
  240. }
  241. }
  242. return ntStatus;
  243. }
  244. /*****************************************************************************
  245. * PropertyItemPropertyHandler()
  246. *****************************************************************************
  247. * KS-sytle property handler that handles all properties using the
  248. * PCPROPERTY_ITEM mechanism.
  249. */
  250. NTSTATUS
  251. PropertyItemPropertyHandler
  252. (
  253. IN PIRP pIrp,
  254. IN PKSIDENTIFIER pKsIdentifier,
  255. IN OUT PVOID pvData OPTIONAL
  256. )
  257. {
  258. PAGED_CODE();
  259. ASSERT(pIrp);
  260. ASSERT(pKsIdentifier);
  261. //
  262. // Extract various things from the IRP and dispatch the property.
  263. //
  264. PIO_STACK_LOCATION irpSp =
  265. IoGetCurrentIrpStackLocation(pIrp);
  266. ULONG ulDataSize =
  267. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  268. NTSTATUS ntStatus =
  269. PcDispatchProperty
  270. ( pIrp
  271. , PPROPERTY_CONTEXT(pIrp->Tail.Overlay.DriverContext[3])
  272. , KSPROPERTY_SET_IRP_STORAGE(pIrp)
  273. , irpSp->Parameters.DeviceIoControl.InputBufferLength
  274. , pKsIdentifier
  275. , &ulDataSize
  276. , pvData
  277. );
  278. //
  279. // Inform the caller of the resulting status and size.
  280. // Pending IRPs must be IoMarkIrpPending()ed before the dispatch routine
  281. // returns.
  282. //
  283. if ((ntStatus != STATUS_PENDING) && !NT_ERROR(ntStatus))
  284. {
  285. pIrp->IoStatus.Information = ulDataSize;
  286. }
  287. return ntStatus;
  288. }
  289. /*****************************************************************************
  290. * PcCompletePendingPropertyRequest()
  291. *****************************************************************************
  292. * Completes a pending property request.
  293. */
  294. PORTCLASSAPI
  295. NTSTATUS
  296. NTAPI
  297. PcCompletePendingPropertyRequest
  298. (
  299. IN PPCPROPERTY_REQUEST PropertyRequest,
  300. IN NTSTATUS NtStatus
  301. )
  302. {
  303. ASSERT(PropertyRequest);
  304. ASSERT(NtStatus != STATUS_PENDING);
  305. //
  306. // Validate Parameters.
  307. //
  308. if (NULL == PropertyRequest)
  309. {
  310. _DbgPrintF(DEBUGLVL_TERSE, ("PcCompletePendingPropertyRequest : Invalid Parameter."));
  311. return STATUS_INVALID_PARAMETER;
  312. }
  313. if (!NT_ERROR(NtStatus))
  314. {
  315. PropertyRequest->Irp->IoStatus.Information =
  316. PropertyRequest->ValueSize;
  317. }
  318. PropertyRequest->Irp->IoStatus.Status = NtStatus;
  319. IoCompleteRequest(PropertyRequest->Irp,IO_NO_INCREMENT);
  320. delete PropertyRequest;
  321. return STATUS_SUCCESS;
  322. }
  323. /*****************************************************************************
  324. * PcFreePropertyTable()
  325. *****************************************************************************
  326. * Frees allocated memory in a PROPERTY_TABLE structure.
  327. */
  328. PORTCLASSAPI
  329. void
  330. NTAPI
  331. PcFreePropertyTable
  332. (
  333. IN PPROPERTY_TABLE PropertyTable
  334. )
  335. {
  336. _DbgPrintF(DEBUGLVL_VERBOSE,("PcFreePropertyTable"));
  337. PAGED_CODE();
  338. ASSERT(PropertyTable);
  339. ASSERT((!PropertyTable->PropertySets) == (!PropertyTable->PropertySetCount));
  340. // PropertySets and PropertySetCount must be non-NULL/non-zero, or NULL/zero
  341. ASSERT(PropertyTable->StaticSets == (!PropertyTable->StaticItems));
  342. // StaticSets and StaticItems must be TRUE/NULL, or FALSE/non-null
  343. PBOOLEAN staticItem = PropertyTable->StaticItems;
  344. if (staticItem)
  345. {
  346. PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
  347. if (propertySet)
  348. {
  349. for( ULONG count = PropertyTable->PropertySetCount;
  350. count--;
  351. propertySet++, staticItem++)
  352. {
  353. if ((! *staticItem) && propertySet->PropertyItem)
  354. {
  355. ExFreePool(PVOID(propertySet->PropertyItem));
  356. }
  357. }
  358. }
  359. ExFreePool(PropertyTable->StaticItems);
  360. PropertyTable->StaticItems = NULL;
  361. }
  362. if (PropertyTable->PropertySets && !PropertyTable->StaticSets)
  363. {
  364. PropertyTable->PropertySetCount = 0;
  365. ExFreePool(PropertyTable->PropertySets);
  366. PropertyTable->PropertySets = NULL;
  367. }
  368. PropertyTable->StaticSets = TRUE;
  369. }
  370. /*****************************************************************************
  371. * PcAddToPropertyTable()
  372. *****************************************************************************
  373. * Adds a PROPERTY_ITEM property table to a PROPERTY_TABLE structure.
  374. */
  375. PORTCLASSAPI
  376. NTSTATUS
  377. NTAPI
  378. PcAddToPropertyTable
  379. (
  380. IN OUT PPROPERTY_TABLE PropertyTable,
  381. IN ULONG PropertyItemCount,
  382. IN const PCPROPERTY_ITEM * PropertyItems,
  383. IN ULONG PropertyItemSize,
  384. IN BOOLEAN NodeTable
  385. )
  386. {
  387. PAGED_CODE();
  388. ASSERT(PropertyTable);
  389. ASSERT(PropertyItems);
  390. ASSERT(PropertyItemSize >= sizeof(PCPROPERTY_ITEM));
  391. _DbgPrintF(DEBUGLVL_VERBOSE,("PcAddToEventTable"));
  392. #define ADVANCE(item) (item = PPCPROPERTY_ITEM(PBYTE(item) + PropertyItemSize))
  393. ASSERT((!PropertyTable->PropertySets) == (!PropertyTable->PropertySetCount));
  394. // values must be non-NULL/non-zero, or NULL/zero.
  395. //
  396. // Determine how many sets we will end up with.
  397. //
  398. ULONG setCount = PropertyTable->PropertySetCount;
  399. const PCPROPERTY_ITEM *item = PropertyItems;
  400. for (ULONG count = PropertyItemCount; count--; ADVANCE(item))
  401. {
  402. BOOLEAN countThis = TRUE;
  403. //
  404. // See if it's already in the table.
  405. //
  406. PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
  407. for
  408. ( ULONG count2 = PropertyTable->PropertySetCount;
  409. count2--;
  410. propertySet++
  411. )
  412. {
  413. if (IsEqualGUIDAligned(*item->Set,*propertySet->Set))
  414. {
  415. countThis = FALSE;
  416. break;
  417. }
  418. }
  419. if (countThis)
  420. {
  421. //
  422. // See if it's appeared in the list previously.
  423. //
  424. for
  425. (
  426. const PCPROPERTY_ITEM *prevItem = PropertyItems;
  427. prevItem != item;
  428. ADVANCE(prevItem)
  429. )
  430. {
  431. if (IsEqualGUIDAligned(*item->Set,*prevItem->Set))
  432. {
  433. countThis = FALSE;
  434. break;
  435. }
  436. }
  437. }
  438. if (countThis)
  439. {
  440. setCount++;
  441. }
  442. }
  443. NTSTATUS ntStatus = STATUS_SUCCESS;
  444. //
  445. // Make a new set table
  446. //
  447. ASSERT(setCount);
  448. ASSERT(setCount >= PropertyTable->PropertySetCount);
  449. //
  450. // Allocate memory required for the set table.
  451. //
  452. PKSPROPERTY_SET newTable =
  453. PKSPROPERTY_SET
  454. (
  455. ExAllocatePoolWithTag
  456. (
  457. PagedPool,
  458. sizeof(KSPROPERTY_SET) * setCount,
  459. 'tScP'
  460. )
  461. );
  462. //
  463. // Allocate memory for the static items flags.
  464. //
  465. PBOOLEAN newStaticItems = NULL;
  466. if (newTable)
  467. {
  468. newStaticItems =
  469. PBOOLEAN
  470. (
  471. ExAllocatePoolWithTag
  472. (
  473. PagedPool,
  474. sizeof(BOOLEAN) * setCount,
  475. 'bScP'
  476. )
  477. );
  478. if (! newStaticItems)
  479. {
  480. ExFreePool(newTable);
  481. newTable = NULL;
  482. }
  483. }
  484. if (newTable)
  485. {
  486. //
  487. // Initialize the new set table.
  488. //
  489. RtlZeroMemory
  490. (
  491. PVOID(newTable),
  492. sizeof(KSPROPERTY_SET) * setCount
  493. );
  494. if (PropertyTable->PropertySetCount != 0)
  495. {
  496. RtlCopyMemory
  497. (
  498. PVOID(newTable),
  499. PVOID(PropertyTable->PropertySets),
  500. sizeof(KSPROPERTY_SET) * PropertyTable->PropertySetCount
  501. );
  502. }
  503. //
  504. // Initialize the new static items flags.
  505. //
  506. RtlFillMemory
  507. (
  508. PVOID(newStaticItems),
  509. sizeof(BOOLEAN) * setCount,
  510. 0xff
  511. );
  512. if (PropertyTable->StaticItems && PropertyTable->PropertySetCount)
  513. {
  514. //
  515. // Flags existed before...copy them.
  516. //
  517. RtlCopyMemory
  518. (
  519. PVOID(newStaticItems),
  520. PVOID(PropertyTable->StaticItems),
  521. sizeof(BOOLEAN) * PropertyTable->PropertySetCount
  522. );
  523. }
  524. //
  525. // Assign set GUIDs to the new set entries.
  526. //
  527. PKSPROPERTY_SET addHere =
  528. newTable + PropertyTable->PropertySetCount;
  529. const PCPROPERTY_ITEM *item2 = PropertyItems;
  530. for (ULONG count = PropertyItemCount; count--; ADVANCE(item2))
  531. {
  532. BOOLEAN addThis = TRUE;
  533. //
  534. // See if it's already in the table.
  535. //
  536. for( PKSPROPERTY_SET propertySet = newTable;
  537. propertySet != addHere;
  538. propertySet++)
  539. {
  540. if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
  541. {
  542. addThis = FALSE;
  543. break;
  544. }
  545. }
  546. if (addThis)
  547. {
  548. addHere->Set = item2->Set;
  549. addHere++;
  550. }
  551. }
  552. ASSERT(addHere == newTable + setCount);
  553. //
  554. // Free old allocated tables.
  555. //
  556. if (PropertyTable->PropertySets && (!PropertyTable->StaticSets))
  557. {
  558. ExFreePool(PropertyTable->PropertySets);
  559. }
  560. if (PropertyTable->StaticItems)
  561. {
  562. ExFreePool(PropertyTable->StaticItems);
  563. }
  564. //
  565. // Install the new tables.
  566. //
  567. PropertyTable->PropertySetCount = setCount;
  568. PropertyTable->PropertySets = newTable;
  569. PropertyTable->StaticSets = FALSE;
  570. PropertyTable->StaticItems = newStaticItems;
  571. }
  572. else
  573. {
  574. // if allocations fail, return error and
  575. // keep sets and items as they were.
  576. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  577. }
  578. //
  579. // Now we have a property set table that contains all the sets we need.
  580. //
  581. if (NT_SUCCESS(ntStatus))
  582. {
  583. //
  584. // For each set...
  585. //
  586. PKSPROPERTY_SET propertySet = PropertyTable->PropertySets;
  587. PBOOLEAN staticItem = PropertyTable->StaticItems;
  588. for
  589. ( ULONG count = PropertyTable->PropertySetCount;
  590. count--;
  591. propertySet++, staticItem++
  592. )
  593. {
  594. //
  595. // Check to see how many new items we have.
  596. //
  597. ULONG itemCount = propertySet->PropertiesCount;
  598. const PCPROPERTY_ITEM *item2 = PropertyItems;
  599. for (ULONG count2 = PropertyItemCount; count2--; ADVANCE(item2))
  600. {
  601. if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
  602. {
  603. itemCount++;
  604. }
  605. }
  606. ASSERT(itemCount >= propertySet->PropertiesCount);
  607. if (itemCount != propertySet->PropertiesCount)
  608. {
  609. //
  610. // Allocate memory required for the items table.
  611. //
  612. PKSPROPERTY_ITEM newTable2 =
  613. PKSPROPERTY_ITEM
  614. (
  615. ExAllocatePoolWithTag
  616. (
  617. PagedPool,
  618. sizeof(KSPROPERTY_ITEM) * itemCount,
  619. 'iScP'
  620. )
  621. );
  622. if (! newTable2)
  623. {
  624. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  625. break;
  626. }
  627. //
  628. // Initialize the table.
  629. //
  630. RtlZeroMemory
  631. (
  632. PVOID(newTable2),
  633. sizeof(KSPROPERTY_ITEM) * itemCount
  634. );
  635. if (propertySet->PropertiesCount)
  636. {
  637. RtlCopyMemory
  638. (
  639. PVOID(newTable2),
  640. PVOID(propertySet->PropertyItem),
  641. sizeof(KSPROPERTY_ITEM) * propertySet->PropertiesCount
  642. );
  643. }
  644. //
  645. // Create the new items.
  646. //
  647. PKSPROPERTY_ITEM addHere =
  648. newTable2 + propertySet->PropertiesCount;
  649. item2 = PropertyItems;
  650. for (count2 = PropertyItemCount; count2--; ADVANCE(item2))
  651. {
  652. if (IsEqualGUIDAligned(*item2->Set,*propertySet->Set))
  653. {
  654. addHere->PropertyId = item2->Id;
  655. addHere->GetPropertyHandler =
  656. ( (item2->Flags & PCPROPERTY_ITEM_FLAG_GET)
  657. ? PropertyItemPropertyHandler
  658. : NULL
  659. );
  660. addHere->MinProperty = sizeof(KSPROPERTY);
  661. addHere->MinData = 0;
  662. addHere->SetPropertyHandler =
  663. ( (item2->Flags & PCPROPERTY_ITEM_FLAG_SET)
  664. ? PropertyItemPropertyHandler
  665. : NULL
  666. );
  667. addHere->Values = NULL;
  668. addHere->RelationsCount = 0;
  669. addHere->Relations =
  670. ( NodeTable
  671. ? NULL
  672. : PKSPROPERTY(item2) // Secret hack!
  673. );
  674. addHere->SupportHandler =
  675. ( (item2->Flags & PCPROPERTY_ITEM_FLAG_BASICSUPPORT)
  676. ? PropertyItemPropertyHandler
  677. : NULL
  678. );
  679. addHere->SerializedSize =
  680. ( (item2->Flags & PCPROPERTY_ITEM_FLAG_SERIALIZE)
  681. ? ULONG(-1)
  682. : 0
  683. );
  684. addHere++;
  685. }
  686. }
  687. ASSERT(addHere == newTable2 + itemCount);
  688. //
  689. // Free old allocated table.
  690. //
  691. if (propertySet->PropertyItem && ! *staticItem)
  692. {
  693. ExFreePool(PVOID(propertySet->PropertyItem));
  694. }
  695. //
  696. // Install the new tables.
  697. //
  698. propertySet->PropertiesCount = itemCount;
  699. propertySet->PropertyItem = newTable2;
  700. *staticItem = FALSE;
  701. }
  702. }
  703. }
  704. return ntStatus;
  705. }
  706. /*****************************************************************************
  707. * GenerateFormatFromRange()
  708. *****************************************************************************
  709. * Determine the particular format, based on the intersection of these
  710. * two specific data ranges. First ask the miniport, then fall back to
  711. * our own algorithm if the miniport doesn't handle it.
  712. */
  713. NTSTATUS
  714. GenerateFormatFromRange (
  715. IN PIRP Irp,
  716. IN ULONG PinId,
  717. IN PKSDATARANGE MyDataRange,
  718. IN PKSDATARANGE ClientDataRange,
  719. IN ULONG OutputBufferLength,
  720. OUT PVOID ResultantFormat OPTIONAL,
  721. OUT PULONG ResultantFormatLength)
  722. {
  723. BOOLEAN bSpecifier;
  724. NTSTATUS Status;
  725. ULONG RequiredSize;
  726. PPROPERTY_CONTEXT pPropertyContext = PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
  727. ASSERT(pPropertyContext);
  728. PSUBDEVICE pSubdevice = pPropertyContext->pSubdevice;
  729. ASSERT(pSubdevice);
  730. //
  731. // Give the miniport a chance to fill in the format structure
  732. //
  733. Status = pSubdevice->DataRangeIntersection (PinId,
  734. ClientDataRange,
  735. MyDataRange,
  736. OutputBufferLength,
  737. ResultantFormat,
  738. ResultantFormatLength);
  739. //
  740. // return if the miniport filled out the structure.
  741. //
  742. if (Status != STATUS_NOT_IMPLEMENTED)
  743. {
  744. return Status;
  745. }
  746. //
  747. // In case the miniport didn't implement the DataRangeIntersection,
  748. // we provide a default handler here.
  749. //
  750. //
  751. // Check if there is a wildcard somewhere.
  752. //
  753. if (IsEqualGUIDAligned (ClientDataRange->MajorFormat, KSDATAFORMAT_TYPE_WILDCARD) ||
  754. IsEqualGUIDAligned (ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) ||
  755. IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD))
  756. {
  757. // If the miniport exposed a WILDCARD, then it must implement an
  758. // intersection handler, because it must provide the specific
  759. // ideal matching data range for that WILDCARD.
  760. //
  761. return STATUS_NO_MATCH;
  762. }
  763. if (!IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_NONE))
  764. {
  765. //
  766. // The miniport did not resolve this format. Let's handle the specifiers
  767. // that we know.
  768. //
  769. if (!IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND) &&
  770. !IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
  771. {
  772. return STATUS_NO_MATCH;
  773. }
  774. bSpecifier = TRUE;
  775. //
  776. // The specifier here defines the format of ClientDataRange
  777. // and the format expected to be returned in ResultantFormat.
  778. //
  779. if (IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
  780. {
  781. RequiredSize = sizeof (KSDATAFORMAT_DSOUND);
  782. }
  783. else
  784. {
  785. RequiredSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);
  786. }
  787. }
  788. else
  789. {
  790. bSpecifier = FALSE;
  791. RequiredSize = sizeof (KSDATAFORMAT);
  792. }
  793. //
  794. // Validate return buffer size, if the request is only for the
  795. // size of the resultant structure, return it now.
  796. //
  797. if (!OutputBufferLength)
  798. {
  799. *ResultantFormatLength = RequiredSize;
  800. return STATUS_BUFFER_OVERFLOW;
  801. }
  802. else if (OutputBufferLength < RequiredSize)
  803. {
  804. return STATUS_BUFFER_TOO_SMALL;
  805. }
  806. // There was a specifier ...
  807. if (bSpecifier)
  808. {
  809. PKSDATARANGE_AUDIO myAudioRange,clientAudioRange;
  810. PKSDATAFORMAT resultantFormat;
  811. PWAVEFORMATEX resultantWaveFormatEx;
  812. myAudioRange = (PKSDATARANGE_AUDIO) MyDataRange;
  813. clientAudioRange = (PKSDATARANGE_AUDIO) ClientDataRange;
  814. resultantFormat = (PKSDATAFORMAT)ResultantFormat;
  815. //
  816. // Fill out the dataformat and other general fields.
  817. //
  818. *resultantFormat = *ClientDataRange;
  819. resultantFormat->FormatSize = RequiredSize;
  820. *ResultantFormatLength = RequiredSize;
  821. //
  822. // Fill out the DSOUND specific structure
  823. //
  824. if (IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
  825. {
  826. PKSDATAFORMAT_DSOUND resultantDSoundFormat;
  827. resultantDSoundFormat = (PKSDATAFORMAT_DSOUND)ResultantFormat;
  828. _DbgPrintF (DEBUGLVL_VERBOSE, ("returning KSDATAFORMAT_DSOUND format intersection"));
  829. //
  830. // DSound format capabilities are not expressed
  831. // this way in KS, so we express no capabilities.
  832. //
  833. resultantDSoundFormat->BufferDesc.Flags = 0 ;
  834. resultantDSoundFormat->BufferDesc.Control = 0 ;
  835. resultantWaveFormatEx = &resultantDSoundFormat->BufferDesc.WaveFormatEx;
  836. }
  837. else
  838. {
  839. _DbgPrintF (DEBUGLVL_VERBOSE, ("returning KSDATAFORMAT_WAVEFORMATEX format intersection"));
  840. resultantWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT)ResultantFormat + 1);
  841. }
  842. //
  843. // Return a format that intersects the given audio range,
  844. // using our maximum support as the "best" format.
  845. //
  846. resultantWaveFormatEx->wFormatTag = WAVE_FORMAT_PCM;
  847. resultantWaveFormatEx->nChannels = (USHORT) min (
  848. myAudioRange->MaximumChannels,clientAudioRange->MaximumChannels);
  849. resultantWaveFormatEx->nSamplesPerSec = min (
  850. myAudioRange->MaximumSampleFrequency,clientAudioRange->MaximumSampleFrequency);
  851. resultantWaveFormatEx->wBitsPerSample = (USHORT) min (
  852. myAudioRange->MaximumBitsPerSample,clientAudioRange->MaximumBitsPerSample);
  853. resultantWaveFormatEx->nBlockAlign = (resultantWaveFormatEx->wBitsPerSample * resultantWaveFormatEx->nChannels) / 8;
  854. resultantWaveFormatEx->nAvgBytesPerSec = (resultantWaveFormatEx->nSamplesPerSec * resultantWaveFormatEx->nBlockAlign);
  855. resultantWaveFormatEx->cbSize = 0;
  856. ((PKSDATAFORMAT) ResultantFormat)->SampleSize = resultantWaveFormatEx->nBlockAlign;
  857. _DbgPrintF (DEBUGLVL_VERBOSE, ("Channels = %d", resultantWaveFormatEx->nChannels));
  858. _DbgPrintF (DEBUGLVL_VERBOSE, ("Samples/sec = %d", resultantWaveFormatEx->nSamplesPerSec));
  859. _DbgPrintF (DEBUGLVL_VERBOSE, ("Bits/sample = %d", resultantWaveFormatEx->wBitsPerSample));
  860. }
  861. else
  862. { // There was no specifier. Return only the KSDATAFORMAT structure.
  863. //
  864. // Copy the data format structure.
  865. //
  866. _DbgPrintF (DEBUGLVL_VERBOSE, ("returning default format intersection"));
  867. RtlCopyMemory (ResultantFormat, ClientDataRange, sizeof (KSDATAFORMAT));
  868. *ResultantFormatLength = sizeof (KSDATAFORMAT);
  869. }
  870. return STATUS_SUCCESS;
  871. }
  872. /*****************************************************************************
  873. * ValidateTypeAndSpecifier()
  874. *****************************************************************************
  875. * Find the data range that best matches the client's data range, given our
  876. * entire list of data ranges. This might include wildcard-based ranges.
  877. *
  878. */
  879. NTSTATUS
  880. ValidateTypeAndSpecifier(
  881. IN PIRP Irp,
  882. IN ULONG PinId,
  883. IN PKSDATARANGE ClientDataRange,
  884. IN ULONG MyDataRangesCount,
  885. IN const PKSDATARANGE * MyDataRanges,
  886. IN ULONG OutputBufferLength,
  887. OUT PVOID ResultantFormat,
  888. OUT PULONG ResultantFormatLength
  889. )
  890. {
  891. NTSTATUS ntStatus;
  892. PKSDATARANGE aClientDataRange;
  893. //
  894. // Check the size of the structure.
  895. //
  896. if (ClientDataRange->FormatSize < sizeof (KSDATARANGE))
  897. {
  898. _DbgPrintF (DEBUGLVL_TERSE, ("Validating ClientDataRange: size < KSDATARANGE!"));
  899. return STATUS_INVALID_PARAMETER;
  900. }
  901. //
  902. // We default to no match.
  903. //
  904. ntStatus = STATUS_NO_MATCH;
  905. //
  906. // Go through all the dataranges in the validate list until we get a SUCCESS.
  907. //
  908. for (; MyDataRangesCount--; MyDataRanges++)
  909. {
  910. PKSDATARANGE myDataRange = *MyDataRanges;
  911. //
  912. // Verify that the correct major format, subformat and specifier (or wildcards)
  913. // are in the intersection.
  914. //
  915. if ((!IsEqualGUIDAligned(ClientDataRange->MajorFormat,myDataRange->MajorFormat) &&
  916. !IsEqualGUIDAligned(ClientDataRange->MajorFormat,KSDATAFORMAT_TYPE_WILDCARD)) ||
  917. (!IsEqualGUIDAligned(ClientDataRange->SubFormat,myDataRange->SubFormat) &&
  918. !IsEqualGUIDAligned(ClientDataRange->SubFormat,KSDATAFORMAT_SUBTYPE_WILDCARD)) ||
  919. (!IsEqualGUIDAligned(ClientDataRange->Specifier,myDataRange->Specifier) &&
  920. !IsEqualGUIDAligned(ClientDataRange->Specifier,KSDATAFORMAT_SPECIFIER_WILDCARD)))
  921. {
  922. continue; // no match and no WILDCARD, try the next one
  923. }
  924. //
  925. // if not WILDCARD, then we ask the miniport to match this one exactly,
  926. // else we manufacture a range and ask the miniport for a match from that.
  927. //
  928. aClientDataRange = ClientDataRange; // assume no WILDCARD for now, we ask the miniport to match this
  929. //
  930. // Handle the wildcards.
  931. //
  932. if (IsEqualGUIDAligned (ClientDataRange->MajorFormat,KSDATAFORMAT_TYPE_WILDCARD) ||
  933. IsEqualGUIDAligned (ClientDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD) ||
  934. IsEqualGUIDAligned (ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WILDCARD))
  935. {
  936. //
  937. // We pass a faked datarange for the specifiers we know or we pass to the
  938. // miniport it's own datarange.
  939. //
  940. // We know the specifiers waveformatex and dsound.
  941. //
  942. if (IsEqualGUIDAligned (myDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
  943. IsEqualGUIDAligned (myDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
  944. {
  945. KSDATARANGE_AUDIO dr;
  946. //
  947. // Take the complete datarange from the driver.
  948. //
  949. dr.DataRange = *myDataRange;
  950. //
  951. // Fill in a HUGE data range (it asked for WILDCARD, after all!)
  952. //
  953. dr.MaximumChannels = 0x1FFF0;
  954. dr.MinimumBitsPerSample = 1;
  955. dr.MaximumBitsPerSample = 0x1FFF0;
  956. dr.MinimumSampleFrequency = 1;
  957. dr.MaximumSampleFrequency = 0x1FFFFFF0;
  958. aClientDataRange = (PKSDATARANGE)&dr;
  959. }
  960. else
  961. {
  962. //
  963. // We don't know this non-wave format (in the list of formats we supposedly support).
  964. // The miniport specified this format, so it is OK to pass it down.
  965. //
  966. aClientDataRange = myDataRange;
  967. }
  968. }
  969. //
  970. // Make sure KSDATARANGE_AUDIO is used, then see if there is a possible match.
  971. //
  972. if (IsEqualGUIDAligned (aClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
  973. IsEqualGUIDAligned (aClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_DSOUND))
  974. {
  975. if (aClientDataRange->FormatSize < sizeof (KSDATARANGE_AUDIO))
  976. {
  977. //
  978. // The datarange structure passed has no KSDATARANGE_AUDIO.
  979. //
  980. _DbgPrintF (DEBUGLVL_TERSE, ("Validating PCM ValidDataRange: size < KSDATARANGE_AUDIO!"));
  981. continue; // not large enough, try the next one
  982. }
  983. //
  984. // Verify that we have an intersection with the specified format and
  985. // our audio format dictated by our specific requirements.
  986. //
  987. _DbgPrintF (DEBUGLVL_VERBOSE, ("validating KSDATARANGE_AUDIO"));
  988. if ((((PKSDATARANGE_AUDIO)aClientDataRange)->MinimumSampleFrequency >
  989. ((PKSDATARANGE_AUDIO)myDataRange)->MaximumSampleFrequency) ||
  990. (((PKSDATARANGE_AUDIO)aClientDataRange)->MaximumSampleFrequency <
  991. ((PKSDATARANGE_AUDIO)myDataRange)->MinimumSampleFrequency) ||
  992. (((PKSDATARANGE_AUDIO)aClientDataRange)->MinimumBitsPerSample >
  993. ((PKSDATARANGE_AUDIO)myDataRange)->MaximumBitsPerSample) ||
  994. (((PKSDATARANGE_AUDIO)aClientDataRange)->MaximumBitsPerSample <
  995. ((PKSDATARANGE_AUDIO)myDataRange)->MinimumBitsPerSample))
  996. {
  997. continue;
  998. }
  999. }
  1000. ntStatus = GenerateFormatFromRange (Irp,
  1001. PinId,
  1002. myDataRange,
  1003. aClientDataRange,
  1004. OutputBufferLength,
  1005. ResultantFormat,
  1006. ResultantFormatLength);
  1007. if ( NT_SUCCESS(ntStatus)
  1008. || (ntStatus == STATUS_BUFFER_OVERFLOW)
  1009. || (ntStatus == STATUS_BUFFER_TOO_SMALL))
  1010. {
  1011. break; // We found a good one, or we failed.
  1012. // Either way we must leave.
  1013. }
  1014. }
  1015. return ntStatus;
  1016. }
  1017. /*****************************************************************************
  1018. * PinIntersectHandler()
  1019. *****************************************************************************
  1020. * This function is a data range callback for use with
  1021. * PropertyHandler_PinIntersection
  1022. */
  1023. NTSTATUS
  1024. PinIntersectHandler
  1025. (
  1026. IN PIRP Irp,
  1027. IN PKSP_PIN Pin,
  1028. IN PKSDATARANGE DataRange,
  1029. OUT PVOID Data
  1030. )
  1031. {
  1032. NTSTATUS Status;
  1033. ULONG OutputBufferLength;
  1034. PAGED_CODE();
  1035. ASSERT(Irp);
  1036. ASSERT(Pin);
  1037. ASSERT(DataRange);
  1038. PPROPERTY_CONTEXT pPropertyContext =
  1039. PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
  1040. ASSERT(pPropertyContext);
  1041. PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor =
  1042. pPropertyContext->pSubdeviceDescriptor;
  1043. ASSERT(pSubdeviceDescriptor);
  1044. ASSERT(pSubdeviceDescriptor->PinDescriptors);
  1045. ASSERT(Pin->PinId < pSubdeviceDescriptor->PinCount);
  1046. PKSPIN_DESCRIPTOR pinDescriptor =
  1047. &pSubdeviceDescriptor->PinDescriptors[Pin->PinId];
  1048. ASSERT(pinDescriptor);
  1049. _DbgPrintF(DEBUGLVL_VERBOSE,("[PinIntersectHandler]"));
  1050. OutputBufferLength =
  1051. IoGetCurrentIrpStackLocation( Irp )->
  1052. Parameters.DeviceIoControl.OutputBufferLength;
  1053. Status =
  1054. ValidateTypeAndSpecifier(
  1055. Irp,
  1056. Pin->PinId,
  1057. DataRange,
  1058. pinDescriptor->DataRangesCount,
  1059. pinDescriptor->DataRanges,
  1060. OutputBufferLength,
  1061. Data,
  1062. PULONG(&Irp->IoStatus.Information) );
  1063. if (!NT_SUCCESS( Status )) {
  1064. _DbgPrintF(
  1065. DEBUGLVL_VERBOSE,
  1066. ("ValidateTypeAndSpecifier() returned %08x", Status) );
  1067. }
  1068. return Status;
  1069. }
  1070. /*****************************************************************************
  1071. * PinPhysicalConnection()
  1072. *****************************************************************************
  1073. * Handles physical connection property access for the pin.
  1074. */
  1075. static
  1076. NTSTATUS
  1077. PinPhysicalConnection
  1078. (
  1079. IN PIRP Irp,
  1080. IN PKSP_PIN Pin,
  1081. OUT PVOID Data
  1082. )
  1083. {
  1084. PAGED_CODE();
  1085. ASSERT(Irp);
  1086. ASSERT(Pin);
  1087. PPROPERTY_CONTEXT pPropertyContext =
  1088. PPROPERTY_CONTEXT(Irp->Tail.Overlay.DriverContext[3]);
  1089. ASSERT(pPropertyContext);
  1090. PSUBDEVICE Subdevice =
  1091. pPropertyContext->pSubdevice;
  1092. ASSERT(Subdevice);
  1093. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1094. ASSERT(irpSp);
  1095. ASSERT(irpSp->DeviceObject);
  1096. PDEVICE_CONTEXT deviceContext =
  1097. PDEVICE_CONTEXT(irpSp->DeviceObject->DeviceExtension);
  1098. NTSTATUS ntStatus = STATUS_NOT_FOUND;
  1099. ULONG outPin;
  1100. PUNICODE_STRING outUnicodeString = NULL;
  1101. for
  1102. (
  1103. PLIST_ENTRY entry = deviceContext->PhysicalConnectionList.Flink;
  1104. entry != &deviceContext->PhysicalConnectionList;
  1105. entry = entry->Flink
  1106. )
  1107. {
  1108. PPHYSICALCONNECTION connection = PPHYSICALCONNECTION(entry);
  1109. if ( (connection->FromSubdevice == Subdevice)
  1110. && (connection->FromPin == Pin->PinId)
  1111. )
  1112. {
  1113. outPin = connection->ToPin;
  1114. if (connection->ToString)
  1115. {
  1116. outUnicodeString = connection->ToString;
  1117. }
  1118. else
  1119. {
  1120. ULONG ulIndex =
  1121. SubdeviceIndex(irpSp->DeviceObject,connection->ToSubdevice);
  1122. if (ulIndex != ULONG(-1))
  1123. {
  1124. ntStatus = STATUS_SUCCESS;
  1125. outUnicodeString = &deviceContext->SymbolicLinkNames[ulIndex];
  1126. }
  1127. }
  1128. break;
  1129. }
  1130. else
  1131. if ( (connection->ToSubdevice == Subdevice)
  1132. && (connection->ToPin == Pin->PinId)
  1133. )
  1134. {
  1135. outPin = connection->FromPin;
  1136. if (connection->FromString)
  1137. {
  1138. outUnicodeString = connection->FromString;
  1139. }
  1140. else
  1141. {
  1142. ULONG ulIndex =
  1143. SubdeviceIndex(irpSp->DeviceObject,connection->FromSubdevice);
  1144. if (ulIndex != ULONG(-1))
  1145. {
  1146. ntStatus = STATUS_SUCCESS;
  1147. outUnicodeString = &deviceContext->SymbolicLinkNames[ulIndex];
  1148. }
  1149. }
  1150. break;
  1151. }
  1152. }
  1153. if (!outUnicodeString)
  1154. {
  1155. ntStatus = STATUS_NOT_FOUND;
  1156. }
  1157. if (NT_SUCCESS(ntStatus))
  1158. {
  1159. ULONG outSize;
  1160. outSize = FIELD_OFFSET(KSPIN_PHYSICALCONNECTION,SymbolicLinkName[0]);
  1161. outSize += (outUnicodeString->Length + sizeof(UNICODE_NULL));
  1162. //
  1163. // Validate return buffer size.
  1164. //
  1165. ULONG outputBufferLength =
  1166. IoGetCurrentIrpStackLocation(Irp)->
  1167. Parameters.DeviceIoControl.OutputBufferLength;
  1168. if (!outputBufferLength)
  1169. {
  1170. Irp->IoStatus.Information = outSize;
  1171. ntStatus = STATUS_BUFFER_OVERFLOW;
  1172. }
  1173. else
  1174. if (outputBufferLength < outSize)
  1175. {
  1176. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1177. }
  1178. else
  1179. {
  1180. PKSPIN_PHYSICALCONNECTION out = PKSPIN_PHYSICALCONNECTION(Data);
  1181. out->Size = outSize;
  1182. out->Pin = outPin;
  1183. RtlCopyMemory
  1184. (
  1185. out->SymbolicLinkName,
  1186. outUnicodeString->Buffer,
  1187. outUnicodeString->Length
  1188. );
  1189. out->SymbolicLinkName[outUnicodeString->Length / sizeof(WCHAR)] = 0;
  1190. Irp->IoStatus.Information = outSize;
  1191. }
  1192. }
  1193. return ntStatus;
  1194. }
  1195. /*****************************************************************************
  1196. * PinCountHandler()
  1197. *****************************************************************************
  1198. * Handles pin count access for the pin.
  1199. */
  1200. void PinCountHandler
  1201. ( IN PPROPERTY_CONTEXT pPropertyContext,
  1202. IN ULONG pinId
  1203. )
  1204. {
  1205. PAGED_CODE();
  1206. ASSERT(pPropertyContext);
  1207. PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor = pPropertyContext->pSubdeviceDescriptor;
  1208. ASSERT(pSubdeviceDescriptor);
  1209. PSUBDEVICE Subdevice = pPropertyContext->pSubdevice;
  1210. ASSERT(Subdevice);
  1211. Subdevice->PinCount( pinId, &(pSubdeviceDescriptor->PinInstances[pinId].FilterNecessary),
  1212. &(pPropertyContext->pulPinInstanceCounts[pinId]),
  1213. &(pSubdeviceDescriptor->PinInstances[pinId].FilterPossible),
  1214. &(pSubdeviceDescriptor->PinInstances[pinId].GlobalCurrent),
  1215. &(pSubdeviceDescriptor->PinInstances[pinId].GlobalPossible) );
  1216. }
  1217. /*****************************************************************************
  1218. * PcPinPropertyHandler()
  1219. *****************************************************************************
  1220. * Property handler for pin properties on the filter.
  1221. */
  1222. PORTCLASSAPI
  1223. NTSTATUS
  1224. NTAPI
  1225. PcPinPropertyHandler
  1226. ( IN PIRP pIrp,
  1227. IN PKSP_PIN pKsPPin,
  1228. IN OUT PVOID pvData
  1229. )
  1230. {
  1231. PAGED_CODE();
  1232. ASSERT(pIrp);
  1233. ASSERT(pKsPPin);
  1234. PPROPERTY_CONTEXT pPropertyContext =
  1235. PPROPERTY_CONTEXT(pIrp->Tail.Overlay.DriverContext[3]);
  1236. ASSERT(pPropertyContext);
  1237. PSUBDEVICE_DESCRIPTOR pSubdeviceDescriptor =
  1238. pPropertyContext->pSubdeviceDescriptor;
  1239. ASSERT(pSubdeviceDescriptor);
  1240. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  1241. if
  1242. ( (pKsPPin->Property.Id != KSPROPERTY_PIN_CTYPES)
  1243. && (pKsPPin->PinId >= pSubdeviceDescriptor->PinCount)
  1244. )
  1245. {
  1246. ntStatus = STATUS_INVALID_PARAMETER;
  1247. }
  1248. else
  1249. {
  1250. switch (pKsPPin->Property.Id)
  1251. {
  1252. case KSPROPERTY_PIN_CTYPES:
  1253. case KSPROPERTY_PIN_DATAFLOW:
  1254. case KSPROPERTY_PIN_DATARANGES:
  1255. case KSPROPERTY_PIN_INTERFACES:
  1256. case KSPROPERTY_PIN_MEDIUMS:
  1257. case KSPROPERTY_PIN_COMMUNICATION:
  1258. case KSPROPERTY_PIN_CATEGORY:
  1259. case KSPROPERTY_PIN_NAME:
  1260. ntStatus =
  1261. KsPinPropertyHandler
  1262. (
  1263. pIrp,
  1264. PKSPROPERTY(pKsPPin),
  1265. pvData,
  1266. pSubdeviceDescriptor->PinCount,
  1267. pSubdeviceDescriptor->PinDescriptors
  1268. );
  1269. break;
  1270. case KSPROPERTY_PIN_DATAINTERSECTION:
  1271. ntStatus =
  1272. KsPinDataIntersection
  1273. (
  1274. pIrp,
  1275. pKsPPin,
  1276. pvData,
  1277. pSubdeviceDescriptor->PinCount,
  1278. pSubdeviceDescriptor->PinDescriptors,
  1279. PinIntersectHandler
  1280. );
  1281. break;
  1282. case KSPROPERTY_PIN_CINSTANCES:
  1283. if (pPropertyContext->pulPinInstanceCounts)
  1284. {
  1285. PinCountHandler(pPropertyContext,pKsPPin->PinId);
  1286. PKSPIN_CINSTANCES(pvData)->PossibleCount =
  1287. pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].FilterPossible;
  1288. PKSPIN_CINSTANCES(pvData)->CurrentCount =
  1289. pPropertyContext->pulPinInstanceCounts[pKsPPin->PinId];
  1290. pIrp->IoStatus.Information = sizeof(KSPIN_CINSTANCES);
  1291. ntStatus = STATUS_SUCCESS;
  1292. }
  1293. break;
  1294. case KSPROPERTY_PIN_GLOBALCINSTANCES:
  1295. if (pPropertyContext->pulPinInstanceCounts)
  1296. {
  1297. PinCountHandler(pPropertyContext,pKsPPin->PinId);
  1298. }
  1299. PKSPIN_CINSTANCES(pvData)->PossibleCount =
  1300. pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].GlobalPossible;
  1301. PKSPIN_CINSTANCES(pvData)->CurrentCount =
  1302. pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].GlobalCurrent;
  1303. pIrp->IoStatus.Information = sizeof(KSPIN_CINSTANCES);
  1304. ntStatus = STATUS_SUCCESS;
  1305. break;
  1306. case KSPROPERTY_PIN_NECESSARYINSTANCES:
  1307. if (pPropertyContext->pulPinInstanceCounts)
  1308. {
  1309. PinCountHandler(pPropertyContext,pKsPPin->PinId);
  1310. *PULONG(pvData) = pSubdeviceDescriptor->PinInstances[pKsPPin->PinId].FilterNecessary;
  1311. pIrp->IoStatus.Information = sizeof(ULONG);
  1312. ntStatus = STATUS_SUCCESS;
  1313. }
  1314. break;
  1315. case KSPROPERTY_PIN_PHYSICALCONNECTION:
  1316. ntStatus =
  1317. PinPhysicalConnection
  1318. (
  1319. pIrp,
  1320. pKsPPin,
  1321. pvData
  1322. );
  1323. break;
  1324. default:
  1325. ntStatus = STATUS_NOT_FOUND;
  1326. break;
  1327. }
  1328. }
  1329. return ntStatus;
  1330. }