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.

831 lines
22 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. hwdata.c
  5. Abstract:
  6. This module contains the C code to set up mouse configuration data.
  7. Author:
  8. Shie-Lin Tzong (shielint) 18-Jan-1991
  9. Revision History:
  10. --*/
  11. #include "hwdetect.h"
  12. #include "string.h"
  13. #if !defined(_GAMBIT_)
  14. #if defined(NEC_98)
  15. extern PMOUSE_INFORMATION
  16. LookFor98BusMouse (
  17. VOID
  18. );
  19. #else
  20. //
  21. // External References
  22. //
  23. extern PMOUSE_INFORMATION
  24. LookForPS2Mouse (
  25. VOID
  26. );
  27. extern PMOUSE_INFORMATION
  28. LookForInportMouse (
  29. VOID
  30. );
  31. #endif
  32. extern PMOUSE_INFORMATION
  33. LookForSerialMouse (
  34. VOID
  35. );
  36. #if defined(NEC_98)
  37. #else
  38. extern PMOUSE_INFORMATION
  39. LookForBusMouse (
  40. VOID
  41. );
  42. extern VOID
  43. Empty8042 (
  44. VOID
  45. );
  46. extern USHORT
  47. HwGetKey (
  48. VOID
  49. );
  50. extern VOID
  51. HwPushKey (
  52. USHORT Key
  53. );
  54. #endif
  55. #endif // _GAMBIT_
  56. extern USHORT SavedKey;
  57. //
  58. // Define the master and slave i8259 IRQ bitmask.
  59. //
  60. #define MASTER_IRQ_MASK_BITS 0xB8
  61. #define SLAVE_IRQ_MASK_BITS 0x02
  62. //
  63. // Define the lowest i8259 IRQ that the Inport mouse can reside on. This
  64. // has the highest NT priority.
  65. //
  66. #define INPORT_LOWEST_IRQ 0x03
  67. //
  68. // Define the Inport chip reset value.
  69. //
  70. #define INPORT_RESET 0x80
  71. //
  72. // Define the data registers (pointed to by the Inport address register).
  73. //
  74. #define INPORT_DATA_REGISTER_1 1
  75. #define INPORT_DATA_REGISTER_2 2
  76. //
  77. // Define the Inport mouse mode register and mode bits.
  78. //
  79. #define INPORT_MODE_REGISTER 7
  80. #define INPORT_MODE_0 0x00 // 0 HZ - INTR = 0
  81. #define INPORT_MODE_30HZ 0x01
  82. #define INPORT_MODE_50HZ 0x02
  83. #define INPORT_MODE_100HZ 0x03
  84. #define INPORT_MODE_200HZ 0x04
  85. #define INPORT_MODE_1 0x06 // 0 HZ - INTR = 1
  86. #define INPORT_DATA_INTERRUPT_ENABLE 0x08
  87. #define INPORT_TIMER_INTERRUPT_ENABLE 0x10
  88. #define INPORT_MODE_HOLD 0x20
  89. #define INPORT_MODE_QUADRATURE 0x00
  90. //
  91. // Video adaptor type identifiers.
  92. //
  93. #if defined(NEC_98)
  94. PUCHAR MouseIdentifier[] = {
  95. "UNKNOWN",
  96. "NO MOUSE",
  97. "MICROSOFT",
  98. "MICROSOFT BALLPOINT",
  99. "LOGITECH",
  100. "NEC"
  101. };
  102. #else //
  103. PUCHAR MouseIdentifier[] = {
  104. "UNKNOWN",
  105. "NO MOUSE",
  106. "MICROSOFT",
  107. "MICROSOFT BALLPOINT",
  108. "LOGITECH"
  109. };
  110. #endif
  111. #if defined(NEC_98)
  112. PUCHAR MouseSubidentifier[] = {
  113. "",
  114. " PS2 MOUSE",
  115. " SERIAL MOUSE",
  116. " INPORT MOUSE",
  117. " BUS MOUSE",
  118. " PS2 MOUSE WITH WHEEL",
  119. " SERIAL MOUSE WITH WHEEL",
  120. " PC-9800 BUS MOUSE",
  121. " N5200/E KB MOUSE"
  122. };
  123. #else
  124. PUCHAR MouseSubidentifier[] = {
  125. "",
  126. " PS2 MOUSE",
  127. " SERIAL MOUSE",
  128. " INPORT MOUSE",
  129. " BUS MOUSE",
  130. " PS2 MOUSE WITH WHEEL",
  131. " SERIAL MOUSE WITH WHEEL"
  132. };
  133. #endif
  134. //
  135. // The following table translates keyboard make code to
  136. // ascii code. Note, only 0-9 and A-Z are translated.
  137. // Everything else is translated to '?'
  138. //
  139. UCHAR MakeToAsciiTable[] = {
  140. 0x3f, 0x3f, 0x31, 0x32, 0x33, // ?, ?, 1, 2, 3,
  141. 0x34, 0x35, 0x36, 0x37, 0x38, // 4, 5, 6, 7, 8,
  142. 0x39, 0x30, 0x3f, 0x3f, 0x3f, // 9, 0, ?, ?, ?,
  143. 0x3f, 0x51, 0x57, 0x45, 0x52, // ?, Q, W, E, R,
  144. 0x54, 0x59, 0x55, 0x49, 0x4f, // T, Y, U, I, O,
  145. 0x50, 0x3f, 0x3f, 0x3f, 0x3f, // P, ?, ?, ?, ?,
  146. 0x41, 0x53, 0x44, 0x46, 0x47, // A, S, D, F, G,
  147. 0x48, 0x4a, 0x4b, 0x4c, 0x3f, // H, J, K, L, ?,
  148. 0x3f, 0x3f, 0x3f, 0x3f, 0x5a, // ?, ?, ?, ?, Z,
  149. 0x58, 0x43, 0x56, 0x42, 0x4e, // X, C, V, B, N,
  150. 0x4d}; // W
  151. #define MAX_MAKE_CODE_TRANSLATED 0x32
  152. static ULONG MouseControllerKey = 0;
  153. FPFWCONFIGURATION_COMPONENT_DATA
  154. SetMouseConfigurationData (
  155. PMOUSE_INFORMATION MouseInfo,
  156. FPFWCONFIGURATION_COMPONENT_DATA MouseList
  157. )
  158. /*++
  159. Routine Description:
  160. This routine fills in mouse configuration data.
  161. Arguments:
  162. MouseInfo - Supplies a pointer to the MOUSE_INFOR structure
  163. MouseList - Supplies a pointer to the existing mouse component list.
  164. Returns:
  165. Returns a pointer to our mice controller list.
  166. --*/
  167. {
  168. UCHAR i = 0;
  169. FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, Controller, PeripheralEntry;
  170. FPFWCONFIGURATION_COMPONENT Component;
  171. HWCONTROLLER_DATA ControlData;
  172. USHORT z, Length;
  173. FPUCHAR fpString;
  174. #if defined(NEC_98)
  175. #if DBG
  176. BlPrint("98MousePORT=%x\n", MouseInfo->MousePort);
  177. BlPrint("98MouseMouseSubtype=%x\n", MouseInfo->MouseSubtype);
  178. BlPrint("98MouseVector=%x\n", MouseInfo->MouseIrq);
  179. BlPrint("98MouseMouseList=%x\n", MouseList);
  180. #endif // DBG
  181. #endif // defined(NEC_98)
  182. if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
  183. (MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
  184. //
  185. // Initialize Controller data
  186. //
  187. ControlData.NumberPortEntries = 0;
  188. ControlData.NumberIrqEntries = 0;
  189. ControlData.NumberMemoryEntries = 0;
  190. ControlData.NumberDmaEntries = 0;
  191. z = 0;
  192. //
  193. // If it is not SERIAL_MOUSE, set up controller component
  194. //
  195. Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  196. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  197. Component = &Controller->ComponentEntry;
  198. Component->Class = ControllerClass;
  199. Component->Type = PointerController;
  200. Component->Flags.Input = 1;
  201. Component->Version = 0;
  202. Component->Key = MouseControllerKey;
  203. MouseControllerKey++;
  204. Component->AffinityMask = 0xffffffff;
  205. Component->IdentifierLength = 0;
  206. Component->Identifier = NULL;
  207. //
  208. // If we have mouse irq or port information, allocate configuration
  209. // data space for mouse controller component to store these information
  210. //
  211. if (MouseInfo->MouseIrq != 0xffff || MouseInfo->MousePort != 0xffff) {
  212. #if !defined(_GAMBIT_)
  213. //
  214. // Set up port and Irq information
  215. //
  216. if (MouseInfo->MousePort != 0xffff) {
  217. ControlData.NumberPortEntries = 1;
  218. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  219. ControlData.DescriptorList[z].ShareDisposition =
  220. CmResourceShareDeviceExclusive;
  221. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  222. ControlData.DescriptorList[z].u.Port.Start.LowPart =
  223. (ULONG)MouseInfo->MousePort;
  224. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  225. ControlData.DescriptorList[z].u.Port.Length = 4;
  226. z++;
  227. }
  228. if (MouseInfo->MouseIrq != 0xffff) {
  229. ControlData.NumberIrqEntries = 1;
  230. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  231. ControlData.DescriptorList[z].ShareDisposition =
  232. CmResourceShareUndetermined;
  233. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  234. ControlData.DescriptorList[z].u.Interrupt.Level =
  235. (ULONG)MouseInfo->MouseIrq;
  236. ControlData.DescriptorList[z].u.Interrupt.Vector =
  237. (ULONG)MouseInfo->MouseIrq;
  238. if (HwBusType == MACHINE_TYPE_MCA) {
  239. ControlData.DescriptorList[z].Flags =
  240. LEVEL_SENSITIVE;
  241. } else {
  242. //
  243. // For EISA the LevelTriggered is temporarily set to FALSE.
  244. //
  245. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  246. }
  247. }
  248. #endif // _GAMBIT_
  249. Controller->ConfigurationData =
  250. HwSetUpResourceDescriptor(Component,
  251. NULL,
  252. &ControlData,
  253. 0,
  254. NULL
  255. );
  256. } else {
  257. //
  258. // Otherwise, we don't have configuration data for the controller
  259. //
  260. Controller->ConfigurationData = NULL;
  261. Component->ConfigurationDataLength = 0;
  262. }
  263. }
  264. //
  265. // Set up Mouse peripheral component
  266. //
  267. PeripheralEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  268. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  269. Component = &PeripheralEntry->ComponentEntry;
  270. Component->Class = PeripheralClass;
  271. Component->Type = PointerPeripheral;
  272. Component->Flags.Input = 1;
  273. Component->Version = 0;
  274. Component->Key = 0;
  275. Component->AffinityMask = 0xffffffff;
  276. Component->ConfigurationDataLength = 0;
  277. PeripheralEntry->ConfigurationData = (FPVOID)NULL;
  278. //
  279. // If Mouse PnP device id is found, translate it to ascii code.
  280. // (The mouse device id is presented to us by keyboard make code.)
  281. //
  282. Length = 0;
  283. if (MouseInfo->DeviceIdLength != 0) {
  284. USHORT i;
  285. if (MouseInfo->MouseSubtype == PS_MOUSE_WITH_WHEEL) {
  286. for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
  287. if (MouseInfo->DeviceId[i] > MAX_MAKE_CODE_TRANSLATED) {
  288. MouseInfo->DeviceId[i] = '?';
  289. } else {
  290. MouseInfo->DeviceId[i] = MakeToAsciiTable[MouseInfo->DeviceId[i]];
  291. }
  292. }
  293. } else if (MouseInfo->MouseSubtype == SERIAL_MOUSE_WITH_WHEEL) {
  294. for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
  295. MouseInfo->DeviceId[i] += 0x20;
  296. }
  297. }
  298. Length = MouseInfo->DeviceIdLength + 3;
  299. }
  300. Length += strlen(MouseIdentifier[MouseInfo->MouseType]) +
  301. strlen(MouseSubidentifier[MouseInfo->MouseSubtype]) + 1;
  302. fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
  303. if (MouseInfo->DeviceIdLength != 0) {
  304. _fstrcpy(fpString, MouseInfo->DeviceId);
  305. _fstrcat(fpString, " - ");
  306. _fstrcat(fpString, MouseIdentifier[MouseInfo->MouseType]);
  307. } else {
  308. _fstrcpy(fpString, MouseIdentifier[MouseInfo->MouseType]);
  309. }
  310. _fstrcat(fpString, MouseSubidentifier[MouseInfo->MouseSubtype]);
  311. Component->IdentifierLength = Length;
  312. Component->Identifier = fpString;
  313. if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
  314. (MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
  315. Controller->Child = PeripheralEntry;
  316. PeripheralEntry->Parent = Controller;
  317. if (MouseList) {
  318. //
  319. // Put the current mouse component to the beginning of the list
  320. //
  321. Controller->Sibling = MouseList;
  322. }
  323. return(Controller);
  324. } else {
  325. CurrentEntry = AdapterEntry->Child; // AdapterEntry MUST have child
  326. while (CurrentEntry) {
  327. if (CurrentEntry->ComponentEntry.Type == SerialController) {
  328. if (MouseInfo->MousePort == (USHORT)CurrentEntry->ComponentEntry.Key) {
  329. //
  330. // For serial mouse, the MousePort field contains
  331. // COM port number.
  332. //
  333. PeripheralEntry->Parent = CurrentEntry;
  334. CurrentEntry->Child = PeripheralEntry;
  335. break;
  336. }
  337. }
  338. CurrentEntry = CurrentEntry->Sibling;
  339. }
  340. return(NULL);
  341. }
  342. }
  343. FPFWCONFIGURATION_COMPONENT_DATA
  344. GetMouseInformation (
  345. VOID
  346. )
  347. /*++
  348. Routine Description:
  349. This routine is the entry for mouse detection routine. It will invoke
  350. lower level routines to detect ALL the mice in the system.
  351. Arguments:
  352. None.
  353. Returns:
  354. A pointer to a mouse component structure, if mouse/mice is detected.
  355. Otherwise a NULL pointer is returned.
  356. --*/
  357. {
  358. PMOUSE_INFORMATION MouseInfo;
  359. FPFWCONFIGURATION_COMPONENT_DATA MouseList = NULL;
  360. #if defined(_GAMBIT_)
  361. MouseInfo = (PMOUSE_INFORMATION)HwAllocateHeap (
  362. sizeof(MOUSE_INFORMATION), TRUE);
  363. MouseInfo->MouseType = 2; // Microsoft mouse
  364. MouseInfo->MouseSubtype = PS_MOUSE; // PS2 mouse
  365. MouseInfo->MousePort = 0; // Serial port 0
  366. MouseInfo->MouseIrq = 4; // Interrupt request vector was 3
  367. MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
  368. return(MouseList);
  369. #else
  370. //
  371. // Check if there is a key in keyboard look ahead buffer. If yes and
  372. // we have not saved any, we will read it and remember it.
  373. //
  374. #if defined(NEC_98)
  375. if (MouseInfo = LookFor98BusMouse()) {
  376. MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
  377. }
  378. if (MouseInfo = LookForSerialMouse()) {
  379. SetMouseConfigurationData(MouseInfo, MouseList);
  380. }
  381. #else
  382. if (SavedKey == 0) {
  383. SavedKey = HwGetKey();
  384. }
  385. if (MouseInfo = LookForPS2Mouse()) {
  386. MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
  387. }
  388. if (MouseInfo = LookForInportMouse()) {
  389. MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
  390. }
  391. while (MouseInfo = LookForSerialMouse()) {
  392. SetMouseConfigurationData(MouseInfo, MouseList);
  393. }
  394. if (MouseInfo = LookForBusMouse()) {
  395. MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
  396. }
  397. //
  398. // Finally drain 8042 output buffer again before we leave
  399. //
  400. Empty8042();
  401. //
  402. // If we have a keystroke before the mouse/keyboard detection, we
  403. // needs to push the key back to the keyboard look ahead buffer such
  404. // that ntldr can read it.
  405. //
  406. if (SavedKey) {
  407. HwPushKey(SavedKey);
  408. }
  409. #endif
  410. #endif // _GAMBIT_
  411. return(MouseList);
  412. }
  413. #if defined(NEC_98) || defined(_GAMBIT_)
  414. #else
  415. BOOLEAN
  416. InportMouseIrqDetection(
  417. IN USHORT CurrentPort,
  418. OUT PUSHORT Vector
  419. )
  420. /*++
  421. Routine Description:
  422. This routine attempts to locate the interrupt vector for which
  423. the Inport mouse is configured. The allowable vectors are
  424. 3, 4, 5, 7, and 9. If no interrupt vector is found, or more than
  425. one is found, the routine returns FALSE. Otherwise, TRUE is returned.
  426. Note that we diddle the i8259 interrupt controllers here.
  427. Arguments:
  428. CurrentPort - I/O port to use for the mouse.
  429. Vector - Pointer to the location to store the mouse interrupt vector.
  430. Return Value:
  431. Returns TRUE if the Inport interrupt vector was located; otherwise,
  432. FALSE is returned.
  433. --*/
  434. {
  435. UCHAR OldMasterMask, OldSlaveMask;
  436. UCHAR MasterMask, SlaveMask;
  437. UCHAR InterruptBits;
  438. UCHAR PossibleInterruptBits;
  439. int i;
  440. int NumberOfIRQs;
  441. BOOLEAN VectorFound = FALSE;
  442. //
  443. // Get the i8259 interrupt masks.
  444. //
  445. OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  446. OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  447. //
  448. // Raise IRQL to the highest priority IRQL the inport would use.
  449. //
  450. WRITE_PORT_UCHAR(
  451. (PUCHAR) PIC1_PORT1,
  452. (UCHAR) 0xff ^ ((UCHAR)(1<<INPORT_LOWEST_IRQ) - 1)
  453. );
  454. WRITE_PORT_UCHAR(
  455. (PUCHAR) PIC2_PORT1,
  456. (UCHAR) 0xff
  457. );
  458. //
  459. // Get the master i8259 interrupt mask.
  460. //
  461. MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  462. //
  463. // Reset the Inport chip.
  464. //
  465. WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_RESET);
  466. //
  467. // Select the Inport mode register for use as the current data register.
  468. //
  469. WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_MODE_REGISTER);
  470. //
  471. // Disable potential Inport mouse interrupts.
  472. //
  473. WRITE_PORT_UCHAR(
  474. (PUCHAR) PIC1_PORT1,
  475. (UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
  476. );
  477. //
  478. // Select the i8259 Interrupt Request Register.
  479. //
  480. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
  481. //
  482. // Attempt to locate the Inport interrupt line on the master i8259.
  483. // Why try this 10 times? It's magic...
  484. //
  485. PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
  486. for (i = 0; i < 10; i++) {
  487. //
  488. // Generate a 0 on the Inport IRQ on the master i8259.
  489. //
  490. WRITE_PORT_UCHAR(
  491. (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
  492. INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
  493. );
  494. //
  495. // Read the interrupt bits off the master i8259. Only bits
  496. // 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
  497. // IRQs. Only continue looking at the master i8259 if there
  498. // is at least one functional IRQ.
  499. //
  500. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
  501. InterruptBits &= MASTER_IRQ_MASK_BITS;
  502. InterruptBits ^= MASTER_IRQ_MASK_BITS;
  503. PossibleInterruptBits &= InterruptBits;
  504. if (!PossibleInterruptBits)
  505. break;
  506. //
  507. // Generate a 1 on the Inport IRQ on the master i8259.
  508. //
  509. WRITE_PORT_UCHAR(
  510. (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
  511. INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
  512. );
  513. //
  514. // Read the interrupt bits off the master i8259. Only bits
  515. // 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
  516. // IRQs. Only continue looking at the master i8259 if there
  517. // is at least one functional IRQ.
  518. //
  519. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
  520. InterruptBits &= MASTER_IRQ_MASK_BITS;
  521. PossibleInterruptBits &= InterruptBits;
  522. if (!PossibleInterruptBits)
  523. break;
  524. }
  525. if (PossibleInterruptBits) {
  526. //
  527. // We found at least one IRQ on the master i8259 that could belong
  528. // to the Inport mouse. Count how many we found. If there is
  529. // more than one, we haven't found the vector. Otherwise, we've
  530. // successfully located the Inport interrupt vector on the master
  531. // i8259 (provided the interrupt vector is 3, 4, 5, or 7).
  532. //
  533. PossibleInterruptBits >>= 3;
  534. NumberOfIRQs = 0;
  535. for (i = 3; i <= 7; i++) {
  536. if (PossibleInterruptBits & 1) {
  537. NumberOfIRQs += 1;
  538. *Vector = (CCHAR) i;
  539. }
  540. PossibleInterruptBits >>= 1;
  541. }
  542. if (NumberOfIRQs == 1) {
  543. VectorFound = TRUE;
  544. } else {
  545. *Vector = 0xffff;
  546. }
  547. }
  548. //
  549. // If we didn't locate the interrupt vector on the master i8259, attempt
  550. // to locate it on the slave i8259.
  551. //
  552. if (!VectorFound) {
  553. //
  554. // Get the slave i8259 interrupt mask.
  555. //
  556. SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  557. //
  558. // Disable potential Inport mouse interrupts.
  559. //
  560. WRITE_PORT_UCHAR(
  561. (PUCHAR) PIC2_PORT1,
  562. (UCHAR) (SlaveMask | SLAVE_IRQ_MASK_BITS)
  563. );
  564. //
  565. // Select the i8259 Interrupt Request Register.
  566. //
  567. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
  568. //
  569. // Attempt to locate the Inport interrupt line on the slave i8259.
  570. // Why try this 10 times? It's magic...
  571. //
  572. PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
  573. for (i = 0; i < 10; i++) {
  574. //
  575. // Generate a 0 on the Inport IRQ on the slave i8259.
  576. //
  577. WRITE_PORT_UCHAR(
  578. (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
  579. INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
  580. );
  581. //
  582. // Read the interrupt bits off the slave i8259. Only bit 2
  583. // is of interest. Eliminate non-functional IRQs. Only continue
  584. // looking at the slave i8259 if there is at least one
  585. // functional IRQ.
  586. //
  587. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
  588. InterruptBits &= SLAVE_IRQ_MASK_BITS;
  589. InterruptBits ^= SLAVE_IRQ_MASK_BITS;
  590. PossibleInterruptBits &= InterruptBits;
  591. if (!PossibleInterruptBits)
  592. break;
  593. //
  594. // Generate a 1 on the Inport IRQ on the slave i8259.
  595. //
  596. WRITE_PORT_UCHAR(
  597. (PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
  598. INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
  599. );
  600. //
  601. // Read the interrupt bits off the slave i8259. Only bit 2
  602. // is of interest. Eliminate non-functional IRQs. Only continue
  603. // looking at the slave i8259 if there is at least one
  604. // functional IRQ.
  605. //
  606. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
  607. InterruptBits &= SLAVE_IRQ_MASK_BITS;
  608. PossibleInterruptBits &= InterruptBits;
  609. if (!PossibleInterruptBits)
  610. break;
  611. }
  612. //
  613. // We may have found the Inport IRQ. If it's not 2 on slave (really
  614. // 9, overall) then we have NOT found the Inport interrupt vector.
  615. // Otherwise, we have successfully located the Inport vector on
  616. // the slave i8259.
  617. //
  618. if (PossibleInterruptBits == 2) {
  619. *Vector = 9;
  620. VectorFound = TRUE;
  621. } else {
  622. *Vector = 0xffff;
  623. }
  624. //
  625. // Restore the i8259 slave.
  626. //
  627. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
  628. //
  629. // Restore the i8259 slave interrupt mask.
  630. //
  631. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
  632. }
  633. //
  634. // Tri-state the Inport IRQ line.
  635. //
  636. WRITE_PORT_UCHAR((PUCHAR) (CurrentPort + INPORT_DATA_REGISTER_1), 0);
  637. //
  638. // Restore the i8259 master.
  639. //
  640. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
  641. //
  642. // Restore the i8259 master interrupt mask.
  643. //
  644. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
  645. //
  646. // Restore the previous IRQL.
  647. //
  648. WRITE_PORT_UCHAR(
  649. (PUCHAR) PIC1_PORT1,
  650. OldMasterMask
  651. );
  652. WRITE_PORT_UCHAR(
  653. (PUCHAR) PIC2_PORT1,
  654. OldSlaveMask
  655. );
  656. return(VectorFound);
  657. }
  658. #endif