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.

817 lines
21 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixisabus.c
  5. Abstract:
  6. Author:
  7. Environment:
  8. Revision History:
  9. --*/
  10. #include "halp.h"
  11. BOOLEAN
  12. HalpTranslateIsaBusAddress (
  13. IN PVOID BusHandler,
  14. IN PVOID RootHandler,
  15. IN PHYSICAL_ADDRESS BusAddress,
  16. IN OUT PULONG AddressSpace,
  17. OUT PPHYSICAL_ADDRESS TranslatedAddress
  18. );
  19. BOOLEAN
  20. HalpTranslateEisaBusAddress (
  21. IN PVOID BusHandler,
  22. IN PVOID RootHandler,
  23. IN PHYSICAL_ADDRESS BusAddress,
  24. IN OUT PULONG AddressSpace,
  25. OUT PPHYSICAL_ADDRESS TranslatedAddress
  26. );
  27. BOOLEAN
  28. HalpTranslateSystemBusAddress (
  29. IN PVOID BusHandler,
  30. IN PVOID RootHandler,
  31. IN PHYSICAL_ADDRESS BusAddress,
  32. IN OUT PULONG AddressSpace,
  33. OUT PPHYSICAL_ADDRESS TranslatedAddress
  34. );
  35. #ifdef EISA_SUPPORTED
  36. ULONG
  37. HalpGetEisaInterruptVector(
  38. IN PBUS_HANDLER BusHandler,
  39. IN PBUS_HANDLER RootHandler,
  40. IN ULONG BusInterruptLevel,
  41. IN ULONG BusInterruptVector,
  42. OUT PKIRQL Irql,
  43. OUT PKAFFINITY Affinity
  44. );
  45. NTSTATUS
  46. HalpAdjustEisaResourceList (
  47. IN PBUS_HANDLER BusHandler,
  48. IN PBUS_HANDLER RootHandler,
  49. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
  50. );
  51. HalpGetEisaData (
  52. IN PBUS_HANDLER BusHandler,
  53. IN PBUS_HANDLER RootHandler,
  54. IN ULONG SlotNumber,
  55. IN PVOID Buffer,
  56. IN ULONG Offset,
  57. IN ULONG Length
  58. );
  59. extern USHORT HalpEisaIrqMask;
  60. extern USHORT HalpEisaIrqIgnore;
  61. #endif // EISA_SUPPORTED
  62. #ifdef ALLOC_PRAGMA
  63. #ifdef EISA_SUPPORTED
  64. #pragma alloc_text(PAGE,HalpAdjustEisaResourceList)
  65. #pragma alloc_text(PAGE,HalpRecordEisaInterruptVectors)
  66. #pragma alloc_text(PAGE,HalpGetEisaInterruptVector)
  67. #pragma alloc_text(PAGE,HalpGetEisaData)
  68. #endif
  69. #pragma alloc_text(PAGE,HalIrqTranslateResourceRequirementsIsa)
  70. #pragma alloc_text(PAGE,HalIrqTranslateResourcesIsa)
  71. #endif
  72. #ifdef EISA_SUPPORTED
  73. HalpGetEisaData (
  74. IN PBUS_HANDLER BusHandler,
  75. IN PBUS_HANDLER RootHandler,
  76. IN ULONG SlotNumber,
  77. IN PVOID Buffer,
  78. IN ULONG Offset,
  79. IN ULONG Length
  80. )
  81. /*++
  82. Routine Description:
  83. The function returns the Eisa bus data for a slot or address.
  84. Arguments:
  85. Buffer - Supplies the space to store the data.
  86. Length - Supplies a count in bytes of the maximum amount to return.
  87. Return Value:
  88. Returns the amount of data stored into the buffer.
  89. --*/
  90. {
  91. OBJECT_ATTRIBUTES ObjectAttributes;
  92. OBJECT_ATTRIBUTES BusObjectAttributes;
  93. PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
  94. PWSTR ConfigData = L"Configuration Data";
  95. ANSI_STRING TmpString;
  96. ULONG BusNumber;
  97. UCHAR BusString[] = "00";
  98. UNICODE_STRING RootName, BusName;
  99. UNICODE_STRING ConfigDataName;
  100. NTSTATUS NtStatus;
  101. PKEY_VALUE_FULL_INFORMATION ValueInformation;
  102. PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
  103. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
  104. PCM_EISA_SLOT_INFORMATION SlotInformation;
  105. ULONG PartialCount;
  106. ULONG TotalDataSize, SlotDataSize;
  107. HANDLE EisaHandle, BusHandle;
  108. ULONG BytesWritten, BytesNeeded;
  109. PUCHAR KeyValueBuffer;
  110. ULONG i;
  111. ULONG DataLength = 0;
  112. PUCHAR DataBuffer = Buffer;
  113. BOOLEAN Found = FALSE;
  114. PAGED_CODE ();
  115. RtlInitUnicodeString(
  116. &RootName,
  117. EisaPath
  118. );
  119. InitializeObjectAttributes(
  120. &ObjectAttributes,
  121. &RootName,
  122. OBJ_CASE_INSENSITIVE,
  123. (HANDLE)NULL,
  124. NULL
  125. );
  126. //
  127. // Open the EISA root
  128. //
  129. NtStatus = ZwOpenKey(
  130. &EisaHandle,
  131. KEY_READ,
  132. &ObjectAttributes
  133. );
  134. if (!NT_SUCCESS(NtStatus)) {
  135. DataLength = 0;
  136. goto HalpGetEisaDataExit;
  137. }
  138. //
  139. // Init bus number path
  140. //
  141. BusNumber = BusHandler->BusNumber;
  142. if (BusNumber > 99) {
  143. DataLength = 0;
  144. goto HalpGetEisaDataExit;
  145. }
  146. if (BusNumber > 9) {
  147. BusString[0] += (UCHAR) (BusNumber/10);
  148. BusString[1] += (UCHAR) (BusNumber % 10);
  149. } else {
  150. BusString[0] += (UCHAR) BusNumber;
  151. BusString[1] = '\0';
  152. }
  153. RtlInitAnsiString(
  154. &TmpString,
  155. BusString
  156. );
  157. RtlAnsiStringToUnicodeString(
  158. &BusName,
  159. &TmpString,
  160. TRUE
  161. );
  162. InitializeObjectAttributes(
  163. &BusObjectAttributes,
  164. &BusName,
  165. OBJ_CASE_INSENSITIVE,
  166. (HANDLE)EisaHandle,
  167. NULL
  168. );
  169. //
  170. // Open the EISA root + Bus Number
  171. //
  172. NtStatus = ZwOpenKey(
  173. &BusHandle,
  174. KEY_READ,
  175. &BusObjectAttributes
  176. );
  177. if (!NT_SUCCESS(NtStatus)) {
  178. HalDebugPrint(( HAL_INFO, "HAL: Opening Bus Number: Status = %x\n",NtStatus ));
  179. DataLength = 0;
  180. goto HalpGetEisaDataExit;
  181. }
  182. //
  183. // opening the configuration data. This first call tells us how
  184. // much memory we need to allocate
  185. //
  186. RtlInitUnicodeString(
  187. &ConfigDataName,
  188. ConfigData
  189. );
  190. //
  191. // This should fail. We need to make this call so we can
  192. // get the actual size of the buffer to allocate.
  193. //
  194. ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i;
  195. NtStatus = ZwQueryValueKey(
  196. BusHandle,
  197. &ConfigDataName,
  198. KeyValueFullInformation,
  199. ValueInformation,
  200. 0,
  201. &BytesNeeded
  202. );
  203. KeyValueBuffer = ExAllocatePoolWithTag(
  204. NonPagedPool,
  205. BytesNeeded,
  206. HAL_POOL_TAG
  207. );
  208. if (KeyValueBuffer == NULL) {
  209. HalDebugPrint(( HAL_INFO, "HAL: Cannot allocate Key Value Buffer\n" ));
  210. ZwClose(BusHandle);
  211. DataLength = 0;
  212. goto HalpGetEisaDataExit;
  213. }
  214. ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer;
  215. NtStatus = ZwQueryValueKey(
  216. BusHandle,
  217. &ConfigDataName,
  218. KeyValueFullInformation,
  219. ValueInformation,
  220. BytesNeeded,
  221. &BytesWritten
  222. );
  223. ZwClose(BusHandle);
  224. if (!NT_SUCCESS(NtStatus)) {
  225. HalDebugPrint(( HAL_INFO, "HAL: Query Config Data: Status = %x\n",NtStatus ));
  226. DataLength = 0;
  227. goto HalpGetEisaDataExit;
  228. }
  229. //
  230. // We get back a Full Resource Descriptor List
  231. //
  232. Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation +
  233. ValueInformation->DataOffset);
  234. PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  235. &(Descriptor->PartialResourceList.PartialDescriptors);
  236. PartialCount = Descriptor->PartialResourceList.Count;
  237. for (i = 0; i < PartialCount; i++) {
  238. //
  239. // Do each partial Resource
  240. //
  241. switch (PartialResource->Type) {
  242. case CmResourceTypeNull:
  243. case CmResourceTypePort:
  244. case CmResourceTypeInterrupt:
  245. case CmResourceTypeMemory:
  246. case CmResourceTypeDma:
  247. //
  248. // We dont care about these.
  249. //
  250. PartialResource++;
  251. break;
  252. case CmResourceTypeDeviceSpecific:
  253. //
  254. // Bingo!
  255. //
  256. TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
  257. SlotInformation = (PCM_EISA_SLOT_INFORMATION)
  258. ((PUCHAR)PartialResource +
  259. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  260. while (((LONG)TotalDataSize) > 0) {
  261. if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
  262. SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
  263. } else {
  264. SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
  265. SlotInformation->NumberFunctions *
  266. sizeof(CM_EISA_FUNCTION_INFORMATION);
  267. }
  268. if (SlotDataSize > TotalDataSize) {
  269. //
  270. // Something is wrong again
  271. //
  272. DataLength = 0;
  273. goto HalpGetEisaDataExit;
  274. }
  275. if (SlotNumber != 0) {
  276. SlotNumber--;
  277. SlotInformation = (PCM_EISA_SLOT_INFORMATION)
  278. ((PUCHAR)SlotInformation + SlotDataSize);
  279. TotalDataSize -= SlotDataSize;
  280. continue;
  281. }
  282. //
  283. // This is our slot
  284. //
  285. Found = TRUE;
  286. break;
  287. }
  288. //
  289. // End loop
  290. //
  291. i = PartialCount;
  292. break;
  293. default:
  294. HalDebugPrint(( HAL_INFO, "HAL: Bad Data in registry!\n" ));
  295. DataLength = 0;
  296. goto HalpGetEisaDataExit;
  297. }
  298. }
  299. if (Found) {
  300. i = Length + Offset;
  301. if (i > SlotDataSize) {
  302. i = SlotDataSize;
  303. }
  304. DataLength = i - Offset;
  305. RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength);
  306. }
  307. HalpGetEisaDataExit:
  308. if (KeyValueBuffer) ExFreePool(KeyValueBuffer);
  309. RtlFreeUnicodeString(&BusName);
  310. return DataLength;
  311. }
  312. #endif // EISA_SUPPORTED
  313. NTSTATUS
  314. HalIrqTranslateResourceRequirementsIsa(
  315. IN PVOID Context,
  316. IN PIO_RESOURCE_DESCRIPTOR Source,
  317. IN PDEVICE_OBJECT PhysicalDeviceObject,
  318. OUT PULONG TargetCount,
  319. OUT PIO_RESOURCE_DESCRIPTOR *Target
  320. )
  321. /*++
  322. Routine Description:
  323. This function is basically a wrapper for
  324. HalIrqTranslateResourceRequirementsRoot that understands
  325. the weirdnesses of the ISA bus.
  326. Arguments:
  327. Return Value:
  328. status
  329. --*/
  330. {
  331. PIO_RESOURCE_DESCRIPTOR modSource, target, rootTarget;
  332. NTSTATUS status;
  333. BOOLEAN picSlaveDeleted = FALSE;
  334. BOOLEAN deleteResource;
  335. ULONG sourceCount = 0;
  336. ULONG targetCount = 0;
  337. ULONG resource;
  338. ULONG rootCount;
  339. ULONG invalidIrq;
  340. PAGED_CODE();
  341. ASSERT(Source->Type == CmResourceTypeInterrupt);
  342. modSource = ExAllocatePoolWithTag(
  343. NonPagedPool,
  344. //
  345. // we will have at most nine ranges when we are done
  346. //
  347. sizeof(IO_RESOURCE_DESCRIPTOR) * 9,
  348. HAL_POOL_TAG
  349. );
  350. if (!modSource) {
  351. return STATUS_INSUFFICIENT_RESOURCES;
  352. }
  353. RtlZeroMemory(modSource, sizeof(IO_RESOURCE_DESCRIPTOR) * 9);
  354. //
  355. // Is the PIC_SLAVE_IRQ in this resource?
  356. //
  357. if ((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_IRQ) &&
  358. (Source->u.Interrupt.MaximumVector >= PIC_SLAVE_IRQ)) {
  359. //
  360. // Clip the maximum
  361. //
  362. if (Source->u.Interrupt.MinimumVector < PIC_SLAVE_IRQ) {
  363. modSource[sourceCount] = *Source;
  364. modSource[sourceCount].u.Interrupt.MinimumVector =
  365. Source->u.Interrupt.MinimumVector;
  366. modSource[sourceCount].u.Interrupt.MaximumVector =
  367. PIC_SLAVE_IRQ - 1;
  368. sourceCount++;
  369. }
  370. //
  371. // Clip the minimum
  372. //
  373. if (Source->u.Interrupt.MaximumVector > PIC_SLAVE_IRQ) {
  374. modSource[sourceCount] = *Source;
  375. modSource[sourceCount].u.Interrupt.MaximumVector =
  376. Source->u.Interrupt.MaximumVector;
  377. modSource[sourceCount].u.Interrupt.MinimumVector =
  378. PIC_SLAVE_IRQ + 1;
  379. sourceCount++;
  380. }
  381. //
  382. // In ISA machines, the PIC_SLAVE_IRQ is rerouted
  383. // to PIC_SLAVE_REDIRECT. So find out if PIC_SLAVE_REDIRECT
  384. // is within this list. If it isn't we need to add it.
  385. //
  386. if (!((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_REDIRECT) &&
  387. (Source->u.Interrupt.MaximumVector >= PIC_SLAVE_REDIRECT))) {
  388. modSource[sourceCount] = *Source;
  389. modSource[sourceCount].u.Interrupt.MinimumVector=PIC_SLAVE_REDIRECT;
  390. modSource[sourceCount].u.Interrupt.MaximumVector=PIC_SLAVE_REDIRECT;
  391. sourceCount++;
  392. }
  393. } else {
  394. *modSource = *Source;
  395. sourceCount = 1;
  396. }
  397. //
  398. // Now that the PIC_SLAVE_IRQ has been handled, we have
  399. // to take into account IRQs that may have been steered
  400. // away to the PCI bus.
  401. //
  402. // N.B. The algorithm used below may produce resources
  403. // with minimums greater than maximums. Those will
  404. // be stripped out later.
  405. //
  406. for (invalidIrq = 0; invalidIrq < PIC_VECTORS; invalidIrq++) {
  407. //
  408. // Look through all the resources, possibly removing
  409. // this IRQ from them.
  410. //
  411. for (resource = 0; resource < sourceCount; resource++) {
  412. deleteResource = FALSE;
  413. if (HalpPciIrqMask & (1 << invalidIrq)) {
  414. //
  415. // This IRQ belongs to the PCI bus.
  416. //
  417. if (!((HalpBusType == MACHINE_TYPE_EISA) &&
  418. ((modSource[resource].Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)))) {
  419. //
  420. // And this resource is not an EISA-style,
  421. // level-triggered interrupt.
  422. //
  423. // N.B. Only the system BIOS truely knows
  424. // whether an IRQ on a PCI bus can be
  425. // shared with an IRQ on an ISA bus.
  426. // This code assumes that, in the case
  427. // that the BIOS set an EISA device to
  428. // the same interrupt as a PCI device,
  429. // the machine can actually function.
  430. //
  431. deleteResource = TRUE;
  432. }
  433. }
  434. #if !defined(MCA) && defined(EISA_SUPPORTED)
  435. if ((HalpBusType == MACHINE_TYPE_EISA) &&
  436. !(HalpEisaIrqIgnore & (1 << invalidIrq))) {
  437. if (modSource[resource].Flags != HalpGetIsaIrqState(invalidIrq)) {
  438. //
  439. // This driver has requested a level-triggered interrupt
  440. // and this particular interrupt is set to be edge, or
  441. // vice-versa.
  442. //
  443. deleteResource = TRUE;
  444. }
  445. }
  446. #endif
  447. if (deleteResource) {
  448. if (modSource[resource].u.Interrupt.MinimumVector == invalidIrq) {
  449. modSource[resource].u.Interrupt.MinimumVector++;
  450. } else if (modSource[resource].u.Interrupt.MaximumVector == invalidIrq) {
  451. modSource[resource].u.Interrupt.MaximumVector--;
  452. } else if ((modSource[resource].u.Interrupt.MinimumVector < invalidIrq) &&
  453. (modSource[resource].u.Interrupt.MaximumVector > invalidIrq)) {
  454. //
  455. // Copy the current resource into a new resource.
  456. //
  457. modSource[sourceCount] = modSource[resource];
  458. //
  459. // Clip the current resource to a range below invalidIrq.
  460. //
  461. modSource[resource].u.Interrupt.MaximumVector = invalidIrq - 1;
  462. //
  463. // Clip the new resource to a range above invalidIrq.
  464. //
  465. modSource[sourceCount].u.Interrupt.MinimumVector = invalidIrq + 1;
  466. sourceCount++;
  467. }
  468. }
  469. }
  470. }
  471. target = ExAllocatePoolWithTag(PagedPool,
  472. sizeof(IO_RESOURCE_DESCRIPTOR) * sourceCount,
  473. HAL_POOL_TAG
  474. );
  475. if (!target) {
  476. ExFreePool(modSource);
  477. return STATUS_INSUFFICIENT_RESOURCES;
  478. }
  479. //
  480. // Now send each of these ranges through
  481. // HalIrqTranslateResourceRequirementsRoot.
  482. //
  483. for (resource = 0; resource < sourceCount; resource++) {
  484. //
  485. // Skip over resources that we have previously
  486. // clobbered (while deleting PCI IRQs.)
  487. //
  488. if (modSource[resource].u.Interrupt.MinimumVector >
  489. modSource[resource].u.Interrupt.MaximumVector) {
  490. continue;
  491. }
  492. status = HalIrqTranslateResourceRequirementsRoot(
  493. Context,
  494. &modSource[resource],
  495. PhysicalDeviceObject,
  496. &rootCount,
  497. &rootTarget
  498. );
  499. if (!NT_SUCCESS(status)) {
  500. ExFreePool(target);
  501. goto HalIrqTranslateResourceRequirementsIsaExit;
  502. }
  503. //
  504. // HalIrqTranslateResourceRequirementsRoot should return
  505. // either one resource or, occasionally, zero.
  506. //
  507. ASSERT(rootCount <= 1);
  508. if (rootCount == 1) {
  509. target[targetCount] = *rootTarget;
  510. targetCount++;
  511. ExFreePool(rootTarget);
  512. }
  513. }
  514. *TargetCount = targetCount;
  515. if (targetCount > 0) {
  516. *Target = target;
  517. } else {
  518. ExFreePool(target);
  519. }
  520. status = STATUS_TRANSLATION_COMPLETE;
  521. HalIrqTranslateResourceRequirementsIsaExit:
  522. ExFreePool(modSource);
  523. return status;
  524. }
  525. NTSTATUS
  526. HalIrqTranslateResourcesIsa(
  527. IN PVOID Context,
  528. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  529. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  530. IN ULONG AlternativesCount, OPTIONAL
  531. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  532. IN PDEVICE_OBJECT PhysicalDeviceObject,
  533. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  534. )
  535. /*++
  536. Routine Description:
  537. This function is basically a wrapper for
  538. HalIrqTranslateResourcesRoot that understands
  539. the weirdnesses of the ISA bus.
  540. Arguments:
  541. Return Value:
  542. status
  543. --*/
  544. {
  545. CM_PARTIAL_RESOURCE_DESCRIPTOR modSource;
  546. NTSTATUS status;
  547. BOOLEAN usePicSlave = FALSE;
  548. ULONG i;
  549. modSource = *Source;
  550. if (Direction == TranslateChildToParent) {
  551. if (Source->u.Interrupt.Vector == PIC_SLAVE_IRQ) {
  552. modSource.u.Interrupt.Vector = PIC_SLAVE_REDIRECT;
  553. modSource.u.Interrupt.Level = PIC_SLAVE_REDIRECT;
  554. }
  555. }
  556. status = HalIrqTranslateResourcesRoot(
  557. Context,
  558. &modSource,
  559. Direction,
  560. AlternativesCount,
  561. Alternatives,
  562. PhysicalDeviceObject,
  563. Target);
  564. if (!NT_SUCCESS(status)) {
  565. return status;
  566. }
  567. if (Direction == TranslateParentToChild) {
  568. //
  569. // Because the ISA interrupt controller is
  570. // cascaded, there is one case where there is
  571. // a two-to-one mapping for interrupt sources.
  572. // (On a PC, both 2 and 9 trigger vector 9.)
  573. //
  574. // We need to account for this and deliver the
  575. // right value back to the driver.
  576. //
  577. if (Target->u.Interrupt.Level == PIC_SLAVE_REDIRECT) {
  578. //
  579. // Search the Alternatives list. If it contains
  580. // PIC_SLAVE_IRQ but not PIC_SLAVE_REDIRECT,
  581. // we should return PIC_SLAVE_IRQ.
  582. //
  583. for (i = 0; i < AlternativesCount; i++) {
  584. if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_REDIRECT) &&
  585. (Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_REDIRECT)) {
  586. //
  587. // The list contains, PIC_SLAVE_REDIRECT. Stop
  588. // looking.
  589. //
  590. usePicSlave = FALSE;
  591. break;
  592. }
  593. if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_IRQ) &&
  594. (Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_IRQ)) {
  595. //
  596. // The list contains, PIC_SLAVE_IRQ. Use it
  597. // unless we find PIC_SLAVE_REDIRECT later.
  598. //
  599. usePicSlave = TRUE;
  600. }
  601. }
  602. if (usePicSlave) {
  603. Target->u.Interrupt.Level = PIC_SLAVE_IRQ;
  604. Target->u.Interrupt.Vector = PIC_SLAVE_IRQ;
  605. }
  606. }
  607. }
  608. return status;
  609. }