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.

754 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. translate.c
  5. Abstract:
  6. This file implements translator interfaces for busses
  7. enumerated by ACPI.
  8. The actual translation information about this bus is
  9. gotten from the _CRS associated with the bus. We put
  10. the data into an IO_RESOURCE_REQUIREMENTS_LIST as
  11. device private data of the following form:
  12. DevicePrivate.Data[0]: child's CM_RESOURCE_TYPE
  13. DevicePrivate.Data[1]: child's start address [31:0]
  14. DevicePrivate.Data[2]: child's start address [63:32]
  15. The descriptor that describes child-side translation
  16. immediately follows the one that describes the
  17. parent-side resources.
  18. The Flags field of the IO_RESOURCE_REQUIREMENTS_LIST may have the
  19. TRANSLATION_RANGE_SPARSE bit set.
  20. Author:
  21. Jake Oshins 7-Nov-97
  22. Environment:
  23. NT Kernel Model Driver only
  24. --*/
  25. #include "pch.h"
  26. NTSTATUS
  27. FindTranslationRange(
  28. IN PHYSICAL_ADDRESS Start,
  29. IN LONGLONG Length,
  30. IN PBRIDGE_TRANSLATOR Translator,
  31. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  32. IN UCHAR ResType,
  33. OUT PBRIDGE_WINDOW *Window
  34. );
  35. NTSTATUS
  36. TranslateBridgeResources(
  37. IN PVOID Context,
  38. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  39. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  40. IN ULONG AlternativesCount, OPTIONAL
  41. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  42. IN PDEVICE_OBJECT PhysicalDeviceObject,
  43. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  44. );
  45. NTSTATUS
  46. TranslateBridgeRequirements(
  47. IN PVOID Context,
  48. IN PIO_RESOURCE_DESCRIPTOR Source,
  49. IN PDEVICE_OBJECT PhysicalDeviceObject,
  50. OUT PULONG TargetCount,
  51. OUT PIO_RESOURCE_DESCRIPTOR *Target
  52. );
  53. NTSTATUS
  54. BuildTranslatorRanges(
  55. IN PBRIDGE_TRANSLATOR Translator,
  56. OUT ULONG *BridgeWindowCount,
  57. OUT PBRIDGE_WINDOW *Window
  58. );
  59. #define MAX(a, b) \
  60. ((a) > (b) ? (a) : (b))
  61. #define MIN(a, b) \
  62. ((a) < (b) ? (a) : (b))
  63. HAL_PORT_RANGE_INTERFACE HalPortRangeInterface;
  64. #ifdef ALLOC_PRAGMA
  65. #pragma alloc_text(PAGE, TranslateEjectInterface)
  66. #pragma alloc_text(PAGE, TranslateBridgeResources)
  67. #pragma alloc_text(PAGE, TranslateBridgeRequirements)
  68. #pragma alloc_text(PAGE, FindTranslationRange)
  69. #pragma alloc_text(PAGE, AcpiNullReference)
  70. #pragma alloc_text(PAGE, BuildTranslatorRanges)
  71. #endif
  72. NTSTATUS
  73. TranslateEjectInterface(
  74. PDEVICE_OBJECT DeviceObject,
  75. PIRP Irp
  76. )
  77. {
  78. PIO_RESOURCE_REQUIREMENTS_LIST ioList = NULL;
  79. PIO_RESOURCE_DESCRIPTOR transDesc;
  80. PIO_RESOURCE_DESCRIPTOR parentDesc;
  81. PTRANSLATOR_INTERFACE transInterface;
  82. PBRIDGE_TRANSLATOR bridgeTrans;
  83. PIO_STACK_LOCATION irpSp;
  84. PDEVICE_EXTENSION devExtension;
  85. BOOLEAN foundTranslations = FALSE;
  86. NTSTATUS status;
  87. PUCHAR crsBuf;
  88. ULONG descCount;
  89. ULONG parentResType;
  90. ULONG childResType;
  91. ULONG crsBufSize;
  92. PHYSICAL_ADDRESS parentStart;
  93. PHYSICAL_ADDRESS childStart;
  94. PAGED_CODE();
  95. devExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  96. ASSERT(devExtension);
  97. ASSERT(devExtension->AcpiObject);
  98. irpSp = IoGetCurrentIrpStackLocation(Irp);
  99. ASSERT(irpSp->Parameters.QueryInterface.Size >= sizeof(TRANSLATOR_INTERFACE));
  100. transInterface = (PTRANSLATOR_INTERFACE)irpSp->Parameters.QueryInterface.Interface;
  101. ASSERT(transInterface);
  102. //
  103. // Get the resources for this bus.
  104. //
  105. status = ACPIGetBufferSync(
  106. devExtension,
  107. PACKED_CRS,
  108. &crsBuf,
  109. &crsBufSize
  110. );
  111. if (!NT_SUCCESS(status)) {
  112. //
  113. // This bus has no _CRS. So it doesn't need a translator.
  114. //
  115. return Irp->IoStatus.Status;
  116. }
  117. //
  118. // Turn it into something meaningful.
  119. //
  120. status = PnpBiosResourcesToNtResources(
  121. crsBuf,
  122. PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES,
  123. &ioList
  124. );
  125. if (!NT_SUCCESS(status)) {
  126. goto TranslateEjectInterfaceExit;
  127. }
  128. //
  129. // Cycle through the descriptors looking for device private data
  130. // that contains translation information.
  131. //
  132. for (descCount = 0; descCount < ioList->List[0].Count; descCount++) {
  133. transDesc = &ioList->List[0].Descriptors[descCount];
  134. if (transDesc->Type == CmResourceTypeDevicePrivate) {
  135. //
  136. // Translation information is contained in
  137. // a device private resource that has
  138. // TRANSLATION_DATA_PARENT_ADDRESS in the
  139. // flags field.
  140. //
  141. if (transDesc->Flags & TRANSLATION_DATA_PARENT_ADDRESS) {
  142. // The first descriptor cannot be a translation descriptor
  143. ASSERT(descCount != 0);
  144. //
  145. // The translation descriptor should follow the descriptor
  146. // that it is trying to modify. The first, normal,
  147. // descriptor is for the child-relative resources. The
  148. // second, device private, descriptor is modifies the
  149. // child-relative resources to generate the parent-relative
  150. // resources.
  151. //
  152. parentResType = transDesc->u.DevicePrivate.Data[0];
  153. parentStart.LowPart = transDesc->u.DevicePrivate.Data[1];
  154. parentStart.HighPart = transDesc->u.DevicePrivate.Data[2];
  155. childResType = ioList->List[0].Descriptors[descCount - 1].Type;
  156. childStart.QuadPart = (transDesc - 1)->u.Generic.MinimumAddress.QuadPart;
  157. if ((parentResType != childResType) ||
  158. (parentStart.QuadPart != childStart.QuadPart)) {
  159. foundTranslations = TRUE;
  160. break;
  161. }
  162. }
  163. }
  164. }
  165. if (!foundTranslations) {
  166. //
  167. // Didn't find any translation information for this bus.
  168. //
  169. status = Irp->IoStatus.Status;
  170. ExFreePool(ioList);
  171. goto TranslateEjectInterfaceExit;
  172. }
  173. //
  174. // Build a translator interface.
  175. //
  176. bridgeTrans = ExAllocatePoolWithTag(
  177. PagedPool,
  178. sizeof (BRIDGE_TRANSLATOR),
  179. ACPI_TRANSLATE_POOLTAG
  180. );
  181. if (!bridgeTrans) {
  182. status = STATUS_INSUFFICIENT_RESOURCES;
  183. goto TranslateEjectInterfaceExit;
  184. }
  185. bridgeTrans->AcpiObject = devExtension->AcpiObject;
  186. bridgeTrans->IoList = ioList;
  187. //
  188. // Build the array of bridge windows.
  189. //
  190. status = BuildTranslatorRanges(
  191. bridgeTrans,
  192. &bridgeTrans->RangeCount,
  193. &bridgeTrans->Ranges
  194. );
  195. if (!NT_SUCCESS(status)) {
  196. goto TranslateEjectInterfaceExit;
  197. }
  198. transInterface->Size = sizeof(TRANSLATOR_INTERFACE);
  199. transInterface->Version = 1;
  200. transInterface->Context = (PVOID)bridgeTrans;
  201. transInterface->InterfaceReference = AcpiNullReference;
  202. transInterface->InterfaceDereference = AcpiNullReference;
  203. transInterface->TranslateResources = TranslateBridgeResources;
  204. transInterface->TranslateResourceRequirements = TranslateBridgeRequirements;
  205. status = STATUS_SUCCESS;
  206. TranslateEjectInterfaceExit:
  207. return status;
  208. }
  209. NTSTATUS
  210. FindTranslationRange(
  211. IN PHYSICAL_ADDRESS Start,
  212. IN LONGLONG Length,
  213. IN PBRIDGE_TRANSLATOR Translator,
  214. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  215. IN UCHAR ResType,
  216. OUT PBRIDGE_WINDOW *Window
  217. )
  218. {
  219. LONGLONG beginning, end;
  220. ULONG i;
  221. UCHAR rangeType;
  222. PAGED_CODE();
  223. for (i = 0; i < Translator->RangeCount; i++) {
  224. if (Direction == TranslateParentToChild) {
  225. beginning = Translator->Ranges[i].ParentAddress.QuadPart;
  226. rangeType = Translator->Ranges[i].ParentType;
  227. } else {
  228. beginning = Translator->Ranges[i].ChildAddress.QuadPart;
  229. rangeType = Translator->Ranges[i].ChildType;
  230. }
  231. end = beginning + Translator->Ranges[i].Length;
  232. if ((rangeType == ResType) &&
  233. (!((Start.QuadPart < beginning) ||
  234. (Start.QuadPart + Length > end)))) {
  235. //
  236. // The range lies within this bridge window
  237. // and the resource types match.
  238. //
  239. *Window = &Translator->Ranges[i];
  240. return STATUS_SUCCESS;
  241. }
  242. }
  243. return STATUS_NOT_FOUND;
  244. }
  245. NTSTATUS
  246. TranslateBridgeResources(
  247. IN PVOID Context,
  248. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  249. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  250. IN ULONG AlternativesCount, OPTIONAL
  251. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  252. IN PDEVICE_OBJECT PhysicalDeviceObject,
  253. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  254. )
  255. /*++
  256. Routine Description:
  257. This function takes a set of resources that are
  258. passed through a bridge and does any translation
  259. that is necessary when changing from a parent-
  260. relative viewpoint to a child-relative one or
  261. back again.
  262. In this function, we have the notion of a "window,"
  263. which is an aperature within the bridge. Bridges
  264. often have multiple windows, each with distinct
  265. translations.
  266. This function should never fail, as any resource
  267. range that will fail translation should have already
  268. been stripped out by TranslateBridgeRequirements.
  269. Arguments:
  270. Context - pointer to the translation data
  271. Source - resource list to be translated
  272. Direction - TranslateChildToParent or
  273. TranslateParentToChild
  274. AlternativesCount - not used
  275. Alternatives - not used
  276. PhysicalDeviceObject - not used
  277. Target - translated resource list
  278. Return Value:
  279. Status
  280. --*/
  281. {
  282. PBRIDGE_TRANSLATOR translator;
  283. PBRIDGE_WINDOW window;
  284. NTSTATUS status;
  285. PAGED_CODE();
  286. ASSERT(Context);
  287. ASSERT((Source->Type == CmResourceTypePort) ||
  288. (Source->Type == CmResourceTypeMemory));
  289. translator = (PBRIDGE_TRANSLATOR)Context;
  290. ASSERT(translator->RangeCount > 0);
  291. //
  292. // Find the window that this translation occurs
  293. // within.
  294. //
  295. status = FindTranslationRange(Source->u.Generic.Start,
  296. Source->u.Generic.Length,
  297. translator,
  298. Direction,
  299. Source->Type,
  300. &window);
  301. if (!NT_SUCCESS(status)) {
  302. //
  303. // We should never get here. This fucntion
  304. // should only be called for ranges that
  305. // are valid. TranslateBridgeRequirements should
  306. // weed out all the invalid ranges.
  307. return status;
  308. }
  309. //
  310. // Copy everything
  311. //
  312. *Target = *Source;
  313. switch (Direction) {
  314. case TranslateChildToParent:
  315. //
  316. // Target inherits the parent's resource type.
  317. //
  318. Target->Type = window->ParentType;
  319. //
  320. // Calculate the target's parent-relative start
  321. // address.
  322. //
  323. Target->u.Generic.Start.QuadPart =
  324. Source->u.Generic.Start.QuadPart +
  325. window->ParentAddress.QuadPart -
  326. window->ChildAddress.QuadPart;
  327. //
  328. // Make sure the length is still in bounds.
  329. //
  330. ASSERT(Target->u.Generic.Length <= (ULONG)(window->Length -
  331. (Target->u.Generic.Start.QuadPart -
  332. window->ParentAddress.QuadPart)));
  333. status = STATUS_TRANSLATION_COMPLETE;
  334. break;
  335. case TranslateParentToChild:
  336. //
  337. // Target inherits the child's resource type.
  338. //
  339. Target->Type = window->ChildType;
  340. //
  341. // Calculate the target's child-relative start
  342. // address.
  343. //
  344. Target->u.Generic.Start.QuadPart =
  345. Source->u.Generic.Start.QuadPart +
  346. window->ChildAddress.QuadPart -
  347. window->ParentAddress.QuadPart;
  348. //
  349. // Make sure the length is still in bounds.
  350. //
  351. ASSERT(Target->u.Generic.Length <= (ULONG)(window->Length -
  352. (Target->u.Generic.Start.QuadPart -
  353. window->ChildAddress.QuadPart)));
  354. status = STATUS_SUCCESS;
  355. break;
  356. default:
  357. status = STATUS_INVALID_PARAMETER;
  358. }
  359. #if 0
  360. if (Target->Type == CmResourceTypePort) {
  361. DbgPrint("XXX: %s[%d]=0x%I64x -> %s[%d]=0x%I64x\n",
  362. (Direction == TranslateChildToParent) ? "child" : "parent",
  363. Source->Type,
  364. Source->u.Generic.Start.QuadPart,
  365. (Direction == TranslateChildToParent) ? "parent" : "child",
  366. Target->Type,
  367. Target->u.Generic.Start.QuadPart);
  368. }
  369. #endif
  370. return status;
  371. }
  372. NTSTATUS
  373. TranslateBridgeRequirements(
  374. IN PVOID Context,
  375. IN PIO_RESOURCE_DESCRIPTOR Source,
  376. IN PDEVICE_OBJECT PhysicalDeviceObject,
  377. OUT PULONG TargetCount,
  378. OUT PIO_RESOURCE_DESCRIPTOR *Target
  379. )
  380. /*++
  381. Routine Description:
  382. This function takes a resource requirements list for
  383. resources on the child side of the bridge and
  384. translates them into resource requirements on the
  385. parent side of the bridge. This may involve clipping
  386. and there may be multiple target ranges.
  387. Arguments:
  388. Context - pointer to the translation data
  389. Source - resource list to be translated
  390. PhysicalDeviceObject - not used
  391. TargetCount - number of resources in the target list
  392. Target - translated resource requirements list
  393. Return Value:
  394. Status
  395. --*/
  396. {
  397. PBRIDGE_TRANSLATOR translator;
  398. PBRIDGE_WINDOW window;
  399. NTSTATUS status;
  400. LONGLONG rangeStart, rangeEnd, windowStart, windowEnd;
  401. ULONG i;
  402. PAGED_CODE();
  403. ASSERT(Context);
  404. ASSERT((Source->Type == CmResourceTypePort) ||
  405. (Source->Type == CmResourceTypeMemory));
  406. translator = (PBRIDGE_TRANSLATOR)Context;
  407. //
  408. // Allocate memory for the target range.
  409. //
  410. *Target = ExAllocatePoolWithTag(PagedPool,
  411. sizeof(IO_RESOURCE_DESCRIPTOR),
  412. ACPI_RESOURCE_POOLTAG);
  413. if (!*Target) {
  414. status = STATUS_INSUFFICIENT_RESOURCES;
  415. goto cleanup;
  416. }
  417. //
  418. // Look at all the aperatures in the bridge to see which
  419. // ones of them could possibly provide translations for
  420. // this resource.
  421. //
  422. rangeStart = Source->u.Generic.MinimumAddress.QuadPart;
  423. rangeEnd = Source->u.Generic.MaximumAddress.QuadPart;
  424. for (i = 0; i < translator->RangeCount; i++) {
  425. window = &translator->Ranges[i];
  426. if (window->ChildType != Source->Type) {
  427. //
  428. // This window describes the wrong
  429. // type of resource.
  430. //
  431. continue;
  432. }
  433. if (Source->u.Generic.Length > window->Length) {
  434. //
  435. // This resource won't fit in this aperature.
  436. //
  437. continue;
  438. }
  439. windowStart = window->ChildAddress.QuadPart;
  440. windowEnd = window->ChildAddress.QuadPart + (LONGLONG)window->Length;
  441. if (!(((rangeStart < windowStart) && (rangeEnd < windowStart)) ||
  442. ((rangeStart > windowEnd) && (rangeEnd > windowEnd)))) {
  443. //
  444. // The range and the window do intersect. So create
  445. // a resource that clips the range to the window.
  446. //
  447. **Target = *Source;
  448. *TargetCount = 1;
  449. (*Target)->Type = window->ParentType;
  450. (*Target)->u.Generic.MinimumAddress.QuadPart =
  451. rangeStart + (window->ParentAddress.QuadPart - windowStart);
  452. (*Target)->u.Generic.MaximumAddress.QuadPart =
  453. rangeEnd + (window->ParentAddress.QuadPart - windowStart);
  454. break;
  455. }
  456. }
  457. if (i < translator->RangeCount) {
  458. return STATUS_TRANSLATION_COMPLETE;
  459. } else {
  460. *TargetCount = 0;
  461. status = STATUS_PNP_TRANSLATION_FAILED;
  462. }
  463. cleanup:
  464. if (*Target) {
  465. ExFreePool(*Target);
  466. }
  467. return status;
  468. }
  469. NTSTATUS
  470. BuildTranslatorRanges(
  471. IN PBRIDGE_TRANSLATOR Translator,
  472. OUT ULONG *BridgeWindowCount,
  473. OUT PBRIDGE_WINDOW *Window
  474. )
  475. {
  476. PIO_RESOURCE_REQUIREMENTS_LIST ioList;
  477. PIO_RESOURCE_DESCRIPTOR transDesc, resDesc;
  478. ULONG descCount, windowCount, maxWindows;
  479. PAGED_CODE();
  480. ioList = Translator->IoList;
  481. //
  482. // Make an array of windows for holding the translation information.
  483. //
  484. maxWindows = ioList->List[0].Count / 2;
  485. *Window = ExAllocatePoolWithTag(PagedPool,
  486. maxWindows * sizeof(BRIDGE_WINDOW),
  487. ACPI_TRANSLATE_POOLTAG);
  488. if (!*Window) {
  489. return STATUS_INSUFFICIENT_RESOURCES;
  490. }
  491. //
  492. // Fill in the array with translations.
  493. //
  494. windowCount = 0;
  495. for (descCount = 0; descCount < ioList->List[0].Count; descCount++) {
  496. transDesc = &ioList->List[0].Descriptors[descCount];
  497. if (transDesc->Type == CmResourceTypeDevicePrivate) {
  498. //
  499. // Translation information is contained in
  500. // a device private resource that has
  501. // TRANSLATION_DATA_PARENT_ADDRESS in the
  502. // flags field.
  503. //
  504. if (transDesc->Flags & TRANSLATION_DATA_PARENT_ADDRESS) {
  505. ASSERT(windowCount <= maxWindows);
  506. //
  507. // The translation descriptor is supposed to follow
  508. // the resource that it is providing information about.
  509. //
  510. resDesc = &ioList->List[0].Descriptors[descCount - 1];
  511. (*Window)[windowCount].ParentType =
  512. (UCHAR)transDesc->u.DevicePrivate.Data[0];
  513. (*Window)[windowCount].ChildType = resDesc->Type;
  514. (*Window)[windowCount].ParentAddress.LowPart =
  515. transDesc->u.DevicePrivate.Data[1];
  516. (*Window)[windowCount].ParentAddress.HighPart =
  517. transDesc->u.DevicePrivate.Data[2];
  518. (*Window)[windowCount].ChildAddress.QuadPart =
  519. resDesc->u.Generic.MinimumAddress.QuadPart;
  520. (*Window)[windowCount].Length =
  521. resDesc->u.Generic.Length;
  522. //
  523. // If the HAL has provided underlying sparse port translation
  524. // services, allow for that.
  525. //
  526. if ((HalPortRangeInterface.QueryAllocateRange != NULL) &&
  527. (resDesc->Type == CmResourceTypePort)) {
  528. USHORT rangeId;
  529. UCHAR parentType = (UCHAR)transDesc->u.DevicePrivate.Data[0];
  530. BOOLEAN isSparse = transDesc->Flags & TRANSLATION_RANGE_SPARSE;
  531. ULONG parentLength = resDesc->u.Generic.Length;
  532. PHYSICAL_ADDRESS parentAddress;
  533. NTSTATUS status;
  534. PHYSICAL_ADDRESS rangeZeroBase;
  535. parentAddress.LowPart = transDesc->u.DevicePrivate.Data[1];
  536. parentAddress.HighPart = transDesc->u.DevicePrivate.Data[2];
  537. rangeZeroBase.QuadPart = parentAddress.QuadPart - resDesc->u.Generic.MinimumAddress.QuadPart;
  538. if (isSparse) {
  539. parentLength = (parentLength + resDesc->u.Generic.MinimumAddress.LowPart) << 10;
  540. }
  541. status = HalPortRangeInterface.QueryAllocateRange(
  542. isSparse,
  543. parentType == CmResourceTypeMemory,
  544. NULL,
  545. rangeZeroBase,
  546. parentLength,
  547. &rangeId
  548. );
  549. if (NT_SUCCESS(status)) {
  550. (*Window)[windowCount].ParentType = CmResourceTypePort;
  551. (*Window)[windowCount].ParentAddress.QuadPart =
  552. (rangeId << 16) |
  553. ((*Window)[windowCount].ChildAddress.QuadPart & 0xffff);
  554. }
  555. }
  556. windowCount++;
  557. }
  558. }
  559. }
  560. *BridgeWindowCount = windowCount;
  561. return STATUS_SUCCESS;
  562. }