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.

562 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pmapic.c
  5. Abstract:
  6. Implements functions specific to ISA busses
  7. in ACPI-APIC machines.
  8. Author:
  9. Jake Oshins (jakeo) 11-October-1997
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "halp.h"
  15. #include "acpitabl.h"
  16. NTSTATUS
  17. TranslateGlobalVectorToIsaVector(
  18. IN ULONG GlobalVector,
  19. OUT PULONG IsaVector
  20. );
  21. NTSTATUS
  22. HalacpiIrqTranslateResourceRequirementsIsa(
  23. IN PVOID Context,
  24. IN PIO_RESOURCE_DESCRIPTOR Source,
  25. IN PDEVICE_OBJECT PhysicalDeviceObject,
  26. OUT PULONG TargetCount,
  27. OUT PIO_RESOURCE_DESCRIPTOR *Target
  28. );
  29. NTSTATUS
  30. HalacpiIrqTranslateResourcesIsa(
  31. IN PVOID Context,
  32. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  33. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  34. IN ULONG AlternativesCount, OPTIONAL
  35. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  36. IN PDEVICE_OBJECT PhysicalDeviceObject,
  37. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  38. );
  39. extern ULONG HalpPicVectorRedirect[];
  40. extern FADT HalpFixedAcpiDescTable;
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, TranslateGlobalVectorToIsaVector)
  43. #pragma alloc_text(PAGE, HalacpiIrqTranslateResourceRequirementsIsa)
  44. #pragma alloc_text(PAGE, HalacpiIrqTranslateResourcesIsa)
  45. #pragma alloc_text(PAGE, HalacpiGetInterruptTranslator)
  46. #endif
  47. #define TranslateIsaVectorToGlobalVector(vector) \
  48. (HalpPicVectorRedirect[vector])
  49. NTSTATUS
  50. TranslateGlobalVectorToIsaVector(
  51. IN ULONG GlobalVector,
  52. OUT PULONG IsaVector
  53. )
  54. {
  55. UCHAR i;
  56. for (i = 0; i < PIC_VECTORS; i++) {
  57. if (HalpPicVectorRedirect[i] == GlobalVector) {
  58. *IsaVector = i;
  59. return STATUS_SUCCESS;
  60. }
  61. }
  62. return STATUS_NOT_FOUND;
  63. }
  64. NTSTATUS
  65. HalacpiIrqTranslateResourceRequirementsIsa(
  66. IN PVOID Context,
  67. IN PIO_RESOURCE_DESCRIPTOR Source,
  68. IN PDEVICE_OBJECT PhysicalDeviceObject,
  69. OUT PULONG TargetCount,
  70. OUT PIO_RESOURCE_DESCRIPTOR *Target
  71. )
  72. /*++
  73. Routine Description:
  74. This function is basically a wrapper for
  75. HalIrqTranslateResourceRequirementsRoot that understands
  76. the weirdnesses of the ISA bus.
  77. Arguments:
  78. Return Value:
  79. status
  80. --*/
  81. {
  82. PIO_RESOURCE_DESCRIPTOR modSource, target, rootTarget;
  83. NTSTATUS status;
  84. BOOLEAN deleteResource;
  85. ULONG sourceCount = 0;
  86. ULONG targetCount = 0;
  87. ULONG resource, resourceLength;
  88. ULONG rootCount;
  89. ULONG irq, startIrq, endIrq;
  90. ULONG maxTargets;
  91. PAGED_CODE();
  92. ASSERT(Source->Type == CmResourceTypeInterrupt);
  93. maxTargets = Source->u.Interrupt.MaximumVector -
  94. Source->u.Interrupt.MinimumVector + 3;
  95. resourceLength = sizeof(IO_RESOURCE_DESCRIPTOR) * maxTargets;
  96. modSource = ExAllocatePoolWithTag(PagedPool, resourceLength, HAL_POOL_TAG);
  97. if (!modSource) {
  98. return STATUS_INSUFFICIENT_RESOURCES;
  99. }
  100. RtlZeroMemory(modSource, resourceLength);
  101. //
  102. // Is the PIC_SLAVE_IRQ in this resource?
  103. //
  104. if ((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_IRQ) &&
  105. (Source->u.Interrupt.MaximumVector >= PIC_SLAVE_IRQ)) {
  106. //
  107. // Clip the maximum
  108. //
  109. if (Source->u.Interrupt.MinimumVector < PIC_SLAVE_IRQ) {
  110. modSource[sourceCount] = *Source;
  111. modSource[sourceCount].u.Interrupt.MinimumVector =
  112. Source->u.Interrupt.MinimumVector;
  113. modSource[sourceCount].u.Interrupt.MaximumVector =
  114. PIC_SLAVE_IRQ - 1;
  115. sourceCount++;
  116. }
  117. //
  118. // Clip the minimum
  119. //
  120. if (Source->u.Interrupt.MaximumVector > PIC_SLAVE_IRQ) {
  121. modSource[sourceCount] = *Source;
  122. modSource[sourceCount].u.Interrupt.MaximumVector =
  123. Source->u.Interrupt.MaximumVector;
  124. modSource[sourceCount].u.Interrupt.MinimumVector =
  125. PIC_SLAVE_IRQ + 1;
  126. sourceCount++;
  127. }
  128. //
  129. // In ISA machines, the PIC_SLAVE_IRQ is rerouted
  130. // to PIC_SLAVE_REDIRECT. So find out if PIC_SLAVE_REDIRECT
  131. // is within this list. If it isn't we need to add it.
  132. //
  133. if (!((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_REDIRECT) &&
  134. (Source->u.Interrupt.MaximumVector >= PIC_SLAVE_REDIRECT))) {
  135. modSource[sourceCount] = *Source;
  136. modSource[sourceCount].u.Interrupt.MinimumVector = PIC_SLAVE_REDIRECT;
  137. modSource[sourceCount].u.Interrupt.MaximumVector = PIC_SLAVE_REDIRECT;
  138. sourceCount++;
  139. }
  140. } else {
  141. *modSource = *Source;
  142. sourceCount = 1;
  143. }
  144. //
  145. // Clip out the SCI vector, if it is here. Also limit the vectors
  146. // to those that might be on an ISA bus.
  147. //
  148. for (resource = 0; resource < sourceCount; resource++) {
  149. //
  150. // Make sure that all values are within ISA ranges.
  151. //
  152. if ((modSource[resource].u.Interrupt.MaximumVector >= PIC_VECTORS) ||
  153. (modSource[resource].u.Interrupt.MinimumVector >= PIC_VECTORS)) {
  154. ExFreePool(modSource);
  155. return STATUS_UNSUCCESSFUL;
  156. }
  157. if ((modSource[resource].u.Interrupt.MinimumVector <=
  158. HalpFixedAcpiDescTable.sci_int_vector) &&
  159. (modSource[resource].u.Interrupt.MaximumVector >=
  160. HalpFixedAcpiDescTable.sci_int_vector)) {
  161. //
  162. // The SCI vector is within this range.
  163. //
  164. if (modSource[resource].u.Interrupt.MinimumVector <
  165. HalpFixedAcpiDescTable.sci_int_vector) {
  166. //
  167. // Put a new range on the end of modSource.
  168. //
  169. modSource[sourceCount].u.Interrupt.MinimumVector =
  170. modSource[resource].u.Interrupt.MinimumVector;
  171. modSource[sourceCount].u.Interrupt.MaximumVector =
  172. HalpFixedAcpiDescTable.sci_int_vector - 1;
  173. sourceCount++;
  174. }
  175. if (modSource[resource].u.Interrupt.MaximumVector >
  176. HalpFixedAcpiDescTable.sci_int_vector) {
  177. //
  178. // Put a new range on the end of modSource.
  179. //
  180. modSource[sourceCount].u.Interrupt.MinimumVector =
  181. HalpFixedAcpiDescTable.sci_int_vector + 1;
  182. modSource[sourceCount].u.Interrupt.MaximumVector =
  183. modSource[resource].u.Interrupt.MaximumVector;
  184. sourceCount++;
  185. }
  186. //
  187. // Now remove the range that we just broke up.
  188. //
  189. RtlMoveMemory(modSource + resource,
  190. modSource + resource + 1,
  191. sizeof(IO_RESOURCE_DESCRIPTOR) *
  192. (sourceCount - resource));
  193. sourceCount--;
  194. }
  195. }
  196. target = ExAllocatePoolWithTag(PagedPool, resourceLength, HAL_POOL_TAG);
  197. if (!target) {
  198. ExFreePool(modSource);
  199. return STATUS_INSUFFICIENT_RESOURCES;
  200. }
  201. RtlZeroMemory(target, resourceLength);
  202. //
  203. // Now translate each range from ISA vectors to ACPI
  204. // "global system interrupt vectors." Since GSIVs aren't
  205. // necessarily contiguous with respect to the ISA vectors,
  206. // this may involve breaking each range up into smaller
  207. // ranges, each independently translated into the GSIV space.
  208. //
  209. for (resource = 0; resource < sourceCount; resource++) {
  210. //
  211. // For each existing resource, start with the minimum
  212. // and maximum, unchanged.
  213. //
  214. irq = modSource[resource].u.Interrupt.MinimumVector;
  215. endIrq = modSource[resource].u.Interrupt.MaximumVector;
  216. do {
  217. //
  218. // Now cycle through every IRQ in this range, testing
  219. // to see if its translated value is contiguous
  220. // with respect to the translated value of the next
  221. // IRQ in the range.
  222. //
  223. startIrq = irq;
  224. for (; irq < endIrq; irq++) {
  225. if (TranslateIsaVectorToGlobalVector(irq) + 1 !=
  226. TranslateIsaVectorToGlobalVector(irq + 1)) {
  227. //
  228. // This range is not contiguous. Stop now
  229. // and create a target range.
  230. //
  231. break;
  232. }
  233. }
  234. //
  235. // Clone the source descriptor
  236. //
  237. target[targetCount] = *Source;
  238. //
  239. // Fill in the relevant changes.
  240. //
  241. target[targetCount].u.Interrupt.MinimumVector =
  242. TranslateIsaVectorToGlobalVector(startIrq);
  243. target[targetCount].u.Interrupt.MaximumVector =
  244. TranslateIsaVectorToGlobalVector(irq);
  245. ASSERT(target[targetCount].u.Interrupt.MinimumVector <=
  246. target[targetCount].u.Interrupt.MaximumVector);
  247. targetCount++;
  248. } while (irq != endIrq);
  249. }
  250. *TargetCount = targetCount;
  251. if (targetCount > 0) {
  252. *Target = target;
  253. } else {
  254. ExFreePool(target);
  255. }
  256. ExFreePool(modSource);
  257. return STATUS_SUCCESS;
  258. }
  259. NTSTATUS
  260. HalacpiIrqTranslateResourcesIsa(
  261. IN PVOID Context,
  262. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  263. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  264. IN ULONG AlternativesCount, OPTIONAL
  265. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  266. IN PDEVICE_OBJECT PhysicalDeviceObject,
  267. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  268. )
  269. /*++
  270. Routine Description:
  271. This function is basically a wrapper for
  272. HalIrqTranslateResourcesRoot that understands
  273. the weirdnesses of the ISA bus.
  274. Arguments:
  275. Return Value:
  276. status
  277. --*/
  278. {
  279. NTSTATUS status;
  280. BOOLEAN usePicSlave = FALSE;
  281. ULONG i;
  282. ULONG vector;
  283. PAGED_CODE();
  284. ASSERT(Source->Type == CmResourceTypeInterrupt);
  285. //
  286. // Copy everything
  287. //
  288. *Target = *Source;
  289. switch (Direction) {
  290. case TranslateChildToParent:
  291. Target->u.Interrupt.Level =
  292. TranslateIsaVectorToGlobalVector(Source->u.Interrupt.Level);
  293. Target->u.Interrupt.Vector =
  294. TranslateIsaVectorToGlobalVector(Source->u.Interrupt.Vector);
  295. break;
  296. case TranslateParentToChild:
  297. status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Level,
  298. &vector);
  299. if (!NT_SUCCESS(status)) {
  300. return status;
  301. }
  302. Target->u.Interrupt.Level = vector;
  303. status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Vector,
  304. &vector);
  305. if (!NT_SUCCESS(status)) {
  306. return status;
  307. }
  308. Target->u.Interrupt.Vector = vector;
  309. //
  310. // Because the ISA interrupt controller is
  311. // cascaded, there is one case where there is
  312. // a two-to-one mapping for interrupt sources.
  313. // (On a PC, both 2 and 9 trigger vector 9.)
  314. //
  315. // We need to account for this and deliver the
  316. // right value back to the driver.
  317. //
  318. if (Target->u.Interrupt.Level == PIC_SLAVE_REDIRECT) {
  319. //
  320. // Search the Alternatives list. If it contains
  321. // PIC_SLAVE_IRQ but not PIC_SLAVE_REDIRECT,
  322. // we should return PIC_SLAVE_IRQ.
  323. //
  324. for (i = 0; i < AlternativesCount; i++) {
  325. if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_REDIRECT) &&
  326. (Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_REDIRECT)) {
  327. //
  328. // The list contains, PIC_SLAVE_REDIRECT. Stop
  329. // looking.
  330. //
  331. usePicSlave = FALSE;
  332. break;
  333. }
  334. if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_IRQ) &&
  335. (Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_IRQ)) {
  336. //
  337. // The list contains, PIC_SLAVE_IRQ. Use it
  338. // unless we find PIC_SLAVE_REDIRECT later.
  339. //
  340. usePicSlave = TRUE;
  341. }
  342. }
  343. if (usePicSlave) {
  344. Target->u.Interrupt.Level = PIC_SLAVE_IRQ;
  345. Target->u.Interrupt.Vector = PIC_SLAVE_IRQ;
  346. }
  347. }
  348. break;
  349. }
  350. return STATUS_SUCCESS;
  351. }
  352. NTSTATUS
  353. HalacpiGetInterruptTranslator(
  354. IN INTERFACE_TYPE ParentInterfaceType,
  355. IN ULONG ParentBusNumber,
  356. IN INTERFACE_TYPE BridgeInterfaceType,
  357. IN USHORT Size,
  358. IN USHORT Version,
  359. OUT PTRANSLATOR_INTERFACE Translator,
  360. OUT PULONG BridgeBusNumber
  361. )
  362. /*++
  363. Routine Description:
  364. Arguments:
  365. ParentInterfaceType - The type of the bus the bridge lives on (normally PCI).
  366. ParentBusNumber - The number of the bus the bridge lives on.
  367. ParentSlotNumber - The slot number the bridge lives in (where valid).
  368. BridgeInterfaceType - The bus type the bridge provides (ie ISA for a PCI-ISA bridge).
  369. ResourceType - The resource type we want to translate.
  370. Size - The size of the translator buffer.
  371. Version - The version of the translator interface requested.
  372. Translator - Pointer to the buffer where the translator should be returned
  373. BridgeBusNumber - Pointer to where the bus number of the bridge bus should be returned
  374. Return Value:
  375. Returns the status of this operation.
  376. --*/
  377. {
  378. PAGED_CODE();
  379. UNREFERENCED_PARAMETER(ParentInterfaceType);
  380. UNREFERENCED_PARAMETER(ParentBusNumber);
  381. ASSERT(Version == HAL_IRQ_TRANSLATOR_VERSION);
  382. ASSERT(Size >= sizeof (TRANSLATOR_INTERFACE));
  383. switch (BridgeInterfaceType) {
  384. case Eisa:
  385. case Isa:
  386. case InterfaceTypeUndefined: // special "IDE" cookie
  387. //
  388. // Pass back an interface for an IRQ translator for
  389. // the (E)ISA interrupts.
  390. //
  391. RtlZeroMemory(Translator, sizeof (TRANSLATOR_INTERFACE));
  392. Translator->Size = sizeof (TRANSLATOR_INTERFACE);
  393. Translator->Version = HAL_IRQ_TRANSLATOR_VERSION;
  394. Translator->InterfaceReference = &HalTranslatorReference;
  395. Translator->InterfaceDereference = &HalTranslatorDereference;
  396. Translator->TranslateResources = &HalacpiIrqTranslateResourcesIsa;
  397. Translator->TranslateResourceRequirements = &HalacpiIrqTranslateResourceRequirementsIsa;
  398. return STATUS_SUCCESS;
  399. default:
  400. return STATUS_NOT_IMPLEMENTED;
  401. }
  402. }