Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1400 lines
32 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This module provides the functions related to device enumeration.
  7. Author:
  8. Andy Thornton (andrewth) 20-Oct-97
  9. Revision History:
  10. --*/
  11. #include "mfp.h"
  12. #pragma hdrstop
  13. #include <initguid.h>
  14. #include <mf.h>
  15. #include <wdmguid.h>
  16. NTSTATUS
  17. MfBuildChildRequirements(
  18. IN PMF_CHILD_EXTENSION Child,
  19. OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList
  20. );
  21. NTSTATUS
  22. MfBuildDeviceID(
  23. IN PMF_PARENT_EXTENSION Parent,
  24. OUT PWSTR *DeviceID
  25. );
  26. NTSTATUS
  27. MfBuildInstanceID(
  28. IN PMF_CHILD_EXTENSION Child,
  29. OUT PWSTR *InstanceID
  30. );
  31. NTSTATUS
  32. MfBuildResourceMap(
  33. IN PUCHAR Data,
  34. IN ULONG Length,
  35. OUT PMF_RESOURCE_MAP *ResourceMap
  36. );
  37. NTSTATUS
  38. MfBuildVaryingResourceMap(
  39. IN PMF_REGISTRY_VARYING_RESOURCE_MAP RegistryMap,
  40. IN ULONG Length,
  41. OUT PMF_VARYING_RESOURCE_MAP *ResourceMap
  42. );
  43. NTSTATUS
  44. MfEnumRegistryChild(
  45. IN HANDLE ParentHandle,
  46. IN ULONG Index,
  47. IN OUT PMF_DEVICE_INFO Info
  48. );
  49. NTSTATUS
  50. MfEnumerate(
  51. IN PMF_PARENT_EXTENSION Parent
  52. );
  53. NTSTATUS
  54. MfEnumerateFromInterface(
  55. IN PMF_PARENT_EXTENSION Parent
  56. );
  57. NTSTATUS
  58. MfEnumerateFromRegistry(
  59. IN PMF_PARENT_EXTENSION Parent
  60. );
  61. BOOLEAN
  62. MfIsChildEnumeratedAlready(
  63. PMF_PARENT_EXTENSION Parent,
  64. PUNICODE_STRING childName
  65. );
  66. BOOLEAN
  67. MfIsResourceShared(
  68. IN PMF_PARENT_EXTENSION Parent,
  69. IN UCHAR Index,
  70. IN ULONG Offset,
  71. IN ULONG Size
  72. );
  73. NTSTATUS
  74. MfParentResourceToChildRequirement(
  75. IN PMF_PARENT_EXTENSION Parent,
  76. IN PMF_CHILD_EXTENSION Child,
  77. IN UCHAR Index,
  78. IN ULONG Offset OPTIONAL,
  79. IN ULONG Size OPTIONAL,
  80. OUT PIO_RESOURCE_DESCRIPTOR Requirement
  81. );
  82. #ifdef ALLOC_PRAGMA
  83. #pragma alloc_text(PAGE, MfBuildChildRequirements)
  84. #pragma alloc_text(PAGE, MfBuildDeviceID)
  85. #pragma alloc_text(PAGE, MfBuildInstanceID)
  86. #pragma alloc_text(PAGE, MfBuildResourceMap)
  87. #pragma alloc_text(PAGE, MfBuildVaryingResourceMap)
  88. #pragma alloc_text(PAGE, MfEnumRegistryChild)
  89. #pragma alloc_text(PAGE, MfEnumerate)
  90. #pragma alloc_text(PAGE, MfEnumerateFromInterface)
  91. #pragma alloc_text(PAGE, MfEnumerateFromRegistry)
  92. #pragma alloc_text(PAGE, MfIsResourceShared)
  93. #pragma alloc_text(PAGE, MfParentResourceToChildRequirement)
  94. #endif
  95. NTSTATUS
  96. MfBuildResourceMap(
  97. IN PUCHAR Data,
  98. IN ULONG Length,
  99. OUT PMF_RESOURCE_MAP *ResourceMap
  100. )
  101. /*++
  102. Routine Description:
  103. Constructs an MF_RESOURCE_MAP from information returned from the registry
  104. Arguments:
  105. Data - The raw REG_BINARY data from the registry
  106. Length - Length in bytes of Data
  107. ResourceMap - On success a pointer to the resource map. Memory should be
  108. freed using ExFreePool when no longer required
  109. Return Value:
  110. Status code indicating the success or otherwise of the operation.
  111. --*/
  112. {
  113. PMF_RESOURCE_MAP resourceMap;
  114. //
  115. // Allocate the resource map structure, add space for a count
  116. //
  117. resourceMap = ExAllocatePoolWithTag(PagedPool,
  118. sizeof(MF_RESOURCE_MAP) +
  119. (Length - 1) * sizeof(UCHAR),
  120. MF_RESOURCE_MAP_TAG
  121. );
  122. if (!resourceMap) {
  123. return STATUS_INSUFFICIENT_RESOURCES;
  124. }
  125. //
  126. // Fill it in
  127. //
  128. resourceMap->Count = Length;
  129. RtlCopyMemory(&resourceMap->Resources, Data, Length);
  130. //
  131. // Hand it back to the caller
  132. //
  133. *ResourceMap = resourceMap;
  134. return STATUS_SUCCESS;
  135. }
  136. NTSTATUS
  137. MfBuildVaryingResourceMap(
  138. IN PMF_REGISTRY_VARYING_RESOURCE_MAP RegistryMap,
  139. IN ULONG Length,
  140. OUT PMF_VARYING_RESOURCE_MAP *ResourceMap
  141. )
  142. /*++
  143. Routine Description:
  144. Constructs an MF_VARYING_RESOURCE_MAP from information returned from the registry
  145. Arguments:
  146. RegistryMap - The raw REG_BINARY data from the registry
  147. Length - Length in bytes of RegistryMap
  148. ResourceMap - On success a pointer to the resource map. Memory should be
  149. freed using ExFreePool when no longer required
  150. Return Value:
  151. Status code indicating the success or otherwise of the operation.
  152. --*/
  153. {
  154. PMF_VARYING_RESOURCE_MAP resourceMap;
  155. PMF_VARYING_RESOURCE_ENTRY current;
  156. PMF_REGISTRY_VARYING_RESOURCE_MAP currentRegistry;
  157. ULONG count;
  158. if (Length % sizeof(MF_REGISTRY_VARYING_RESOURCE_MAP) != 0) {
  159. return STATUS_INVALID_PARAMETER;
  160. }
  161. count = Length / sizeof(MF_REGISTRY_VARYING_RESOURCE_MAP);
  162. //
  163. // Allocate the resource map structure
  164. //
  165. resourceMap = ExAllocatePoolWithTag(PagedPool,
  166. sizeof(MF_VARYING_RESOURCE_MAP) +
  167. (count-1) * sizeof(MF_VARYING_RESOURCE_ENTRY),
  168. MF_VARYING_MAP_TAG
  169. );
  170. if (!resourceMap) {
  171. return STATUS_INSUFFICIENT_RESOURCES;
  172. }
  173. //
  174. // Fill it in
  175. //
  176. resourceMap->Count = count;
  177. //
  178. // Translate the registry data into an aligned internal format
  179. //
  180. current = resourceMap->Resources;
  181. currentRegistry = RegistryMap;
  182. while (count--) {
  183. current->ResourceIndex = currentRegistry->ResourceIndex;
  184. current->Offset = currentRegistry->Offset;
  185. current->Size = currentRegistry->Size;
  186. currentRegistry++;
  187. current++;
  188. }
  189. //
  190. // Hand it back to the caller
  191. //
  192. *ResourceMap = resourceMap;
  193. return STATUS_SUCCESS;
  194. }
  195. NTSTATUS
  196. MfEnumRegistryChild(
  197. IN HANDLE ParentHandle,
  198. IN ULONG Index,
  199. IN OUT PMF_DEVICE_INFO Info
  200. )
  201. /*++
  202. Routine Description:
  203. Initialized an MF_DEVICE_INFO from information stored in the registry.
  204. Arguments:
  205. ParentHandle - Handle to the registry key under which the data is stored
  206. Index - Index of the subkey to use
  207. Info - Pointer to the device info that should be filled in
  208. Return Value:
  209. Status code indicating the success or otherwise of the operation.
  210. --*/
  211. {
  212. NTSTATUS status;
  213. PMF_REGISTRY_VARYING_RESOURCE_MAP varyingMap = NULL;
  214. PUCHAR resourceMap = NULL;
  215. ULONG varyingMapSize = 0, resourceMapSize = 0, stringSize = 0;
  216. BOOLEAN gotId = FALSE;
  217. ASSERT(ParentHandle && Info);
  218. //
  219. // Retrieve the data - we must have a HardwareID and/or CompatibleID
  220. //
  221. status = MfGetRegistryValue(ParentHandle,
  222. L"HardwareID",
  223. REG_MULTI_SZ,
  224. MF_GETREG_SZ_TO_MULTI_SZ,
  225. &stringSize,
  226. &Info->HardwareID.Buffer
  227. );
  228. if (NT_SUCCESS(status)) {
  229. gotId = TRUE;
  230. } else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
  231. goto cleanup;
  232. }
  233. ASSERT(stringSize <= MAXUSHORT);
  234. Info->HardwareID.Length = (USHORT)stringSize;
  235. Info->HardwareID.MaximumLength = Info->HardwareID.Length;
  236. //
  237. // ... CompatibleID ...
  238. //
  239. stringSize = 0;
  240. status = MfGetRegistryValue(ParentHandle,
  241. L"CompatibleID",
  242. REG_MULTI_SZ,
  243. MF_GETREG_SZ_TO_MULTI_SZ,
  244. &stringSize,
  245. &Info->CompatibleID.Buffer
  246. );
  247. if (NT_SUCCESS(status)) {
  248. gotId = TRUE;
  249. } else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
  250. goto cleanup;
  251. }
  252. ASSERT(stringSize <= MAXUSHORT);
  253. Info->CompatibleID.Length = (USHORT)stringSize;
  254. Info->CompatibleID.MaximumLength = Info->CompatibleID.Length;
  255. //
  256. // Now check that we have got an ID - if we don't then fail
  257. //
  258. if (!gotId) {
  259. status = STATUS_UNSUCCESSFUL;
  260. goto cleanup;
  261. }
  262. //
  263. // ...ResourceMap...
  264. //
  265. status = MfGetRegistryValue(ParentHandle,
  266. L"ResourceMap",
  267. REG_BINARY,
  268. 0, // flags
  269. &resourceMapSize,
  270. &resourceMap
  271. );
  272. if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) {
  273. goto cleanup;
  274. }
  275. //
  276. // If we have a resource map the store it in our device info
  277. //
  278. if (resourceMap) {
  279. status = MfBuildResourceMap(resourceMap,
  280. resourceMapSize,
  281. &Info->ResourceMap
  282. );
  283. ExFreePool(resourceMap);
  284. resourceMap = NULL;
  285. if (!NT_SUCCESS(status)) {
  286. goto cleanup;
  287. }
  288. }
  289. //
  290. // ...VaryingResourceMap...
  291. //
  292. status = MfGetRegistryValue(ParentHandle,
  293. L"VaryingResourceMap",
  294. REG_BINARY,
  295. 0, // flags
  296. &varyingMapSize,
  297. &varyingMap
  298. );
  299. if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) {
  300. goto cleanup;
  301. }
  302. if (varyingMap) {
  303. status = MfBuildVaryingResourceMap(varyingMap,
  304. varyingMapSize,
  305. &Info->VaryingResourceMap
  306. );
  307. ExFreePool(varyingMap);
  308. varyingMap = NULL;
  309. if (!NT_SUCCESS(status)) {
  310. goto cleanup;
  311. }
  312. }
  313. //
  314. // ...MfFlags
  315. //
  316. status = MfGetRegistryValue(ParentHandle,
  317. L"MFFlags",
  318. REG_DWORD,
  319. 0, // flags
  320. NULL,
  321. (PVOID) &Info->MfFlags
  322. );
  323. if (!NT_SUCCESS(status) && status != STATUS_OBJECT_NAME_NOT_FOUND) {
  324. goto cleanup;
  325. }
  326. return STATUS_SUCCESS;
  327. cleanup:
  328. MfFreeDeviceInfo(Info);
  329. //
  330. // If any of the values were of the wrong type then this is an invalid
  331. // MF entry.
  332. //
  333. if (status == STATUS_OBJECT_TYPE_MISMATCH) {
  334. status = STATUS_INVALID_PARAMETER;
  335. }
  336. return status;
  337. }
  338. NTSTATUS
  339. MfEnumerate(
  340. IN PMF_PARENT_EXTENSION Parent
  341. )
  342. /*++
  343. Routine Description:
  344. Allocates and initialies the Children list of PDOs for this MF device.
  345. First from the registry and then by querying an MF_ENUMERATION_INTERFACE from
  346. its PDO.
  347. Arguments:
  348. Parent - The MF device that should be enumerated
  349. Return Value:
  350. Status code indicating the success or otherwise of the operation.
  351. --*/
  352. {
  353. NTSTATUS status;
  354. PMF_CHILD_EXTENSION current, next;
  355. //
  356. // Try to get our children from the registry
  357. //
  358. status = MfEnumerateFromRegistry(Parent);
  359. if (!NT_SUCCESS(status)) {
  360. //
  361. // STATUS_UNSUCCESSFUL indicates that there wasn't any MF information
  362. // in the registry
  363. //
  364. if (status == STATUS_UNSUCCESSFUL) {
  365. //
  366. // See if our parent has an MF_ENUMERATION_INTERFACE for us...
  367. //
  368. status = MfEnumerateFromInterface(Parent);
  369. }
  370. }
  371. return status;
  372. }
  373. NTSTATUS
  374. MfEnumerateFromRegistry(
  375. IN PMF_PARENT_EXTENSION Parent
  376. )
  377. /*++
  378. Routine Description:
  379. Allocates and initialies the Children list of PDOs for this MF device by
  380. looking in the registry
  381. Arguments:
  382. Parent - The MF device that should be enumerated
  383. Return Value:
  384. Status code indicating the success or otherwise of the operation.
  385. STATUS_UNSUCCESSFUL indicates that no MF information was found in the
  386. registry.
  387. --*/
  388. {
  389. NTSTATUS status;
  390. HANDLE parentHandle = NULL, childHandle = NULL;
  391. ULONG index = 0;
  392. UNICODE_STRING childName;
  393. PDEVICE_OBJECT pdo;
  394. PMF_CHILD_EXTENSION child;
  395. MF_DEVICE_INFO info;
  396. ASSERT(!(Parent->Common.DeviceState & MF_DEVICE_ENUMERATED));
  397. //
  398. // Open the "Device Parameters" key for our PDO and see what the INF file
  399. // put there.
  400. //
  401. status = IoOpenDeviceRegistryKey(Parent->PhysicalDeviceObject,
  402. PLUGPLAY_REGKEY_DEVICE,
  403. KEY_READ,
  404. &parentHandle
  405. );
  406. if (!NT_SUCCESS(status)) {
  407. goto cleanup;
  408. }
  409. ASSERT(parentHandle);
  410. //
  411. // Iterate over keys
  412. //
  413. for (;;) {
  414. //
  415. // Open the child key for this info
  416. //
  417. status = MfGetSubkeyByIndex(parentHandle,
  418. index,
  419. KEY_READ,
  420. &childHandle,
  421. &childName
  422. );
  423. if (status == STATUS_NO_MORE_ENTRIES) {
  424. if (IsListEmpty(&Parent->Children)) {
  425. //
  426. // There wern't any children - fail
  427. //
  428. status = STATUS_UNSUCCESSFUL;
  429. goto cleanup;
  430. }
  431. //
  432. // We've found all the children
  433. //
  434. break;
  435. }
  436. if (!NT_SUCCESS(status)) {
  437. goto cleanup;
  438. }
  439. RtlZeroMemory(&info, sizeof(info));
  440. if (!MfIsChildEnumeratedAlready(Parent, &childName)) {
  441. info.Name = childName;
  442. //
  443. // Query the registry for the info
  444. //
  445. status = MfEnumRegistryChild(childHandle, index, &info);
  446. if (NT_SUCCESS(status)) {
  447. status = MfCreatePdo(Parent, &pdo);
  448. if (NT_SUCCESS(status)) {
  449. child = (PMF_CHILD_EXTENSION) pdo->DeviceExtension;
  450. child->Info = info;
  451. } else {
  452. MfFreeDeviceInfo(&info);
  453. }
  454. }
  455. } else {
  456. ExFreePool(childName.Buffer);
  457. }
  458. ZwClose(childHandle);
  459. index++;
  460. }
  461. ZwClose(parentHandle);
  462. return STATUS_SUCCESS;
  463. cleanup:
  464. if (parentHandle) {
  465. ZwClose(parentHandle);
  466. }
  467. if (childHandle) {
  468. ZwClose(childHandle);
  469. }
  470. return status;
  471. }
  472. NTSTATUS
  473. MfEnumerateFromInterface(
  474. IN PMF_PARENT_EXTENSION Parent
  475. )
  476. /*++
  477. Routine Description:
  478. Allocates and initialies the Children list of PDOs for this MF device by
  479. querying its pdo for an interface
  480. Arguments:
  481. Parent - The MF device that should be enumerated
  482. Return Value:
  483. Status code indicating the success or otherwise of the operation.
  484. --*/
  485. {
  486. NTSTATUS status;
  487. IO_STACK_LOCATION request;
  488. MF_ENUMERATION_INTERFACE interface;
  489. PDEVICE_OBJECT pdo;
  490. PMF_CHILD_EXTENSION child;
  491. MF_DEVICE_INFO info;
  492. ULONG index = 0;
  493. //
  494. // Send a query interface IRP to our parent's PDO
  495. //
  496. RtlZeroMemory(&request, sizeof(IO_STACK_LOCATION));
  497. RtlZeroMemory(&interface, sizeof(MF_ENUMERATION_INTERFACE));
  498. request.MajorFunction = IRP_MJ_PNP;
  499. request.MinorFunction = IRP_MN_QUERY_INTERFACE;
  500. request.Parameters.QueryInterface.InterfaceType = &GUID_MF_ENUMERATION_INTERFACE;
  501. request.Parameters.QueryInterface.Size = sizeof(MF_ENUMERATION_INTERFACE);
  502. request.Parameters.QueryInterface.Version = 1;
  503. request.Parameters.QueryInterface.Interface = (PINTERFACE) &interface;
  504. status = MfSendPnpIrp(Parent->PhysicalDeviceObject, &request, NULL);
  505. if (!NT_SUCCESS(status)) {
  506. goto cleanup;
  507. }
  508. for (;;) {
  509. RtlZeroMemory(&info, sizeof(info));
  510. //
  511. // Query the interface for the info
  512. //
  513. status = interface.EnumerateChild(interface.Context,
  514. index,
  515. &info
  516. );
  517. if (!NT_SUCCESS(status)) {
  518. if (status == STATUS_NO_MORE_ENTRIES) {
  519. if (IsListEmpty(&Parent->Children)) {
  520. //
  521. // There wern't any children - fail
  522. //
  523. status = STATUS_UNSUCCESSFUL;
  524. goto cleanup;
  525. }
  526. status = STATUS_SUCCESS;
  527. break;
  528. } else {
  529. goto cleanup;
  530. }
  531. }
  532. if (!MfIsChildEnumeratedAlready(Parent, &info.Name)) {
  533. //
  534. // Create a device object
  535. //
  536. status = MfCreatePdo(Parent, &pdo);
  537. if (NT_SUCCESS(status)) {
  538. child = (PMF_CHILD_EXTENSION) pdo->DeviceExtension;
  539. child->Info = info;
  540. } else {
  541. MfFreeDeviceInfo(&info);
  542. }
  543. } else {
  544. MfFreeDeviceInfo(&info);
  545. }
  546. index++;
  547. }
  548. interface.InterfaceDereference(interface.Context);
  549. return STATUS_SUCCESS;
  550. cleanup:
  551. return status;
  552. }
  553. NTSTATUS
  554. MfBuildDeviceID(
  555. IN PMF_PARENT_EXTENSION Parent,
  556. OUT PWSTR *DeviceID
  557. )
  558. /*++
  559. Routine Description:
  560. Constructs a device ID for the parent device
  561. Arguments:
  562. Parent - Parent the device ID should be constructed for
  563. DeviceID - On success the device id
  564. Return Value:
  565. Status code indicating the success or otherwise of the operation.
  566. --*/
  567. {
  568. #define MF_ENUMERATOR_STRING L"MF\\"
  569. NTSTATUS status;
  570. PWSTR source, destination, id = NULL;
  571. id = ExAllocatePoolWithTag(PagedPool,
  572. sizeof(MF_ENUMERATOR_STRING) // This includes the termination NULL
  573. + Parent->DeviceID.Length,
  574. MF_DEVICE_ID_TAG
  575. );
  576. if (!id) {
  577. status = STATUS_INSUFFICIENT_RESOURCES;
  578. goto cleanup;
  579. }
  580. RtlCopyMemory(id,
  581. MF_ENUMERATOR_STRING,
  582. sizeof(MF_ENUMERATOR_STRING) - sizeof(UNICODE_NULL)
  583. );
  584. //
  585. // Copy the device ID of the parent to the buffer replacing each
  586. // occurence of '\' with '#'
  587. //
  588. destination = id +
  589. (sizeof(MF_ENUMERATOR_STRING) - sizeof(UNICODE_NULL)) / sizeof(WCHAR);
  590. FOR_ALL_IN_ARRAY(Parent->DeviceID.Buffer,
  591. Parent->DeviceID.Length / sizeof(WCHAR),
  592. source) {
  593. ASSERT(*source != L' ');
  594. if (*source == L'\\') {
  595. *destination = L'#';
  596. } else {
  597. *destination = *source;
  598. }
  599. destination++;
  600. }
  601. //
  602. // Finally null terminate it
  603. //
  604. *destination = UNICODE_NULL;
  605. *DeviceID = id;
  606. return STATUS_SUCCESS;
  607. cleanup:
  608. if (id) {
  609. ExFreePool(id);
  610. }
  611. return status;
  612. }
  613. NTSTATUS
  614. MfBuildInstanceID(
  615. IN PMF_CHILD_EXTENSION Child,
  616. OUT PWSTR *InstanceID
  617. )
  618. /*++
  619. Routine Description:
  620. Constructs a instance ID for this child
  621. Arguments:
  622. Child - Child the ID should be constructed for
  623. DeviceID - On success the device id
  624. Return Value:
  625. Status code indicating the success or otherwise of the operation.
  626. --*/
  627. {
  628. NTSTATUS status;
  629. PWSTR current, id = NULL;
  630. id = ExAllocatePoolWithTag(PagedPool,
  631. Child->Parent->InstanceID.Length + sizeof(L'#')
  632. + Child->Info.Name.Length + sizeof(UNICODE_NULL),
  633. MF_INSTANCE_ID_TAG
  634. );
  635. if (!id) {
  636. status = STATUS_INSUFFICIENT_RESOURCES;
  637. goto cleanup;
  638. }
  639. //
  640. // Copy the parents instance ID...
  641. //
  642. RtlCopyMemory(id,
  643. Child->Parent->InstanceID.Buffer,
  644. Child->Parent->InstanceID.Length
  645. );
  646. current = id + Child->Parent->InstanceID.Length / sizeof(WCHAR);
  647. //
  648. // ...then the '#'...
  649. //
  650. *current++ = L'#';
  651. //
  652. // ...the child name...
  653. //
  654. RtlCopyMemory(current,
  655. Child->Info.Name.Buffer,
  656. Child->Info.Name.Length
  657. );
  658. //
  659. // ...and last but not least the NULL termination
  660. //
  661. current += Child->Info.Name.Length / sizeof(WCHAR);
  662. *current = UNICODE_NULL;
  663. *InstanceID = id;
  664. return STATUS_SUCCESS;
  665. cleanup:
  666. if (id) {
  667. ExFreePool(id);
  668. }
  669. return status;
  670. }
  671. BOOLEAN
  672. MfIsResourceShared(
  673. IN PMF_PARENT_EXTENSION Parent,
  674. IN UCHAR Index,
  675. IN ULONG Offset,
  676. IN ULONG Size
  677. )
  678. /*++
  679. Routine Description:
  680. Determines if the Parent resource of Index has been requested by more than
  681. one child, in which case the children wanting that resource should claim it
  682. shared.
  683. Arguments:
  684. Parent - The parent device of the MF subtree.
  685. Index - The index of the parent resources we are interested in.
  686. Return Value:
  687. TRUE if the resource is shared, FALSE otherwise
  688. --*/
  689. {
  690. PMF_CHILD_EXTENSION current;
  691. PUCHAR resource;
  692. PMF_VARYING_RESOURCE_ENTRY varyingResource;
  693. PLIST_ENTRY currentEntry;
  694. BOOLEAN result = FALSE;
  695. ULONG refCount = 0;
  696. //
  697. // Iterate through the list of children in the parent
  698. //
  699. MfAcquireChildrenLock(Parent);
  700. for (currentEntry = Parent->Children.Flink;
  701. currentEntry != &Parent->Children;
  702. currentEntry = currentEntry->Flink) {
  703. current = CONTAINING_RECORD(currentEntry,
  704. MF_CHILD_EXTENSION,
  705. ListEntry);
  706. //
  707. // Iterate through the array of descriptors
  708. //
  709. if (current->Info.ResourceMap) {
  710. FOR_ALL_IN_ARRAY(current->Info.ResourceMap->Resources,
  711. current->Info.ResourceMap->Count,
  712. resource) {
  713. if (*resource == Index) {
  714. refCount++;
  715. if (refCount > 1) {
  716. result = TRUE;
  717. goto out;
  718. }
  719. }
  720. }
  721. }
  722. if (current->Info.VaryingResourceMap) {
  723. FOR_ALL_IN_ARRAY(current->Info.VaryingResourceMap->Resources,
  724. current->Info.VaryingResourceMap->Count,
  725. varyingResource) {
  726. //
  727. // If indexes are the same and ranges overlap, we have a reference
  728. //
  729. if ((varyingResource->ResourceIndex == Index) &&
  730. ( ( Size == 0) ||
  731. ( varyingResource->Offset >= Offset &&
  732. varyingResource->Offset < Offset + Size) ||
  733. ( Offset >= varyingResource->Offset &&
  734. Offset < varyingResource->Offset + varyingResource->Size))) {
  735. refCount++;
  736. if (refCount > 1) {
  737. result = TRUE;
  738. goto out;
  739. }
  740. }
  741. }
  742. }
  743. }
  744. out:
  745. MfReleaseChildrenLock(Parent);
  746. return result;
  747. }
  748. NTSTATUS
  749. MfBuildChildRequirements(
  750. IN PMF_CHILD_EXTENSION Child,
  751. OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList
  752. )
  753. /*++
  754. Routine Description:
  755. Constructs a requirements list for Child based on the resources allocated
  756. to the childs parent
  757. Arguments:
  758. Child - Child the requirements list is to be built for
  759. RequirementsList - On success a pointer to the list
  760. Return Value:
  761. Status code indicating the success or otherwise of the operation.
  762. --*/
  763. {
  764. NTSTATUS status;
  765. ULONG size, count = 0;
  766. PIO_RESOURCE_REQUIREMENTS_LIST requirements = NULL;
  767. PIO_RESOURCE_DESCRIPTOR descriptor;
  768. PCHAR resource;
  769. PMF_VARYING_RESOURCE_ENTRY varyingResource;
  770. //
  771. // Check if we have a resource list. If not, then MF has been
  772. // loaded on device that doesn't consume resources. As a result,
  773. // the children can't consume resources either.
  774. //
  775. if (Child->Parent->ResourceList == NULL) {
  776. *RequirementsList = NULL;
  777. return STATUS_SUCCESS;
  778. }
  779. //
  780. // Calculate the size of the resource list
  781. //
  782. if (Child->Info.VaryingResourceMap) {
  783. count += Child->Info.VaryingResourceMap->Count;
  784. }
  785. if (Child->Info.ResourceMap) {
  786. count += Child->Info.ResourceMap->Count;
  787. }
  788. //
  789. // Allocate the buffer
  790. //
  791. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  792. (count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  793. requirements = ExAllocatePoolWithTag(PagedPool,
  794. size,
  795. MF_CHILD_REQUIREMENTS_TAG
  796. );
  797. if (!requirements) {
  798. status = STATUS_INSUFFICIENT_RESOURCES;
  799. goto cleanup;
  800. }
  801. //
  802. // Build the list
  803. //
  804. RtlZeroMemory(requirements, size);
  805. requirements->ListSize = size;
  806. requirements->InterfaceType = Child->Parent->ResourceList->List[0].InterfaceType;
  807. requirements->BusNumber = Child->Parent->ResourceList->List[0].BusNumber;
  808. requirements->AlternativeLists = 1;
  809. requirements->List[0].Version = MF_CM_RESOURCE_VERSION;
  810. requirements->List[0].Revision = MF_CM_RESOURCE_REVISION;
  811. requirements->List[0].Count = count;
  812. descriptor = requirements->List[0].Descriptors;
  813. if (Child->Info.ResourceMap) {
  814. FOR_ALL_IN_ARRAY(Child->Info.ResourceMap->Resources,
  815. Child->Info.ResourceMap->Count,
  816. resource) {
  817. status = MfParentResourceToChildRequirement(Child->Parent,
  818. Child,
  819. *resource,
  820. 0,
  821. 0,
  822. descriptor
  823. );
  824. if (!NT_SUCCESS(status)) {
  825. goto cleanup;
  826. }
  827. descriptor++;
  828. }
  829. }
  830. if (Child->Info.VaryingResourceMap) {
  831. FOR_ALL_IN_ARRAY(Child->Info.VaryingResourceMap->Resources,
  832. Child->Info.VaryingResourceMap->Count,
  833. varyingResource) {
  834. status = MfParentResourceToChildRequirement(Child->Parent,
  835. Child,
  836. varyingResource->ResourceIndex,
  837. varyingResource->Offset,
  838. varyingResource->Size,
  839. descriptor
  840. );
  841. if (!NT_SUCCESS(status)) {
  842. goto cleanup;
  843. }
  844. descriptor++;
  845. }
  846. }
  847. *RequirementsList = requirements;
  848. return STATUS_SUCCESS;
  849. cleanup:
  850. *RequirementsList = NULL;
  851. if (requirements) {
  852. ExFreePool(requirements);
  853. }
  854. return status;
  855. }
  856. NTSTATUS
  857. MfParentResourceToChildRequirement(
  858. IN PMF_PARENT_EXTENSION Parent,
  859. IN PMF_CHILD_EXTENSION Child,
  860. IN UCHAR Index,
  861. IN ULONG Offset OPTIONAL,
  862. IN ULONG Size OPTIONAL,
  863. OUT PIO_RESOURCE_DESCRIPTOR Requirement
  864. )
  865. /*++
  866. Routine Description:
  867. This function build an requirements descriptor for a resource the parent is
  868. started with.
  869. Arguments:
  870. Parent - The parent device of the MF subtree.
  871. Index - The index of the parent resources we are interested in.
  872. Offset - The offset within the parent resource of the requirement.
  873. This is actually used as an index into a table stored in the parent
  874. resource list describing the mapping from this given offset to the
  875. real offset to be used. This allows for varying resource maps to
  876. access the same offset within the same resource and get a different
  877. requirement. If Size == 0, this is ignored.
  878. Size - The length of the requirement. If set to 0, it is assumed to be
  879. the length of the parent resource.
  880. Requirement - Pointer to a descriptor that should be filled in
  881. Return Value:
  882. Success or otherwise of the operation
  883. --*/
  884. {
  885. NTSTATUS status;
  886. CM_PARTIAL_RESOURCE_DESCRIPTOR resource;
  887. PMF_RESOURCE_TYPE resType;
  888. ULONG effectiveOffset;
  889. ULONGLONG resourceStart;
  890. ULONG dummyLength;
  891. ASSERT(Parent->ResourceList->Count == 1);
  892. //
  893. // Bounds check the index
  894. //
  895. if (Index > Parent->ResourceList->List[0].PartialResourceList.Count) {
  896. if (Child->Info.MfFlags & MF_FLAGS_FILL_IN_UNKNOWN_RESOURCE) {
  897. //
  898. // Fill in a null resource list
  899. //
  900. RtlZeroMemory(Requirement, sizeof(IO_RESOURCE_DESCRIPTOR));
  901. Requirement->Type = CmResourceTypeNull;
  902. return STATUS_SUCCESS;
  903. }
  904. return STATUS_INVALID_PARAMETER;
  905. }
  906. RtlCopyMemory(&resource,
  907. &Parent->ResourceList->List[0].PartialResourceList.PartialDescriptors[Index],
  908. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  909. //
  910. // Find the appropriate resource type for the resource -> requirement
  911. // function if this is an arbitrated resource
  912. //
  913. if (!(resource.Type & CmResourceTypeNonArbitrated)) {
  914. resType = MfFindResourceType(resource.Type);
  915. if (!resType) {
  916. DEBUG_MSG(1,
  917. ("Unknown resource type %i at parent index 0x%x\n",
  918. resource.Type,
  919. Index
  920. ));
  921. return STATUS_INVALID_PARAMETER;
  922. }
  923. //
  924. // update the resource with the correct offset and length
  925. // if size == 0 we assume it is optional and don't do the update
  926. //
  927. if (Size) {
  928. status = resType->UnpackResource(&resource,
  929. &resourceStart,
  930. &dummyLength);
  931. if (!NT_SUCCESS(status)) {
  932. return status;
  933. }
  934. status = resType->UpdateResource(&resource,
  935. resourceStart+Offset,
  936. Size
  937. );
  938. if (!NT_SUCCESS(status)) {
  939. return status;
  940. }
  941. }
  942. //
  943. // Convert the resource to a requirement
  944. //
  945. status = resType->RequirementFromResource(&resource, Requirement);
  946. if (!NT_SUCCESS(status)) {
  947. return status;
  948. }
  949. //
  950. // Update the share disposition if necessary
  951. //
  952. if (MfIsResourceShared(Parent, Index, Offset, Size)) {
  953. Requirement->ShareDisposition = CmResourceShareShared;
  954. }
  955. } else {
  956. //
  957. // This is a non-arbitrated resource so it is modled after a device
  958. // private, just copy the data
  959. //
  960. Requirement->Type = resource.Type;
  961. Requirement->ShareDisposition = resource.ShareDisposition;
  962. Requirement->Flags = resource.Flags;
  963. Requirement->u.DevicePrivate.Data[0] = resource.u.DevicePrivate.Data[0];
  964. Requirement->u.DevicePrivate.Data[1] = resource.u.DevicePrivate.Data[1];
  965. Requirement->u.DevicePrivate.Data[2] = resource.u.DevicePrivate.Data[2];
  966. }
  967. return STATUS_SUCCESS;
  968. }
  969. BOOLEAN
  970. MfIsChildEnumeratedAlready(
  971. PMF_PARENT_EXTENSION Parent,
  972. PUNICODE_STRING ChildName
  973. )
  974. /*++
  975. Routine Description:
  976. This function checks whether a child with this name has already
  977. been enumerated.
  978. Arguments:
  979. Parent - The parent device of the MF subtree.
  980. ChildName - unicode string to compare to existing child names
  981. Return Value:
  982. TRUE or FALSE
  983. --*/
  984. {
  985. PMF_CHILD_EXTENSION currentChild;
  986. PLIST_ENTRY currentEntry;
  987. BOOLEAN result = FALSE;
  988. for (currentEntry = Parent->Children.Flink;
  989. currentEntry != &Parent->Children;
  990. currentEntry = currentEntry->Flink) {
  991. currentChild = CONTAINING_RECORD(currentEntry,
  992. MF_CHILD_EXTENSION,
  993. ListEntry);
  994. //
  995. // Comparison is case-sensitive because there is no reason it
  996. // shouldn't be.
  997. //
  998. if (RtlEqualUnicodeString(&currentChild->Info.Name,
  999. ChildName,
  1000. FALSE)) {
  1001. result = TRUE;
  1002. break;
  1003. }
  1004. }
  1005. return result;
  1006. }