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.

1649 lines
46 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. comport.c
  5. Abstract:
  6. This module contains C code to determine comport and LPT configuration in
  7. syste.
  8. Author:
  9. Shie-Lin Tzong (shielint) Dec-23-1991
  10. Revision History:
  11. --*/
  12. #include "hwdetect.h"
  13. #include "comlpt.h"
  14. #include "bios.h"
  15. #include "string.h"
  16. #define LOWEST_IRQ 3
  17. #define MASTER_IRQ_MASK_BITS 0xf8
  18. #define SLAVE_IRQ_MASK_BITS 0xfe
  19. //
  20. // ComPortAddress[] is a global array to remember which comports have
  21. // been detected and their I/O port addresses.
  22. //
  23. #if defined(NEC_98)
  24. #define NEC_MAX_COM_PORTS 15
  25. #define NEC_MAX_IO_PATTERN 38
  26. #define FIFO_INT_ID_PRS1 0x40
  27. #define FIFO_INT_ID_PRS 0x60
  28. #define COUNTRY_JAPAN 81
  29. #define NEC1500 0x1500 // Old mode
  30. #define NEC1501 0x1501 // SuperIO
  31. #define NEC1502 0x1502 // SuperIO2
  32. #define NEC1503 0x1503 // 2ndCCU 16550 Controller
  33. #define NEC8071 0x8071 // Extended Board of 1stCCU Compatibility Controller
  34. #define NEC0C01 0x0C01 // Extended Board of 16550 Compatibility Controller
  35. //
  36. // PC-9801-94 ports
  37. //
  38. #define TOKI_CONTROL 0x549
  39. #define READ_DIVISOR_LATCH( PDesiredDivisor ) \
  40. do \
  41. { \
  42. PUCHAR Address; \
  43. PSHORT PDivisor = PDesiredDivisor; \
  44. UCHAR LineControl; \
  45. UCHAR Lsb; \
  46. UCHAR Msb; \
  47. LineControl = READ_PORT_UCHAR( (PUCHAR)0x23b ); \
  48. WRITE_PORT_UCHAR((PUCHAR)0x23b,(UCHAR)0x80 ); \
  49. Lsb = READ_PORT_UCHAR( (PUCHAR)0x238 ); \
  50. Msb = READ_PORT_UCHAR( (PUCHAR)0x239 ); \
  51. *PDivisor = Lsb; \
  52. *PDivisor = *PDivisor | (((USHORT)Msb) << 8); \
  53. WRITE_PORT_UCHAR((PUCHAR)0x23b,(UCHAR)0x0 ); \
  54. } while (0)
  55. #define WRITE_DIVISOR_LATCH(BaseAddress,DesiredDivisor) \
  56. do \
  57. { \
  58. PUCHAR Address = BaseAddress; \
  59. SHORT Divisor = DesiredDivisor; \
  60. UCHAR LineControl; \
  61. LineControl = READ_PORT_UCHAR(Address+LINE_CONTROL_REGISTER); \
  62. WRITE_PORT_UCHAR( \
  63. Address+LINE_CONTROL_REGISTER, \
  64. (UCHAR)(LineControl | SERIAL_LCR_DLAB) \
  65. ); \
  66. WRITE_PORT_UCHAR( \
  67. Address+DIVISOR_LATCH_LSB, \
  68. (UCHAR)(Divisor & 0xff) \
  69. ); \
  70. WRITE_PORT_UCHAR( \
  71. Address+DIVISOR_LATCH_MSB, \
  72. (UCHAR)((Divisor & 0xff00) >> 8) \
  73. ); \
  74. WRITE_PORT_UCHAR( \
  75. Address+LINE_CONTROL_REGISTER, \
  76. LineControl \
  77. ); \
  78. } while (0)
  79. #define NextComPortNumber(ComportName, PortNumber) \
  80. do \
  81. { \
  82. if (PortNumber < 9){ \
  83. ComportName[3] = PortNumber + (UCHAR)'1'; \
  84. ComportName[4] = '\0'; \
  85. }else{ \
  86. ComportName[3] = (UCHAR)'1'; \
  87. ComportName[4] = (PortNumber - 10) + (UCHAR)'1'; \
  88. ComportName[5] = '\0'; \
  89. } \
  90. ++PortNumber; \
  91. }while(0) \
  92. USHORT ComPortAddress[NEC_MAX_COM_PORTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  93. #else // NEC_98
  94. USHORT ComPortAddress[MAX_COM_PORTS] = {0, 0, 0, 0};
  95. #endif // NEC_98
  96. #if defined(NEC_98)
  97. VOID
  98. NEC2ndCCUInitialize (
  99. VOID
  100. )
  101. /*++
  102. Routine Description:
  103. We have to initialize 2ndCCU(NS16550A) after system reset.
  104. Because the initial value of this chip is instability.
  105. Arguments:
  106. None.
  107. Return Value:
  108. None.
  109. --*/
  110. {
  111. _asm { cli }
  112. WRITE_PORT_UCHAR( (PUCHAR)0x0411,(UCHAR)0x91 );
  113. IoDelay(1);
  114. WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x01 );
  115. IoDelay(1);
  116. //
  117. // set baudrate.
  118. //
  119. WRITE_PORT_UCHAR( (PUCHAR)0x023B,(UCHAR)0x80 );
  120. IoDelay(1);
  121. WRITE_DIVISOR_LATCH( (PUCHAR)0x0238,(SHORT)0x0060 );
  122. IoDelay(1);
  123. WRITE_PORT_UCHAR( (PUCHAR)0x023B,(UCHAR)0x00 );
  124. IoDelay(1);
  125. WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x08 );
  126. //
  127. // wait 5 micro sec
  128. //
  129. IoDelay(5);
  130. WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x01 );
  131. IoDelay(1);
  132. _asm { sti }
  133. //
  134. // initialize - END
  135. //
  136. }
  137. BOOLEAN
  138. FifoPresenceCheck (
  139. PUCHAR PortAddress
  140. )
  141. /*++
  142. Routine Description:
  143. This routine reports whether the resource have FIFO faculty.
  144. Arguments:
  145. None.
  146. Return Value:
  147. Will return true if the resource have, otherwise it
  148. will return false.
  149. --*/
  150. {
  151. BOOLEAN FifoStatus = TRUE;
  152. USHORT cnt;
  153. UCHAR tmp;
  154. WRITE_PORT_UCHAR( (PUCHAR)(PortAddress - 0x1) , (UCHAR)(0x03) );
  155. IoDelay(10);
  156. tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
  157. IoDelay(10);
  158. if ((tmp & FIFO_INT_ID_PRS1) == 0) {
  159. tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
  160. IoDelay(10);
  161. }
  162. for (cnt = 0;cnt < 2;cnt++){
  163. tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
  164. IoDelay(10);
  165. if ((tmp & FIFO_INT_ID_PRS) != 0){
  166. FifoStatus = FALSE;
  167. break;
  168. }
  169. tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
  170. IoDelay(10);
  171. if ((tmp & FIFO_INT_ID_PRS) != 0x40){
  172. FifoStatus = FALSE;
  173. break;
  174. }
  175. }
  176. return(FifoStatus);
  177. }
  178. BOOLEAN
  179. DoesPortExistNEC101(
  180. SHORT PortNumber,
  181. PUSHORT InterruptNumber,
  182. PUSHORT PortLength
  183. )
  184. {
  185. BOOLEAN PortExist = FALSE;
  186. USHORT Port = PortNumber;
  187. USHORT NEC_y = 0;
  188. USHORT IsCommonInterrupt;
  189. USHORT temp1,temp2;
  190. USHORT Ch_2_IRQ_Tbl[4] = {3,5,6,9};
  191. USHORT Ch_3_IRQ_Tbl[4] = {3,10,12,13};
  192. USHORT COMMON_IRQ_Tbl[7] = {3,5,6,9,10,12,13};
  193. NEC_y = ( ( Port ) & (0x0f00) );
  194. switch (Port & 0x00ff) {
  195. case 0x00b0:
  196. if ( READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b3)) != 0xff ) {
  197. PortExist = TRUE;
  198. }
  199. break;
  200. case 0x00b2:
  201. if ( READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00bb)) != 0xff ) {
  202. PortExist = TRUE;
  203. }
  204. break;
  205. default:
  206. break;
  207. }
  208. //
  209. // This check is necessary to know detecting PC-9861K is not support.
  210. //
  211. if (( PortExist == TRUE ) &&
  212. ( FifoPresenceCheck((PUCHAR)(Port | 0x0005)) == FALSE)){
  213. PortExist = FALSE;
  214. }
  215. if (PortExist == TRUE){
  216. IsCommonInterrupt = ( (0x04) & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b8))) );
  217. IoDelay(10);
  218. if( IsCommonInterrupt ){
  219. temp1 = ( (0x03) & ( READ_PORT_UCHAR((PUCHAR)(NEC_y | Port))) );
  220. IoDelay(10);
  221. if( ( Port & (0x00ff) ) == 0x00b0 ){
  222. *InterruptNumber = Ch_2_IRQ_Tbl[temp1];
  223. }else{
  224. *InterruptNumber = Ch_3_IRQ_Tbl[temp1];
  225. }
  226. }else{
  227. temp1 = ( 0x01 & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b0))) );
  228. IoDelay(10);
  229. temp2 = ( 0x03 & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b2))) );
  230. IoDelay(10);
  231. *InterruptNumber = COMMON_IRQ_Tbl[(((temp1 << 2) | temp2) & 0x07)];
  232. }
  233. *PortLength = 1;
  234. }
  235. return(PortExist);
  236. }
  237. BOOLEAN
  238. DoesPortExistNECFaxModem(
  239. SHORT PortNumber,
  240. PUSHORT InterruptNumber,
  241. PUSHORT PortLength
  242. )
  243. {
  244. BOOLEAN PortExist = FALSE;
  245. USHORT Port = PortNumber;
  246. USHORT temp;
  247. temp = READ_PORT_UCHAR( (PUCHAR)(Port | 0x000f) );
  248. if ((temp & 0x0f0) == 0) {
  249. switch ( temp & 0x0f ) {
  250. case 0x01:
  251. *InterruptNumber = 3;
  252. break;
  253. case 0x02:
  254. *InterruptNumber = 5;
  255. break;
  256. case 0x04:
  257. *InterruptNumber = 6;
  258. break;
  259. case 0x08:
  260. *InterruptNumber = 12;
  261. break;
  262. default:
  263. break;
  264. }
  265. if (*InterruptNumber != 0) {
  266. PortExist = TRUE;
  267. }
  268. *PortLength = 8;
  269. }
  270. return(PortExist);
  271. }
  272. #endif // NEC_98
  273. #if !defined(_GAMBIT_)
  274. VOID
  275. SerialInterruptRequest (
  276. PUCHAR PortAddress
  277. )
  278. /*++
  279. Routine Description:
  280. This routine generates an interrupt on the interrupt line for
  281. com port.
  282. Arguments:
  283. PortAddress - the port address of the desired com port.
  284. Return Value:
  285. None.
  286. --*/
  287. {
  288. USHORT i;
  289. UCHAR Temp;
  290. WRITE_PORT_UCHAR(
  291. PortAddress + MODEM_CONTROL_REGISTER,
  292. 8
  293. );
  294. WRITE_PORT_UCHAR(
  295. PortAddress + INTERRUPT_ENABLE_REGISTER,
  296. 0
  297. );
  298. WRITE_PORT_UCHAR(
  299. PortAddress + INTERRUPT_ENABLE_REGISTER,
  300. 0xf
  301. );
  302. //
  303. // Add some delay
  304. //
  305. for (i = 0; i < 5 ; i++ ) {
  306. Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  307. Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  308. }
  309. }
  310. VOID
  311. SerialInterruptDismiss (
  312. PUCHAR PortAddress
  313. )
  314. /*++
  315. Routine Description:
  316. This routine dismisses an interrupt on the interrupt line for
  317. com port.
  318. Arguments:
  319. PortAddress - the port address of the desired com port.
  320. Return Value:
  321. None.
  322. --*/
  323. {
  324. USHORT i;
  325. UCHAR Temp;
  326. Temp = READ_PORT_UCHAR(
  327. PortAddress + INTERRUPT_IDENT_REGISTER
  328. );
  329. WRITE_PORT_UCHAR(
  330. PortAddress + INTERRUPT_ENABLE_REGISTER,
  331. 0
  332. );
  333. //
  334. // Add some delay
  335. //
  336. for (i = 0; i < 5 ; i++ ) {
  337. Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  338. Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  339. }
  340. }
  341. BOOLEAN
  342. DoesPortExist(
  343. IN PUCHAR Address
  344. )
  345. /*++
  346. Routine Description:
  347. This routine examines several of what might be the serial device
  348. registers. It ensures that the bits that should be zero are zero.
  349. It will then attempt to set the device to 19200 baud. If the
  350. will then attempt to read that baud. If it is still 19200 then
  351. we can feel pretty safe that this is a serial device.
  352. NOTE: If there is indeed a serial port at the address specified
  353. it will absolutely have interrupts inhibited upon return
  354. from this routine.
  355. Arguments:
  356. Address - address of hw port.
  357. Return Value:
  358. TRUE - Port exists. Party on.
  359. FALSE - Port doesn't exist. Don't use it.
  360. History:
  361. 7/23/97 a-paulbr fixed bug 95050. Init LineControl to 0x00
  362. --*/
  363. {
  364. UCHAR IerContents;
  365. UCHAR BaudRateMsb, BaudRateLsb;
  366. BOOLEAN ReturnValue = FALSE;
  367. UCHAR LineControl = 0x00;
  368. UCHAR LineControl_Save;
  369. UCHAR Temp;
  370. //
  371. // Save the original LCR, so we can restore it later
  372. // We won't use it, because the port could be handing us
  373. // a bad initial value. We will use 0x00 instead.
  374. //
  375. LineControl_Save = READ_PORT_UCHAR(Address+LINE_CONTROL_REGISTER);
  376. //
  377. // Read original baud rate divisor and save it.
  378. //
  379. WRITE_PORT_UCHAR(
  380. Address+LINE_CONTROL_REGISTER,
  381. (UCHAR)(LineControl | SERIAL_LCR_DLAB)
  382. );
  383. BaudRateMsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
  384. BaudRateLsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
  385. //
  386. // Change baud rate to 9600.
  387. //
  388. WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BAUD_RATE_9600_MSB);
  389. WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BAUD_RATE_9600_LSB);
  390. //
  391. // Read IER and save it away.
  392. //
  393. WRITE_PORT_UCHAR(
  394. Address+LINE_CONTROL_REGISTER,
  395. (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
  396. );
  397. IerContents = READ_PORT_UCHAR(
  398. Address + INTERRUPT_ENABLE_REGISTER
  399. );
  400. WRITE_PORT_UCHAR(
  401. Address + INTERRUPT_ENABLE_REGISTER,
  402. IER_TEST_VALUE
  403. );
  404. //
  405. // Read baud rate divisor. The values we read should be equal to the
  406. // values we set earlier.
  407. //
  408. WRITE_PORT_UCHAR(
  409. Address+LINE_CONTROL_REGISTER,
  410. (UCHAR)(LineControl | SERIAL_LCR_DLAB)
  411. );
  412. Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
  413. if (Temp != BAUD_RATE_9600_MSB) {
  414. goto AllDone;
  415. }
  416. Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
  417. if (Temp != BAUD_RATE_9600_LSB) {
  418. goto AllDone;
  419. }
  420. //
  421. // Read IER and it should be equal to the value we set earlier.
  422. //
  423. WRITE_PORT_UCHAR(
  424. Address+LINE_CONTROL_REGISTER,
  425. (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
  426. );
  427. Temp = READ_PORT_UCHAR(
  428. Address + INTERRUPT_ENABLE_REGISTER
  429. );
  430. if (Temp != IER_TEST_VALUE) {
  431. goto AllDone;
  432. }
  433. ReturnValue = TRUE;
  434. AllDone:
  435. //
  436. // Restore registers which we destroyed .
  437. //
  438. WRITE_PORT_UCHAR(
  439. Address+LINE_CONTROL_REGISTER,
  440. (UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
  441. );
  442. WRITE_PORT_UCHAR(
  443. Address + INTERRUPT_ENABLE_REGISTER,
  444. IerContents
  445. );
  446. WRITE_PORT_UCHAR(
  447. Address+LINE_CONTROL_REGISTER,
  448. (UCHAR)(LineControl | SERIAL_LCR_DLAB)
  449. );
  450. WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BaudRateMsb);
  451. WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BaudRateLsb);
  452. WRITE_PORT_UCHAR(
  453. Address+LINE_CONTROL_REGISTER,
  454. LineControl_Save
  455. );
  456. return ReturnValue;
  457. }
  458. BOOLEAN
  459. HwInterruptDetection(
  460. IN PUCHAR BasePort,
  461. IN VOID (*InterruptRequestRoutine)(),
  462. IN VOID (*InterruptDismissRoutine)(),
  463. OUT PUSHORT Vector
  464. )
  465. /*++
  466. Routine Description:
  467. This routine attempts to locate the interrupt vector for which
  468. the device is configured. The allowable vectors are
  469. 3 - 7, and 9 - 15. If no interrupt vector is found, or more than
  470. one is found, the routine returns FALSE. Otherwise, TRUE is returned.
  471. Note that we diddle the i8259 interrupt controllers here.
  472. Arguments:
  473. BasePort - the I/O port base for the device.
  474. InterruptRequestRoutine - A pointer to a routine to generate
  475. desired interrupt.
  476. InterruptDismissRoutine - A pointer to a routine to dismiss the interrupt
  477. generated by InterruptRequestRoutine.
  478. Vector - Pointer to the location to store the mouse interrupt vector.
  479. Return Value:
  480. Returns TRUE if the Inport interrupt vector was located; otherwise,
  481. FALSE is returned.
  482. --*/
  483. {
  484. UCHAR OldMasterMask, OldSlaveMask;
  485. UCHAR MasterMask, SlaveMask;
  486. UCHAR InterruptBits;
  487. UCHAR PossibleInterruptBits;
  488. int i;
  489. int NumberOfIRQs;
  490. BOOLEAN VectorFound = FALSE;
  491. //
  492. // Get the i8259 interrupt masks.
  493. //
  494. OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  495. OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  496. //
  497. // Raise IRQL to the highest priority IRQL the inport would use.
  498. //
  499. WRITE_PORT_UCHAR(
  500. (PUCHAR) PIC1_PORT1,
  501. (UCHAR) 0xff ^ ((UCHAR)(1 << LOWEST_IRQ) - 1)
  502. );
  503. WRITE_PORT_UCHAR(
  504. (PUCHAR) PIC2_PORT1,
  505. (UCHAR) 0xfe
  506. );
  507. //
  508. // Get the master i8259 interrupt mask.
  509. //
  510. MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
  511. //
  512. // Disable potential device interrupts.
  513. //
  514. WRITE_PORT_UCHAR(
  515. (PUCHAR) PIC1_PORT1,
  516. (UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
  517. );
  518. //
  519. // Attempt to locate the interrupt line on the master i8259.
  520. // Why try this 10 times? It's magic...
  521. //
  522. PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
  523. for (i = 0; i < 10; i++) {
  524. //
  525. // Generate a 0 on the master 8259 interrupt line
  526. //
  527. (*InterruptDismissRoutine)(BasePort);
  528. //
  529. // Read the interrupt bits off the master i8259. Only bits
  530. // 3 - 7 are of interest. Eliminate non-functional
  531. // IRQs. Only continue looking at the master i8259 if there
  532. // is at least one functional IRQ.
  533. //
  534. _asm {cli}
  535. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
  536. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
  537. _asm {sti}
  538. InterruptBits &= MASTER_IRQ_MASK_BITS;
  539. InterruptBits ^= MASTER_IRQ_MASK_BITS;
  540. PossibleInterruptBits &= InterruptBits;
  541. if (!PossibleInterruptBits) {
  542. break;
  543. }
  544. //
  545. // Generate an interrupt from the desired device.
  546. //
  547. (*InterruptRequestRoutine)(BasePort);
  548. //
  549. // Read the interrupt bits off the master i8259. Only bits
  550. // 3 - 7 are of interest. Eliminate non-functional
  551. // IRQs. Only continue looking at the master i8259 if there
  552. // is at least one functional IRQ.
  553. //
  554. _asm {cli}
  555. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
  556. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
  557. _asm {sti}
  558. InterruptBits &= MASTER_IRQ_MASK_BITS;
  559. PossibleInterruptBits &= InterruptBits;
  560. if (!PossibleInterruptBits) {
  561. break;
  562. }
  563. }
  564. if (PossibleInterruptBits) {
  565. //
  566. // We found at least one IRQ on the master i8259 that could belong
  567. // to the Inport mouse. Count how many we found. If there is
  568. // more than one, we haven't found the vector. Otherwise, we've
  569. // successfully located the Inport interrupt vector on the master
  570. // i8259 (provided the interrupt vector is 3, 4, 5, or 7).
  571. //
  572. PossibleInterruptBits >>= 3;
  573. NumberOfIRQs = 0;
  574. for (i = 3; i <= 7; i++) {
  575. if (PossibleInterruptBits & 1) {
  576. NumberOfIRQs += 1;
  577. *Vector = (CCHAR) i;
  578. }
  579. PossibleInterruptBits >>= 1;
  580. }
  581. if (NumberOfIRQs == 1) {
  582. VectorFound = TRUE;
  583. }
  584. }
  585. //
  586. // If we didn't locate the interrupt vector on the master i8259, attempt
  587. // to locate it on the slave i8259.
  588. //
  589. if (!VectorFound) {
  590. //
  591. // Get the slave i8259 interrupt mask.
  592. //
  593. SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
  594. //
  595. // Attempt to locate the interupt line on the slave i8259.
  596. // Why try this 20 times? It's magic...
  597. //
  598. PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
  599. for (i = 0; i < 20; i++) {
  600. //
  601. // Generate a 0 on the Inport IRQ on the slave i8259.
  602. //
  603. (*InterruptDismissRoutine)(BasePort);
  604. //
  605. // Read the interrupt bits off the slave i8259.
  606. // Eliminate non-functional IRQs. Only continue
  607. // looking at the slave i8259 if there is at least one
  608. // functional IRQ.
  609. //
  610. _asm {cli}
  611. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
  612. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
  613. _asm {sti}
  614. InterruptBits &= SLAVE_IRQ_MASK_BITS;
  615. InterruptBits ^= SLAVE_IRQ_MASK_BITS;
  616. PossibleInterruptBits &= InterruptBits;
  617. if (!PossibleInterruptBits) {
  618. break;
  619. }
  620. //
  621. // Generate a 1 on the Inport IRQ on the slave i8259.
  622. //
  623. (*InterruptRequestRoutine)(BasePort);
  624. //
  625. // Read the interrupt bits off the slave i8259.
  626. // Eliminate non-functional IRQs. Only continue
  627. // looking at the slave i8259 if there is at least one
  628. // functional IRQ.
  629. //
  630. _asm {cli}
  631. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
  632. InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
  633. _asm {sti}
  634. InterruptBits &= SLAVE_IRQ_MASK_BITS;
  635. PossibleInterruptBits &= InterruptBits;
  636. if (!PossibleInterruptBits) {
  637. break;
  638. }
  639. }
  640. if (PossibleInterruptBits) {
  641. //
  642. // We found at least one IRQ on the slave i8259 that could belong
  643. // to the device. Count how many we found. If there is
  644. // more than one, we haven't found the vector. Otherwise, we've
  645. // successfully located the device interrupt vector on the slave
  646. // i8259.
  647. //
  648. PossibleInterruptBits >>= 1;
  649. NumberOfIRQs = 0;
  650. for (i = 9; i <= 15; i++) {
  651. if (PossibleInterruptBits & 1) {
  652. NumberOfIRQs += 1;
  653. *Vector = (CCHAR) i;
  654. }
  655. PossibleInterruptBits >>= 1;
  656. }
  657. if (NumberOfIRQs == 1) {
  658. VectorFound = TRUE;
  659. }
  660. }
  661. //
  662. // Restore the i8259 slave.
  663. //
  664. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
  665. //
  666. // Restore the i8259 slave interrupt mask.
  667. //
  668. WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
  669. }
  670. //
  671. // Dismiss interrupt on the device
  672. //
  673. (*InterruptDismissRoutine)(BasePort);
  674. //
  675. // Restore the i8259 master.
  676. //
  677. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
  678. //
  679. // Restore the i8259 master interrupt mask.
  680. //
  681. WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
  682. //
  683. // Restore the previous IRQL.
  684. //
  685. WRITE_PORT_UCHAR(
  686. (PUCHAR) PIC1_PORT1,
  687. OldMasterMask
  688. );
  689. WRITE_PORT_UCHAR(
  690. (PUCHAR) PIC2_PORT1,
  691. OldSlaveMask
  692. );
  693. return(VectorFound);
  694. }
  695. #endif // _GAMBIT_
  696. FPFWCONFIGURATION_COMPONENT_DATA
  697. GetComportInformation (
  698. VOID
  699. )
  700. /*++
  701. Routine Description:
  702. This routine will attempt to detect the comports information
  703. for the system. The information includes port address, irq
  704. level.
  705. Note that this routine can only detect up to 4 comports and
  706. it assumes that if MCA, COM3 and COM4 use irq 4. Otherwise,
  707. COM3 uses irq 4 and COM4 uses irq 3. Also, the number of ports
  708. for COMPORT is set to 8 (for example, COM2 uses ports 2F8 - 2FF)
  709. Arguments:
  710. None.
  711. Return Value:
  712. A pointer to a stucture of type FWCONFIGURATION_COMPONENT_DATA
  713. which is the root of comport component list.
  714. If no comport exists, a value of NULL is returned.
  715. --*/
  716. {
  717. #if defined(NEC_98)
  718. FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
  719. FPFWCONFIGURATION_COMPONENT_DATA FirstComport = NULL;
  720. FPFWCONFIGURATION_COMPONENT Component;
  721. HWCONTROLLER_DATA ControlData;
  722. UCHAR i, j, z;
  723. SHORT Port;
  724. UCHAR ComportName[] = "COM??";
  725. CM_SERIAL_DEVICE_DATA SerialData;
  726. ULONG BaudClock = 1843200;
  727. USHORT Vector;
  728. BOOLEAN PortExist;
  729. USHORT IoPorts[NEC_MAX_IO_PATTERN] = {0x030, 0x238,
  730. 0x00b0, 0x00b2, 0x01b0, 0x01b2, 0x02b0, 0x02b2,
  731. 0x03b0, 0x03b2, 0x04b0, 0x04b2, 0x05b0, 0x05b2,
  732. 0x06b0, 0x06b2, 0x07b0, 0x07b2, 0x08b0, 0x08b2,
  733. 0x09b0, 0x09b2, 0x0ab0, 0x0ab2, 0x0bb0, 0x0bb2,
  734. 0x0cb0, 0x0cb2, 0x0db0, 0x0db2, 0x0eb0, 0x0eb2,
  735. 0x0fb0, 0x0fb2,
  736. 0x8b0, 0x9b0, 0xab0, 0xbb0};
  737. USHORT PortLength;
  738. USHORT InterruptNumber;
  739. USHORT NEC_COM_number = 0;
  740. //
  741. // Check BIOS ROM data is right or not.
  742. // if not, we don't detect CCU.
  743. //
  744. if ( (COM_ID_L != 0x98) || (COM_ID_H != 0x21) ){
  745. return(FirstComport);
  746. }
  747. //
  748. // Initialize serial device specific data
  749. //
  750. SerialData.Version = COUNTRY_JAPAN;
  751. SerialData.Revision = NEC1500;
  752. SerialData.BaudClock = 153600;
  753. for (i = 0; i < NEC_MAX_IO_PATTERN; i++) {
  754. PortExist = FALSE;
  755. //
  756. // Initialize Controller data
  757. //
  758. ControlData.NumberPortEntries = 0;
  759. ControlData.NumberIrqEntries = 0;
  760. ControlData.NumberMemoryEntries = 0;
  761. ControlData.NumberDmaEntries = 0;
  762. z = 0;
  763. //
  764. // Load the port address from the BIOS data area, if it exists
  765. //
  766. Port = IoPorts[i];
  767. InterruptNumber = 0;
  768. switch(i){
  769. case 0:
  770. //
  771. // internal 1st CCU
  772. //
  773. if ( (ROM_FLAG7 & LOCKED_CCU1) == 0 ) {
  774. PortExist = TRUE;
  775. InterruptNumber = 4;
  776. PortLength = 1;
  777. SerialData.Revision = NEC1501;
  778. if (ROM_FLAG5 & 0x10) {
  779. SerialData.Revision = NEC1502;
  780. }
  781. }
  782. break;
  783. case 1:
  784. //
  785. // internal 2nd CCU
  786. //
  787. if ( (ROM_FLAG5 & 0x08) && ((ROM_FLAG7 & LOCKED_CCU2) == 0) ) {
  788. PortExist = DoesPortExist( (PUCHAR)Port );
  789. InterruptNumber = 5;
  790. PortLength = 7;
  791. SerialData.Revision = NEC1503;
  792. SerialData.BaudClock = 1843200;
  793. }
  794. break;
  795. case 34:
  796. case 35:
  797. case 36:
  798. case 37:
  799. //
  800. // external FAX/Modem board
  801. //
  802. PortExist = DoesPortExistNECFaxModem(Port,&InterruptNumber,&PortLength);
  803. SerialData.Revision = NEC0C01;
  804. SerialData.BaudClock = 1843200;
  805. break;
  806. default:
  807. //
  808. // PC-9801-101 borad
  809. //
  810. PortExist = DoesPortExistNEC101(Port,&InterruptNumber,&PortLength);
  811. SerialData.Revision = NEC8071;
  812. SerialData.BaudClock = 153600;
  813. break;
  814. }
  815. if (PortExist) {
  816. //
  817. // Remember the port address in our global variable
  818. // such that other detection code (e.g. Serial Mouse) can
  819. // get the information.
  820. //
  821. ComPortAddress[NEC_COM_number] = Port;
  822. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  823. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  824. if (!FirstComport) {
  825. FirstComport = CurrentEntry;
  826. }
  827. Component = &CurrentEntry->ComponentEntry;
  828. Component->Class = ControllerClass;
  829. Component->Type = SerialController;
  830. Component->Flags.ConsoleOut = 1;
  831. Component->Flags.ConsoleIn = 1;
  832. Component->Flags.Output = 1;
  833. Component->Flags.Input = 1;
  834. Component->Version = 0;
  835. Component->Key = NEC_COM_number;
  836. Component->AffinityMask = 0xffffffff;
  837. //
  838. // Set up type string.
  839. //
  840. NextComPortNumber(ComportName, NEC_COM_number);
  841. // ComportName[3] = NEC_COM_number + (UCHAR)'1';
  842. // NEC_COM_number++;
  843. //
  844. // Set up Port information
  845. //
  846. ControlData.NumberPortEntries = 1;
  847. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  848. ControlData.DescriptorList[z].ShareDisposition =
  849. CmResourceShareDeviceExclusive;
  850. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  851. ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)Port;
  852. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  853. ControlData.DescriptorList[z].u.Port.Length = PortLength;
  854. z++;
  855. //
  856. // Set up Irq information
  857. //
  858. ControlData.NumberIrqEntries = 1;
  859. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  860. ControlData.DescriptorList[z].ShareDisposition =
  861. CmResourceShareUndetermined;
  862. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  863. ControlData.DescriptorList[z].u.Interrupt.Level = InterruptNumber;
  864. ControlData.DescriptorList[z].u.Interrupt.Vector = InterruptNumber;
  865. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  866. CurrentEntry->ConfigurationData =
  867. HwSetUpResourceDescriptor(Component,
  868. ComportName,
  869. &ControlData,
  870. sizeof(SerialData),
  871. (PUCHAR)&SerialData
  872. );
  873. if (PreviousEntry) {
  874. PreviousEntry->Sibling = CurrentEntry;
  875. }
  876. PreviousEntry = CurrentEntry;
  877. if (Port == 0x238){
  878. NEC2ndCCUInitialize ();
  879. }
  880. }
  881. }
  882. return(FirstComport);
  883. #else // NEC_98
  884. FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
  885. FPFWCONFIGURATION_COMPONENT_DATA FirstComport = NULL;
  886. FPFWCONFIGURATION_COMPONENT Component;
  887. HWCONTROLLER_DATA ControlData;
  888. UCHAR i, j, z;
  889. SHORT Port;
  890. UCHAR ComportName[] = "COM?";
  891. CM_SERIAL_DEVICE_DATA SerialData;
  892. ULONG BaudClock = 1843200;
  893. USHORT Vector;
  894. BOOLEAN PortExist;
  895. USHORT IoPorts[MAX_COM_PORTS] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  896. #if !defined(_GAMBIT_)
  897. //
  898. // BIOS DATA area 40:0 is the port address of the first valid COM port
  899. //
  900. USHORT far *pPortAddress = (USHORT far *)0x00400000;
  901. #endif
  902. //
  903. // Initialize serial device specific data
  904. //
  905. SerialData.Version = 0;
  906. SerialData.Revision = 0;
  907. SerialData.BaudClock = 1843200;
  908. #if !defined(_GAMBIT_)
  909. //
  910. // Initialize default COM port address.
  911. // Some BIOS puts incorrect comport address to the 40:0 area.
  912. // To cope with this problem, we test the port address supplied
  913. // by BIOS first. If it fail, we try our default port.
  914. //
  915. for (i = 0; i < MAX_COM_PORTS; i++) {
  916. for (j = 0; j < MAX_COM_PORTS; j++) {
  917. if (IoPorts[i] == *(pPortAddress + j)) {
  918. IoPorts[i] = 0;
  919. break;
  920. }
  921. }
  922. }
  923. #endif
  924. #if defined(_GAMBIT_)
  925. for (i = 0; i < 1; i++) {
  926. #else
  927. for (i = 0; i < MAX_COM_PORTS; i++) {
  928. #endif
  929. PortExist = FALSE;
  930. //
  931. // Initialize Controller data
  932. //
  933. ControlData.NumberPortEntries = 0;
  934. ControlData.NumberIrqEntries = 0;
  935. ControlData.NumberMemoryEntries = 0;
  936. ControlData.NumberDmaEntries = 0;
  937. z = 0;
  938. #if _GAMBIT_
  939. Port = IoPorts[i];
  940. PortExist = TRUE;
  941. #else
  942. //
  943. // Load the port address from the BIOS data area, if it exists
  944. //
  945. Port = *(pPortAddress + i);
  946. //
  947. // Determine if the port exists
  948. //
  949. if (Port != 0) {
  950. if (DoesPortExist((PUCHAR)Port)) {
  951. PortExist = TRUE;
  952. }
  953. }
  954. if (!PortExist && (Port = IoPorts[i])) {
  955. if (PortExist = DoesPortExist((PUCHAR)Port)) {
  956. IoPorts[i] = 0;
  957. *(pPortAddress+i) = (USHORT)Port;
  958. }
  959. }
  960. #endif //_GAMBIT_
  961. if (PortExist) {
  962. //
  963. // Remember the port address in our global variable
  964. // such that other detection code (e.g. Serial Mouse) can
  965. // get the information.
  966. //
  967. ComPortAddress[i] = Port;
  968. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  969. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  970. if (!FirstComport) {
  971. FirstComport = CurrentEntry;
  972. }
  973. Component = &CurrentEntry->ComponentEntry;
  974. Component->Class = ControllerClass;
  975. Component->Type = SerialController;
  976. Component->Flags.ConsoleOut = 1;
  977. Component->Flags.ConsoleIn = 1;
  978. Component->Flags.Output = 1;
  979. Component->Flags.Input = 1;
  980. Component->Version = 0;
  981. Component->Key = i;
  982. Component->AffinityMask = 0xffffffff;
  983. //
  984. // Set up type string.
  985. //
  986. ComportName[3] = i + (UCHAR)'1';
  987. //
  988. // Set up Port information
  989. //
  990. ControlData.NumberPortEntries = 1;
  991. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  992. ControlData.DescriptorList[z].ShareDisposition =
  993. CmResourceShareDeviceExclusive;
  994. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  995. ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)Port;
  996. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  997. ControlData.DescriptorList[z].u.Port.Length = 7;
  998. z++;
  999. //
  1000. // Set up Irq information
  1001. //
  1002. ControlData.NumberIrqEntries = 1;
  1003. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  1004. ControlData.DescriptorList[z].ShareDisposition =
  1005. CmResourceShareUndetermined;
  1006. if (HwBusType == MACHINE_TYPE_MCA) {
  1007. ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
  1008. if (i == 0) { // COM1 - irql4; COM2 - COM3 - irq3
  1009. ControlData.DescriptorList[z].u.Interrupt.Level = 4;
  1010. ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
  1011. } else {
  1012. ControlData.DescriptorList[z].u.Interrupt.Level = 3;
  1013. ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
  1014. }
  1015. } else {
  1016. //
  1017. // For EISA the LevelTriggered is temporarily set to FALSE.
  1018. // COM1 and COM3 use irq 4; COM2 and COM4 use irq3
  1019. //
  1020. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  1021. if (Port == 0x3f8 || Port == 0x3e8) {
  1022. ControlData.DescriptorList[z].u.Interrupt.Level = 4;
  1023. ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
  1024. } else if (Port == 0x2f8 || Port == 0x2e8) {
  1025. ControlData.DescriptorList[z].u.Interrupt.Level = 3;
  1026. ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
  1027. } else if (i == 0 || i == 2) {
  1028. ControlData.DescriptorList[z].u.Interrupt.Level = 4;
  1029. ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
  1030. } else {
  1031. ControlData.DescriptorList[z].u.Interrupt.Level = 3;
  1032. ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
  1033. }
  1034. }
  1035. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  1036. //
  1037. // Try to determine the interrupt vector. If we success, the
  1038. // new vector will be used to replace the default value.
  1039. //
  1040. #if !defined(_GAMBIT_)
  1041. if (HwInterruptDetection((PUCHAR)Port,
  1042. SerialInterruptRequest,
  1043. SerialInterruptDismiss,
  1044. &Vector)) {
  1045. ControlData.DescriptorList[z].u.Interrupt.Level =
  1046. (ULONG)Vector;
  1047. ControlData.DescriptorList[z].u.Interrupt.Vector =
  1048. (ULONG)Vector;
  1049. }
  1050. //
  1051. // Since the com port interrupt detection destryed some
  1052. // of the com port registers, here we do the clean up.
  1053. //
  1054. WRITE_PORT_UCHAR ((PUCHAR)(Port + INTERRUPT_ENABLE_REGISTER), 0);
  1055. WRITE_PORT_UCHAR ((PUCHAR)(Port + MODEM_CONTROL_REGISTER), 0);
  1056. #endif //_GAMBIT_
  1057. CurrentEntry->ConfigurationData =
  1058. HwSetUpResourceDescriptor(Component,
  1059. ComportName,
  1060. &ControlData,
  1061. sizeof(SerialData),
  1062. (PUCHAR)&SerialData
  1063. );
  1064. if (PreviousEntry) {
  1065. PreviousEntry->Sibling = CurrentEntry;
  1066. }
  1067. PreviousEntry = CurrentEntry;
  1068. }
  1069. }
  1070. return(FirstComport);
  1071. #endif // NEC_98
  1072. }
  1073. #if !defined(_GAMBIT_)
  1074. FPFWCONFIGURATION_COMPONENT_DATA
  1075. GetLptInformation (
  1076. VOID
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. This routine will attempt to detect the parallel printer port
  1081. information for the system. The information includes port address,
  1082. irq level.
  1083. Note if this code is run after user established NETWORK LPT
  1084. connection. The Network LPT will be counted as regular parallel
  1085. port.
  1086. Arguments:
  1087. None.
  1088. Return Value:
  1089. A pointer to a stucture of type PONENT_DATA
  1090. which is the root of Parallel component list.
  1091. If no comport exists, a value of NULL is returned.
  1092. --*/
  1093. {
  1094. FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
  1095. FPFWCONFIGURATION_COMPONENT_DATA FirstLptPort = NULL;
  1096. FPFWCONFIGURATION_COMPONENT Component;
  1097. HWCONTROLLER_DATA ControlData;
  1098. UCHAR LptPortName[] = "PARALLEL?";
  1099. USHORT i, z;
  1100. USHORT LptStatus;
  1101. ULONG Port;
  1102. #if defined(NEC_98)
  1103. ULONG Portnec;
  1104. int lptportnumnec;
  1105. UCHAR level;
  1106. UCHAR j = 0;
  1107. UCHAR tmp;
  1108. USHORT PortAddress[MAX_LPT_PORTS] = { 0, 0, 0 };
  1109. USHORT far *pPortAddress = &PortAddress;
  1110. //
  1111. // check the internal LPT port is locked.
  1112. //
  1113. if ( COM_ID_L == 0x98 && COM_ID_H == 0x21 &&
  1114. ROM_FLAG7 & LOCKED_LPT ){
  1115. // The LPT was locked .
  1116. // skip the internal LPT port.
  1117. } else {
  1118. //
  1119. // try to set full centro mode
  1120. //
  1121. _asm {
  1122. push ax
  1123. mov ah, 17h
  1124. int 1Ah
  1125. mov tmp, ah
  1126. pop ax
  1127. }
  1128. if ( BIOS_FLAG5 & PRTMODE_FULL_CENTRO ){
  1129. PortAddress[0] = 0x140; // Full centro-mode
  1130. } else {
  1131. PortAddress[0] = 0x40; // Old type.
  1132. }
  1133. j++;
  1134. }
  1135. //
  1136. // check the external LPT ports.
  1137. //
  1138. // NOTE:
  1139. // There is check codes that external port is starting LPT1 or LPT2.
  1140. // at here in PC-98's old original source.
  1141. // It read 0x054F(Int Ch Read) port and check CAON (bit2).
  1142. // If the bit is clear, then the port is starting LPT1.
  1143. // I could not understand its raison d'e^tre.
  1144. //
  1145. tmp = READ_PORT_UCHAR( (PUCHAR)TOKI_CONTROL );
  1146. if ( tmp == 0xFF ){
  1147. //
  1148. // There is no external LPT ports.
  1149. //
  1150. PortAddress[j] = 0;
  1151. PortAddress[j+1] = 0;
  1152. } else {
  1153. //
  1154. // There is a extended card (PC-9801-94).
  1155. // It has 2 LPT ports.
  1156. // Change them to Full centro mode.
  1157. //
  1158. PortAddress[j] = 0x540;
  1159. WRITE_PORT_UCHAR( (PUCHAR)0x0549, (UCHAR)0x10 );
  1160. WRITE_PORT_UCHAR( (PUCHAR)0x054E, (UCHAR)0x00 );
  1161. WRITE_PORT_UCHAR( (PUCHAR)0x0542, (UCHAR)0x04 );
  1162. PortAddress[j+1] = 0xD40;
  1163. WRITE_PORT_UCHAR( (PUCHAR)0x0D49, (UCHAR)0x10 );
  1164. WRITE_PORT_UCHAR( (PUCHAR)0x0D4E, (UCHAR)0x00 );
  1165. WRITE_PORT_UCHAR( (PUCHAR)0x0D42, (UCHAR)0x04 );
  1166. //
  1167. // get int level
  1168. //
  1169. tmp = READ_PORT_UCHAR( (PUCHAR)0x54F );
  1170. switch( tmp & 0x3 ){
  1171. case 0x00:
  1172. level = 3; // Extended slot INT 0
  1173. break;
  1174. case 0x01:
  1175. level = 5; // Extended slot INT 1
  1176. break;
  1177. case 0x10:
  1178. level = 6; // Extended slot INT 2
  1179. break;
  1180. case 0x11:
  1181. level = 13; // Extended slot INT 6
  1182. }
  1183. }
  1184. #else // NEC_98
  1185. //
  1186. // BIOS DATA area 40:8 is the port address of the first valid COM port
  1187. //
  1188. USHORT far *pPortAddress = (USHORT far *)0x00400008;
  1189. #endif // NEC_98
  1190. for (i = 0; i < MAX_LPT_PORTS; i++) {
  1191. Port = (ULONG)*(pPortAddress + i);
  1192. if (Port == 0) {
  1193. continue;
  1194. #if defined(NEC_98)
  1195. #else
  1196. } else {
  1197. //
  1198. // If we think we have a lpt, we will initialize it to
  1199. // a known state. In order to make printing work under
  1200. // nt, the arbitration level must be disabled. The BIOS
  1201. // init function seems to do the trick.
  1202. //
  1203. _asm {
  1204. mov ah, 1
  1205. mov dx, i
  1206. int 17h
  1207. }
  1208. #endif
  1209. }
  1210. //
  1211. // Initialize Controller data
  1212. //
  1213. ControlData.NumberPortEntries = 0;
  1214. ControlData.NumberIrqEntries = 0;
  1215. ControlData.NumberMemoryEntries = 0;
  1216. ControlData.NumberDmaEntries = 0;
  1217. z = 0;
  1218. #if defined(NEC_98)
  1219. //
  1220. // We do not have to determine if the port exists.
  1221. // Because it was already done.
  1222. //
  1223. LptStatus = 0;
  1224. #else // NEC_98
  1225. //
  1226. // Determine if the port exists
  1227. //
  1228. LptStatus = _bios_printer(_PRINTER_STATUS, i , 0);
  1229. #endif // NEC_98
  1230. if (!(LptStatus & 6)){
  1231. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  1232. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  1233. if (!FirstLptPort) {
  1234. FirstLptPort = CurrentEntry;
  1235. }
  1236. Component = &CurrentEntry->ComponentEntry;
  1237. Component->Class = ControllerClass;
  1238. Component->Type = ParallelController;
  1239. Component->Flags.Output = 1;
  1240. Component->Version = 0;
  1241. Component->Key = i;
  1242. Component->AffinityMask = 0xffffffff;
  1243. //
  1244. // Set up type string.
  1245. //
  1246. LptPortName[8] = (UCHAR)i + (UCHAR)'1';
  1247. //
  1248. // Set up Port information
  1249. //
  1250. Port = (ULONG)*(pPortAddress + i);
  1251. #if defined(NEC_98)
  1252. if (Port == 0x40){
  1253. ControlData.NumberPortEntries = 4;
  1254. for ( j = 0; j < ControlData.NumberPortEntries; j++ ){
  1255. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  1256. ControlData.DescriptorList[z].ShareDisposition =
  1257. CmResourceShareDeviceExclusive;
  1258. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  1259. ControlData.DescriptorList[z].u.Port.Start.LowPart = Port + (j * 2);
  1260. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  1261. ControlData.DescriptorList[z].u.Port.Length = 1;
  1262. z++;
  1263. }
  1264. }else{
  1265. #endif // NEC_98
  1266. ControlData.NumberPortEntries = 1;
  1267. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  1268. ControlData.DescriptorList[z].ShareDisposition =
  1269. CmResourceShareDeviceExclusive;
  1270. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  1271. ControlData.DescriptorList[z].u.Port.Start.LowPart = Port;
  1272. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  1273. ControlData.DescriptorList[z].u.Port.Length = 3;
  1274. z++;
  1275. #if defined(NEC_98)
  1276. }
  1277. #endif // NEC_98
  1278. //
  1279. // Set up Irq information
  1280. //
  1281. ControlData.NumberIrqEntries = 1;
  1282. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  1283. ControlData.DescriptorList[z].ShareDisposition =
  1284. CmResourceShareUndetermined;
  1285. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  1286. #if defined(NEC_98)
  1287. if (i ==0) {
  1288. ControlData.DescriptorList[z].u.Interrupt.Level = 14;
  1289. ControlData.DescriptorList[z].u.Interrupt.Vector = 14;
  1290. } else {
  1291. ControlData.DescriptorList[z].u.Interrupt.Level = level;
  1292. ControlData.DescriptorList[z].u.Interrupt.Vector = level;
  1293. }
  1294. #else // NEC_98
  1295. if (i ==0) {
  1296. ControlData.DescriptorList[z].u.Interrupt.Level = 7;
  1297. ControlData.DescriptorList[z].u.Interrupt.Vector = 7;
  1298. } else {
  1299. ControlData.DescriptorList[z].u.Interrupt.Level = 5;
  1300. ControlData.DescriptorList[z].u.Interrupt.Vector = 5;
  1301. }
  1302. #endif // NEC_98
  1303. if (HwBusType == MACHINE_TYPE_MCA) {
  1304. ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
  1305. } else {
  1306. //
  1307. // For EISA the LevelTriggered is temporarily set to FALSE.
  1308. //
  1309. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  1310. }
  1311. CurrentEntry->ConfigurationData =
  1312. HwSetUpResourceDescriptor(Component,
  1313. LptPortName,
  1314. &ControlData,
  1315. 0,
  1316. NULL
  1317. );
  1318. if (PreviousEntry) {
  1319. PreviousEntry->Sibling = CurrentEntry;
  1320. }
  1321. PreviousEntry = CurrentEntry;
  1322. }
  1323. }
  1324. return(FirstLptPort);
  1325. }
  1326. #endif //_GAMBIT_