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.

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