mirror of https://github.com/tongzx/nt5src
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
1649 lines
46 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
comport.c
|
|
|
|
Abstract:
|
|
|
|
This module contains C code to determine comport and LPT configuration in
|
|
syste.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) Dec-23-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "hwdetect.h"
|
|
#include "comlpt.h"
|
|
#include "bios.h"
|
|
#include "string.h"
|
|
|
|
#define LOWEST_IRQ 3
|
|
#define MASTER_IRQ_MASK_BITS 0xf8
|
|
#define SLAVE_IRQ_MASK_BITS 0xfe
|
|
|
|
//
|
|
// ComPortAddress[] is a global array to remember which comports have
|
|
// been detected and their I/O port addresses.
|
|
//
|
|
|
|
#if defined(NEC_98)
|
|
|
|
#define NEC_MAX_COM_PORTS 15
|
|
#define NEC_MAX_IO_PATTERN 38
|
|
#define FIFO_INT_ID_PRS1 0x40
|
|
#define FIFO_INT_ID_PRS 0x60
|
|
|
|
#define COUNTRY_JAPAN 81
|
|
#define NEC1500 0x1500 // Old mode
|
|
#define NEC1501 0x1501 // SuperIO
|
|
#define NEC1502 0x1502 // SuperIO2
|
|
#define NEC1503 0x1503 // 2ndCCU 16550 Controller
|
|
#define NEC8071 0x8071 // Extended Board of 1stCCU Compatibility Controller
|
|
#define NEC0C01 0x0C01 // Extended Board of 16550 Compatibility Controller
|
|
//
|
|
// PC-9801-94 ports
|
|
//
|
|
#define TOKI_CONTROL 0x549
|
|
|
|
#define READ_DIVISOR_LATCH( PDesiredDivisor ) \
|
|
do \
|
|
{ \
|
|
PUCHAR Address; \
|
|
PSHORT PDivisor = PDesiredDivisor; \
|
|
UCHAR LineControl; \
|
|
UCHAR Lsb; \
|
|
UCHAR Msb; \
|
|
LineControl = READ_PORT_UCHAR( (PUCHAR)0x23b ); \
|
|
WRITE_PORT_UCHAR((PUCHAR)0x23b,(UCHAR)0x80 ); \
|
|
Lsb = READ_PORT_UCHAR( (PUCHAR)0x238 ); \
|
|
Msb = READ_PORT_UCHAR( (PUCHAR)0x239 ); \
|
|
*PDivisor = Lsb; \
|
|
*PDivisor = *PDivisor | (((USHORT)Msb) << 8); \
|
|
WRITE_PORT_UCHAR((PUCHAR)0x23b,(UCHAR)0x0 ); \
|
|
} while (0)
|
|
|
|
#define WRITE_DIVISOR_LATCH(BaseAddress,DesiredDivisor) \
|
|
do \
|
|
{ \
|
|
PUCHAR Address = BaseAddress; \
|
|
SHORT Divisor = DesiredDivisor; \
|
|
UCHAR LineControl; \
|
|
LineControl = READ_PORT_UCHAR(Address+LINE_CONTROL_REGISTER); \
|
|
WRITE_PORT_UCHAR( \
|
|
Address+LINE_CONTROL_REGISTER, \
|
|
(UCHAR)(LineControl | SERIAL_LCR_DLAB) \
|
|
); \
|
|
WRITE_PORT_UCHAR( \
|
|
Address+DIVISOR_LATCH_LSB, \
|
|
(UCHAR)(Divisor & 0xff) \
|
|
); \
|
|
WRITE_PORT_UCHAR( \
|
|
Address+DIVISOR_LATCH_MSB, \
|
|
(UCHAR)((Divisor & 0xff00) >> 8) \
|
|
); \
|
|
WRITE_PORT_UCHAR( \
|
|
Address+LINE_CONTROL_REGISTER, \
|
|
LineControl \
|
|
); \
|
|
} while (0)
|
|
|
|
#define NextComPortNumber(ComportName, PortNumber) \
|
|
do \
|
|
{ \
|
|
if (PortNumber < 9){ \
|
|
ComportName[3] = PortNumber + (UCHAR)'1'; \
|
|
ComportName[4] = '\0'; \
|
|
}else{ \
|
|
ComportName[3] = (UCHAR)'1'; \
|
|
ComportName[4] = (PortNumber - 10) + (UCHAR)'1'; \
|
|
ComportName[5] = '\0'; \
|
|
} \
|
|
++PortNumber; \
|
|
}while(0) \
|
|
|
|
USHORT ComPortAddress[NEC_MAX_COM_PORTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
#else // NEC_98
|
|
USHORT ComPortAddress[MAX_COM_PORTS] = {0, 0, 0, 0};
|
|
#endif // NEC_98
|
|
|
|
#if defined(NEC_98)
|
|
VOID
|
|
NEC2ndCCUInitialize (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
We have to initialize 2ndCCU(NS16550A) after system reset.
|
|
Because the initial value of this chip is instability.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
_asm { cli }
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0411,(UCHAR)0x91 );
|
|
IoDelay(1);
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x01 );
|
|
IoDelay(1);
|
|
|
|
//
|
|
// set baudrate.
|
|
//
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x023B,(UCHAR)0x80 );
|
|
IoDelay(1);
|
|
WRITE_DIVISOR_LATCH( (PUCHAR)0x0238,(SHORT)0x0060 );
|
|
IoDelay(1);
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x023B,(UCHAR)0x00 );
|
|
IoDelay(1);
|
|
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x08 );
|
|
|
|
//
|
|
// wait 5 micro sec
|
|
//
|
|
IoDelay(5);
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0413,(UCHAR)0x01 );
|
|
IoDelay(1);
|
|
_asm { sti }
|
|
|
|
//
|
|
// initialize - END
|
|
//
|
|
}
|
|
|
|
BOOLEAN
|
|
FifoPresenceCheck (
|
|
PUCHAR PortAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reports whether the resource have FIFO faculty.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Will return true if the resource have, otherwise it
|
|
will return false.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN FifoStatus = TRUE;
|
|
USHORT cnt;
|
|
UCHAR tmp;
|
|
|
|
WRITE_PORT_UCHAR( (PUCHAR)(PortAddress - 0x1) , (UCHAR)(0x03) );
|
|
|
|
IoDelay(10);
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
|
|
IoDelay(10);
|
|
if ((tmp & FIFO_INT_ID_PRS1) == 0) {
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
|
|
IoDelay(10);
|
|
}
|
|
|
|
for (cnt = 0;cnt < 2;cnt++){
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
|
|
IoDelay(10);
|
|
if ((tmp & FIFO_INT_ID_PRS) != 0){
|
|
FifoStatus = FALSE;
|
|
break;
|
|
}
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)PortAddress );
|
|
IoDelay(10);
|
|
if ((tmp & FIFO_INT_ID_PRS) != 0x40){
|
|
FifoStatus = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(FifoStatus);
|
|
}
|
|
|
|
BOOLEAN
|
|
DoesPortExistNEC101(
|
|
SHORT PortNumber,
|
|
PUSHORT InterruptNumber,
|
|
PUSHORT PortLength
|
|
)
|
|
{
|
|
BOOLEAN PortExist = FALSE;
|
|
USHORT Port = PortNumber;
|
|
USHORT NEC_y = 0;
|
|
USHORT IsCommonInterrupt;
|
|
USHORT temp1,temp2;
|
|
USHORT Ch_2_IRQ_Tbl[4] = {3,5,6,9};
|
|
USHORT Ch_3_IRQ_Tbl[4] = {3,10,12,13};
|
|
USHORT COMMON_IRQ_Tbl[7] = {3,5,6,9,10,12,13};
|
|
|
|
NEC_y = ( ( Port ) & (0x0f00) );
|
|
|
|
switch (Port & 0x00ff) {
|
|
case 0x00b0:
|
|
if ( READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b3)) != 0xff ) {
|
|
PortExist = TRUE;
|
|
}
|
|
break;
|
|
case 0x00b2:
|
|
if ( READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00bb)) != 0xff ) {
|
|
PortExist = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This check is necessary to know detecting PC-9861K is not support.
|
|
//
|
|
if (( PortExist == TRUE ) &&
|
|
( FifoPresenceCheck((PUCHAR)(Port | 0x0005)) == FALSE)){
|
|
PortExist = FALSE;
|
|
}
|
|
|
|
if (PortExist == TRUE){
|
|
IsCommonInterrupt = ( (0x04) & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b8))) );
|
|
IoDelay(10);
|
|
|
|
if( IsCommonInterrupt ){
|
|
temp1 = ( (0x03) & ( READ_PORT_UCHAR((PUCHAR)(NEC_y | Port))) );
|
|
IoDelay(10);
|
|
if( ( Port & (0x00ff) ) == 0x00b0 ){
|
|
*InterruptNumber = Ch_2_IRQ_Tbl[temp1];
|
|
}else{
|
|
*InterruptNumber = Ch_3_IRQ_Tbl[temp1];
|
|
}
|
|
}else{
|
|
temp1 = ( 0x01 & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b0))) );
|
|
IoDelay(10);
|
|
temp2 = ( 0x03 & (READ_PORT_UCHAR((PUCHAR)(NEC_y | 0x00b2))) );
|
|
IoDelay(10);
|
|
*InterruptNumber = COMMON_IRQ_Tbl[(((temp1 << 2) | temp2) & 0x07)];
|
|
}
|
|
|
|
*PortLength = 1;
|
|
}
|
|
|
|
return(PortExist);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
DoesPortExistNECFaxModem(
|
|
SHORT PortNumber,
|
|
PUSHORT InterruptNumber,
|
|
PUSHORT PortLength
|
|
)
|
|
{
|
|
BOOLEAN PortExist = FALSE;
|
|
USHORT Port = PortNumber;
|
|
USHORT temp;
|
|
|
|
|
|
temp = READ_PORT_UCHAR( (PUCHAR)(Port | 0x000f) );
|
|
|
|
if ((temp & 0x0f0) == 0) {
|
|
|
|
switch ( temp & 0x0f ) {
|
|
case 0x01:
|
|
*InterruptNumber = 3;
|
|
break;
|
|
case 0x02:
|
|
*InterruptNumber = 5;
|
|
break;
|
|
case 0x04:
|
|
*InterruptNumber = 6;
|
|
break;
|
|
case 0x08:
|
|
*InterruptNumber = 12;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (*InterruptNumber != 0) {
|
|
PortExist = TRUE;
|
|
}
|
|
*PortLength = 8;
|
|
}
|
|
|
|
return(PortExist);
|
|
|
|
}
|
|
#endif // NEC_98
|
|
|
|
#if !defined(_GAMBIT_)
|
|
VOID
|
|
SerialInterruptRequest (
|
|
PUCHAR PortAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine generates an interrupt on the interrupt line for
|
|
com port.
|
|
|
|
Arguments:
|
|
|
|
PortAddress - the port address of the desired com port.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
|
|
{
|
|
|
|
USHORT i;
|
|
UCHAR Temp;
|
|
|
|
WRITE_PORT_UCHAR(
|
|
PortAddress + MODEM_CONTROL_REGISTER,
|
|
8
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
PortAddress + INTERRUPT_ENABLE_REGISTER,
|
|
0
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
PortAddress + INTERRUPT_ENABLE_REGISTER,
|
|
0xf
|
|
);
|
|
|
|
//
|
|
// Add some delay
|
|
//
|
|
|
|
for (i = 0; i < 5 ; i++ ) {
|
|
Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
|
|
Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
|
|
}
|
|
}
|
|
VOID
|
|
SerialInterruptDismiss (
|
|
PUCHAR PortAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine dismisses an interrupt on the interrupt line for
|
|
com port.
|
|
|
|
Arguments:
|
|
|
|
PortAddress - the port address of the desired com port.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
|
|
{
|
|
USHORT i;
|
|
UCHAR Temp;
|
|
|
|
Temp = READ_PORT_UCHAR(
|
|
PortAddress + INTERRUPT_IDENT_REGISTER
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
PortAddress + INTERRUPT_ENABLE_REGISTER,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Add some delay
|
|
//
|
|
|
|
for (i = 0; i < 5 ; i++ ) {
|
|
Temp = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
|
|
Temp = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
DoesPortExist(
|
|
IN PUCHAR Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine examines several of what might be the serial device
|
|
registers. It ensures that the bits that should be zero are zero.
|
|
It will then attempt to set the device to 19200 baud. If the
|
|
will then attempt to read that baud. If it is still 19200 then
|
|
we can feel pretty safe that this is a serial device.
|
|
|
|
NOTE: If there is indeed a serial port at the address specified
|
|
it will absolutely have interrupts inhibited upon return
|
|
from this routine.
|
|
|
|
Arguments:
|
|
|
|
Address - address of hw port.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Port exists. Party on.
|
|
|
|
FALSE - Port doesn't exist. Don't use it.
|
|
|
|
History:
|
|
7/23/97 a-paulbr fixed bug 95050. Init LineControl to 0x00
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UCHAR IerContents;
|
|
UCHAR BaudRateMsb, BaudRateLsb;
|
|
BOOLEAN ReturnValue = FALSE;
|
|
UCHAR LineControl = 0x00;
|
|
UCHAR LineControl_Save;
|
|
UCHAR Temp;
|
|
|
|
//
|
|
// Save the original LCR, so we can restore it later
|
|
// We won't use it, because the port could be handing us
|
|
// a bad initial value. We will use 0x00 instead.
|
|
//
|
|
|
|
LineControl_Save = READ_PORT_UCHAR(Address+LINE_CONTROL_REGISTER);
|
|
|
|
//
|
|
// Read original baud rate divisor and save it.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl | SERIAL_LCR_DLAB)
|
|
);
|
|
BaudRateMsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
|
|
BaudRateLsb = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
|
|
|
|
//
|
|
// Change baud rate to 9600.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BAUD_RATE_9600_MSB);
|
|
WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BAUD_RATE_9600_LSB);
|
|
|
|
//
|
|
// Read IER and save it away.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
|
|
);
|
|
IerContents = READ_PORT_UCHAR(
|
|
Address + INTERRUPT_ENABLE_REGISTER
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address + INTERRUPT_ENABLE_REGISTER,
|
|
IER_TEST_VALUE
|
|
);
|
|
|
|
//
|
|
// Read baud rate divisor. The values we read should be equal to the
|
|
// values we set earlier.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl | SERIAL_LCR_DLAB)
|
|
);
|
|
Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_MSB);
|
|
if (Temp != BAUD_RATE_9600_MSB) {
|
|
goto AllDone;
|
|
}
|
|
Temp = READ_PORT_UCHAR(Address+DIVISOR_LATCH_LSB);
|
|
if (Temp != BAUD_RATE_9600_LSB) {
|
|
goto AllDone;
|
|
}
|
|
|
|
//
|
|
// Read IER and it should be equal to the value we set earlier.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
|
|
);
|
|
Temp = READ_PORT_UCHAR(
|
|
Address + INTERRUPT_ENABLE_REGISTER
|
|
);
|
|
if (Temp != IER_TEST_VALUE) {
|
|
goto AllDone;
|
|
}
|
|
ReturnValue = TRUE;
|
|
|
|
AllDone:
|
|
|
|
//
|
|
// Restore registers which we destroyed .
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl & ~SERIAL_LCR_DLAB)
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address + INTERRUPT_ENABLE_REGISTER,
|
|
IerContents
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
(UCHAR)(LineControl | SERIAL_LCR_DLAB)
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_MSB, BaudRateMsb);
|
|
WRITE_PORT_UCHAR(Address+DIVISOR_LATCH_LSB, BaudRateLsb);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
Address+LINE_CONTROL_REGISTER,
|
|
LineControl_Save
|
|
);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOLEAN
|
|
HwInterruptDetection(
|
|
IN PUCHAR BasePort,
|
|
IN VOID (*InterruptRequestRoutine)(),
|
|
IN VOID (*InterruptDismissRoutine)(),
|
|
OUT PUSHORT Vector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to locate the interrupt vector for which
|
|
the device is configured. The allowable vectors are
|
|
3 - 7, and 9 - 15. If no interrupt vector is found, or more than
|
|
one is found, the routine returns FALSE. Otherwise, TRUE is returned.
|
|
|
|
Note that we diddle the i8259 interrupt controllers here.
|
|
|
|
Arguments:
|
|
|
|
BasePort - the I/O port base for the device.
|
|
|
|
InterruptRequestRoutine - A pointer to a routine to generate
|
|
desired interrupt.
|
|
|
|
InterruptDismissRoutine - A pointer to a routine to dismiss the interrupt
|
|
generated by InterruptRequestRoutine.
|
|
|
|
Vector - Pointer to the location to store the mouse interrupt vector.
|
|
|
|
Return Value:
|
|
|
|
Returns TRUE if the Inport interrupt vector was located; otherwise,
|
|
FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR OldMasterMask, OldSlaveMask;
|
|
UCHAR MasterMask, SlaveMask;
|
|
UCHAR InterruptBits;
|
|
UCHAR PossibleInterruptBits;
|
|
int i;
|
|
int NumberOfIRQs;
|
|
BOOLEAN VectorFound = FALSE;
|
|
|
|
//
|
|
// Get the i8259 interrupt masks.
|
|
//
|
|
|
|
OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
|
|
OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
|
|
|
|
//
|
|
// Raise IRQL to the highest priority IRQL the inport would use.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
(PUCHAR) PIC1_PORT1,
|
|
(UCHAR) 0xff ^ ((UCHAR)(1 << LOWEST_IRQ) - 1)
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
(PUCHAR) PIC2_PORT1,
|
|
(UCHAR) 0xfe
|
|
);
|
|
|
|
//
|
|
// Get the master i8259 interrupt mask.
|
|
//
|
|
|
|
MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
|
|
|
|
//
|
|
// Disable potential device interrupts.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
(PUCHAR) PIC1_PORT1,
|
|
(UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
|
|
);
|
|
|
|
//
|
|
// Attempt to locate the interrupt line on the master i8259.
|
|
// Why try this 10 times? It's magic...
|
|
//
|
|
|
|
PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
|
|
for (i = 0; i < 10; i++) {
|
|
|
|
|
|
//
|
|
// Generate a 0 on the master 8259 interrupt line
|
|
//
|
|
|
|
(*InterruptDismissRoutine)(BasePort);
|
|
|
|
//
|
|
// Read the interrupt bits off the master i8259. Only bits
|
|
// 3 - 7 are of interest. Eliminate non-functional
|
|
// IRQs. Only continue looking at the master i8259 if there
|
|
// is at least one functional IRQ.
|
|
//
|
|
|
|
_asm {cli}
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
|
|
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
|
|
_asm {sti}
|
|
InterruptBits &= MASTER_IRQ_MASK_BITS;
|
|
InterruptBits ^= MASTER_IRQ_MASK_BITS;
|
|
PossibleInterruptBits &= InterruptBits;
|
|
if (!PossibleInterruptBits) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Generate an interrupt from the desired device.
|
|
//
|
|
|
|
(*InterruptRequestRoutine)(BasePort);
|
|
|
|
//
|
|
// Read the interrupt bits off the master i8259. Only bits
|
|
// 3 - 7 are of interest. Eliminate non-functional
|
|
// IRQs. Only continue looking at the master i8259 if there
|
|
// is at least one functional IRQ.
|
|
//
|
|
|
|
_asm {cli}
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
|
|
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
|
|
_asm {sti}
|
|
InterruptBits &= MASTER_IRQ_MASK_BITS;
|
|
PossibleInterruptBits &= InterruptBits;
|
|
|
|
if (!PossibleInterruptBits) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (PossibleInterruptBits) {
|
|
|
|
//
|
|
// We found at least one IRQ on the master i8259 that could belong
|
|
// to the Inport mouse. Count how many we found. If there is
|
|
// more than one, we haven't found the vector. Otherwise, we've
|
|
// successfully located the Inport interrupt vector on the master
|
|
// i8259 (provided the interrupt vector is 3, 4, 5, or 7).
|
|
//
|
|
|
|
PossibleInterruptBits >>= 3;
|
|
NumberOfIRQs = 0;
|
|
for (i = 3; i <= 7; i++) {
|
|
if (PossibleInterruptBits & 1) {
|
|
NumberOfIRQs += 1;
|
|
*Vector = (CCHAR) i;
|
|
}
|
|
PossibleInterruptBits >>= 1;
|
|
}
|
|
if (NumberOfIRQs == 1) {
|
|
VectorFound = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't locate the interrupt vector on the master i8259, attempt
|
|
// to locate it on the slave i8259.
|
|
//
|
|
|
|
if (!VectorFound) {
|
|
|
|
//
|
|
// Get the slave i8259 interrupt mask.
|
|
//
|
|
|
|
SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
|
|
|
|
//
|
|
// Attempt to locate the interupt line on the slave i8259.
|
|
// Why try this 20 times? It's magic...
|
|
//
|
|
|
|
PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
|
|
for (i = 0; i < 20; i++) {
|
|
|
|
//
|
|
// Generate a 0 on the Inport IRQ on the slave i8259.
|
|
//
|
|
|
|
(*InterruptDismissRoutine)(BasePort);
|
|
|
|
//
|
|
// Read the interrupt bits off the slave i8259.
|
|
// Eliminate non-functional IRQs. Only continue
|
|
// looking at the slave i8259 if there is at least one
|
|
// functional IRQ.
|
|
//
|
|
|
|
_asm {cli}
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
|
|
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
|
|
_asm {sti}
|
|
InterruptBits &= SLAVE_IRQ_MASK_BITS;
|
|
InterruptBits ^= SLAVE_IRQ_MASK_BITS;
|
|
PossibleInterruptBits &= InterruptBits;
|
|
if (!PossibleInterruptBits) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Generate a 1 on the Inport IRQ on the slave i8259.
|
|
//
|
|
|
|
(*InterruptRequestRoutine)(BasePort);
|
|
|
|
//
|
|
// Read the interrupt bits off the slave i8259.
|
|
// Eliminate non-functional IRQs. Only continue
|
|
// looking at the slave i8259 if there is at least one
|
|
// functional IRQ.
|
|
//
|
|
|
|
_asm {cli}
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
|
|
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
|
|
_asm {sti}
|
|
InterruptBits &= SLAVE_IRQ_MASK_BITS;
|
|
PossibleInterruptBits &= InterruptBits;
|
|
|
|
if (!PossibleInterruptBits) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (PossibleInterruptBits) {
|
|
|
|
//
|
|
// We found at least one IRQ on the slave i8259 that could belong
|
|
// to the device. Count how many we found. If there is
|
|
// more than one, we haven't found the vector. Otherwise, we've
|
|
// successfully located the device interrupt vector on the slave
|
|
// i8259.
|
|
//
|
|
|
|
PossibleInterruptBits >>= 1;
|
|
NumberOfIRQs = 0;
|
|
for (i = 9; i <= 15; i++) {
|
|
if (PossibleInterruptBits & 1) {
|
|
NumberOfIRQs += 1;
|
|
*Vector = (CCHAR) i;
|
|
}
|
|
PossibleInterruptBits >>= 1;
|
|
}
|
|
if (NumberOfIRQs == 1) {
|
|
VectorFound = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore the i8259 slave.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
|
|
|
|
//
|
|
// Restore the i8259 slave interrupt mask.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
|
|
}
|
|
|
|
//
|
|
// Dismiss interrupt on the device
|
|
//
|
|
|
|
(*InterruptDismissRoutine)(BasePort);
|
|
|
|
//
|
|
// Restore the i8259 master.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
|
|
|
|
//
|
|
// Restore the i8259 master interrupt mask.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
|
|
|
|
//
|
|
// Restore the previous IRQL.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR(
|
|
(PUCHAR) PIC1_PORT1,
|
|
OldMasterMask
|
|
);
|
|
|
|
WRITE_PORT_UCHAR(
|
|
(PUCHAR) PIC2_PORT1,
|
|
OldSlaveMask
|
|
);
|
|
|
|
return(VectorFound);
|
|
}
|
|
#endif // _GAMBIT_
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA
|
|
GetComportInformation (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to detect the comports information
|
|
for the system. The information includes port address, irq
|
|
level.
|
|
|
|
Note that this routine can only detect up to 4 comports and
|
|
it assumes that if MCA, COM3 and COM4 use irq 4. Otherwise,
|
|
COM3 uses irq 4 and COM4 uses irq 3. Also, the number of ports
|
|
for COMPORT is set to 8 (for example, COM2 uses ports 2F8 - 2FF)
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A pointer to a stucture of type FWCONFIGURATION_COMPONENT_DATA
|
|
which is the root of comport component list.
|
|
If no comport exists, a value of NULL is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if defined(NEC_98)
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
|
|
FPFWCONFIGURATION_COMPONENT_DATA FirstComport = NULL;
|
|
FPFWCONFIGURATION_COMPONENT Component;
|
|
HWCONTROLLER_DATA ControlData;
|
|
UCHAR i, j, z;
|
|
SHORT Port;
|
|
UCHAR ComportName[] = "COM??";
|
|
CM_SERIAL_DEVICE_DATA SerialData;
|
|
ULONG BaudClock = 1843200;
|
|
USHORT Vector;
|
|
BOOLEAN PortExist;
|
|
USHORT IoPorts[NEC_MAX_IO_PATTERN] = {0x030, 0x238,
|
|
0x00b0, 0x00b2, 0x01b0, 0x01b2, 0x02b0, 0x02b2,
|
|
0x03b0, 0x03b2, 0x04b0, 0x04b2, 0x05b0, 0x05b2,
|
|
0x06b0, 0x06b2, 0x07b0, 0x07b2, 0x08b0, 0x08b2,
|
|
0x09b0, 0x09b2, 0x0ab0, 0x0ab2, 0x0bb0, 0x0bb2,
|
|
0x0cb0, 0x0cb2, 0x0db0, 0x0db2, 0x0eb0, 0x0eb2,
|
|
0x0fb0, 0x0fb2,
|
|
0x8b0, 0x9b0, 0xab0, 0xbb0};
|
|
USHORT PortLength;
|
|
USHORT InterruptNumber;
|
|
USHORT NEC_COM_number = 0;
|
|
|
|
//
|
|
// Check BIOS ROM data is right or not.
|
|
// if not, we don't detect CCU.
|
|
//
|
|
if ( (COM_ID_L != 0x98) || (COM_ID_H != 0x21) ){
|
|
return(FirstComport);
|
|
}
|
|
|
|
//
|
|
// Initialize serial device specific data
|
|
//
|
|
|
|
SerialData.Version = COUNTRY_JAPAN;
|
|
SerialData.Revision = NEC1500;
|
|
SerialData.BaudClock = 153600;
|
|
|
|
for (i = 0; i < NEC_MAX_IO_PATTERN; i++) {
|
|
|
|
PortExist = FALSE;
|
|
|
|
//
|
|
// Initialize Controller data
|
|
//
|
|
|
|
ControlData.NumberPortEntries = 0;
|
|
ControlData.NumberIrqEntries = 0;
|
|
ControlData.NumberMemoryEntries = 0;
|
|
ControlData.NumberDmaEntries = 0;
|
|
z = 0;
|
|
|
|
//
|
|
// Load the port address from the BIOS data area, if it exists
|
|
//
|
|
|
|
Port = IoPorts[i];
|
|
InterruptNumber = 0;
|
|
|
|
switch(i){
|
|
case 0:
|
|
//
|
|
// internal 1st CCU
|
|
//
|
|
if ( (ROM_FLAG7 & LOCKED_CCU1) == 0 ) {
|
|
PortExist = TRUE;
|
|
InterruptNumber = 4;
|
|
PortLength = 1;
|
|
SerialData.Revision = NEC1501;
|
|
if (ROM_FLAG5 & 0x10) {
|
|
SerialData.Revision = NEC1502;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// internal 2nd CCU
|
|
//
|
|
if ( (ROM_FLAG5 & 0x08) && ((ROM_FLAG7 & LOCKED_CCU2) == 0) ) {
|
|
PortExist = DoesPortExist( (PUCHAR)Port );
|
|
InterruptNumber = 5;
|
|
PortLength = 7;
|
|
SerialData.Revision = NEC1503;
|
|
SerialData.BaudClock = 1843200;
|
|
}
|
|
break;
|
|
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
//
|
|
// external FAX/Modem board
|
|
//
|
|
PortExist = DoesPortExistNECFaxModem(Port,&InterruptNumber,&PortLength);
|
|
SerialData.Revision = NEC0C01;
|
|
SerialData.BaudClock = 1843200;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// PC-9801-101 borad
|
|
//
|
|
PortExist = DoesPortExistNEC101(Port,&InterruptNumber,&PortLength);
|
|
SerialData.Revision = NEC8071;
|
|
SerialData.BaudClock = 153600;
|
|
break;
|
|
}
|
|
|
|
if (PortExist) {
|
|
|
|
//
|
|
// Remember the port address in our global variable
|
|
// such that other detection code (e.g. Serial Mouse) can
|
|
// get the information.
|
|
//
|
|
|
|
ComPortAddress[NEC_COM_number] = Port;
|
|
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
if (!FirstComport) {
|
|
FirstComport = CurrentEntry;
|
|
}
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
|
|
Component->Class = ControllerClass;
|
|
Component->Type = SerialController;
|
|
Component->Flags.ConsoleOut = 1;
|
|
Component->Flags.ConsoleIn = 1;
|
|
Component->Flags.Output = 1;
|
|
Component->Flags.Input = 1;
|
|
Component->Version = 0;
|
|
Component->Key = NEC_COM_number;
|
|
Component->AffinityMask = 0xffffffff;
|
|
|
|
//
|
|
// Set up type string.
|
|
//
|
|
|
|
NextComPortNumber(ComportName, NEC_COM_number);
|
|
// ComportName[3] = NEC_COM_number + (UCHAR)'1';
|
|
// NEC_COM_number++;
|
|
|
|
//
|
|
// Set up Port information
|
|
//
|
|
|
|
ControlData.NumberPortEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareDeviceExclusive;
|
|
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
|
|
ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)Port;
|
|
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
|
|
ControlData.DescriptorList[z].u.Port.Length = PortLength;
|
|
z++;
|
|
|
|
//
|
|
// Set up Irq information
|
|
//
|
|
|
|
ControlData.NumberIrqEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareUndetermined;
|
|
ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = InterruptNumber;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = InterruptNumber;
|
|
|
|
ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
|
|
|
|
|
|
CurrentEntry->ConfigurationData =
|
|
HwSetUpResourceDescriptor(Component,
|
|
ComportName,
|
|
&ControlData,
|
|
sizeof(SerialData),
|
|
(PUCHAR)&SerialData
|
|
);
|
|
if (PreviousEntry) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
|
|
if (Port == 0x238){
|
|
NEC2ndCCUInitialize ();
|
|
}
|
|
}
|
|
}
|
|
return(FirstComport);
|
|
#else // NEC_98
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
|
|
FPFWCONFIGURATION_COMPONENT_DATA FirstComport = NULL;
|
|
FPFWCONFIGURATION_COMPONENT Component;
|
|
HWCONTROLLER_DATA ControlData;
|
|
UCHAR i, j, z;
|
|
SHORT Port;
|
|
UCHAR ComportName[] = "COM?";
|
|
CM_SERIAL_DEVICE_DATA SerialData;
|
|
ULONG BaudClock = 1843200;
|
|
USHORT Vector;
|
|
BOOLEAN PortExist;
|
|
USHORT IoPorts[MAX_COM_PORTS] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
|
|
|
|
|
|
#if !defined(_GAMBIT_)
|
|
//
|
|
// BIOS DATA area 40:0 is the port address of the first valid COM port
|
|
//
|
|
|
|
USHORT far *pPortAddress = (USHORT far *)0x00400000;
|
|
#endif
|
|
|
|
//
|
|
// Initialize serial device specific data
|
|
//
|
|
|
|
SerialData.Version = 0;
|
|
SerialData.Revision = 0;
|
|
SerialData.BaudClock = 1843200;
|
|
|
|
#if !defined(_GAMBIT_)
|
|
//
|
|
// Initialize default COM port address.
|
|
// Some BIOS puts incorrect comport address to the 40:0 area.
|
|
// To cope with this problem, we test the port address supplied
|
|
// by BIOS first. If it fail, we try our default port.
|
|
//
|
|
|
|
for (i = 0; i < MAX_COM_PORTS; i++) {
|
|
for (j = 0; j < MAX_COM_PORTS; j++) {
|
|
if (IoPorts[i] == *(pPortAddress + j)) {
|
|
IoPorts[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(_GAMBIT_)
|
|
for (i = 0; i < 1; i++) {
|
|
#else
|
|
for (i = 0; i < MAX_COM_PORTS; i++) {
|
|
#endif
|
|
|
|
PortExist = FALSE;
|
|
|
|
//
|
|
// Initialize Controller data
|
|
//
|
|
|
|
ControlData.NumberPortEntries = 0;
|
|
ControlData.NumberIrqEntries = 0;
|
|
ControlData.NumberMemoryEntries = 0;
|
|
ControlData.NumberDmaEntries = 0;
|
|
z = 0;
|
|
|
|
#if _GAMBIT_
|
|
Port = IoPorts[i];
|
|
PortExist = TRUE;
|
|
#else
|
|
//
|
|
// Load the port address from the BIOS data area, if it exists
|
|
//
|
|
|
|
Port = *(pPortAddress + i);
|
|
|
|
//
|
|
// Determine if the port exists
|
|
//
|
|
|
|
if (Port != 0) {
|
|
if (DoesPortExist((PUCHAR)Port)) {
|
|
PortExist = TRUE;
|
|
}
|
|
}
|
|
if (!PortExist && (Port = IoPorts[i])) {
|
|
if (PortExist = DoesPortExist((PUCHAR)Port)) {
|
|
IoPorts[i] = 0;
|
|
*(pPortAddress+i) = (USHORT)Port;
|
|
}
|
|
}
|
|
#endif //_GAMBIT_
|
|
if (PortExist) {
|
|
|
|
//
|
|
// Remember the port address in our global variable
|
|
// such that other detection code (e.g. Serial Mouse) can
|
|
// get the information.
|
|
//
|
|
|
|
ComPortAddress[i] = Port;
|
|
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
if (!FirstComport) {
|
|
FirstComport = CurrentEntry;
|
|
}
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
|
|
Component->Class = ControllerClass;
|
|
Component->Type = SerialController;
|
|
Component->Flags.ConsoleOut = 1;
|
|
Component->Flags.ConsoleIn = 1;
|
|
Component->Flags.Output = 1;
|
|
Component->Flags.Input = 1;
|
|
Component->Version = 0;
|
|
Component->Key = i;
|
|
Component->AffinityMask = 0xffffffff;
|
|
|
|
//
|
|
// Set up type string.
|
|
//
|
|
|
|
ComportName[3] = i + (UCHAR)'1';
|
|
|
|
//
|
|
// Set up Port information
|
|
//
|
|
|
|
ControlData.NumberPortEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareDeviceExclusive;
|
|
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
|
|
ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)Port;
|
|
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
|
|
ControlData.DescriptorList[z].u.Port.Length = 7;
|
|
z++;
|
|
|
|
//
|
|
// Set up Irq information
|
|
//
|
|
|
|
ControlData.NumberIrqEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareUndetermined;
|
|
if (HwBusType == MACHINE_TYPE_MCA) {
|
|
ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
|
|
if (i == 0) { // COM1 - irql4; COM2 - COM3 - irq3
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 4;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
|
|
} else {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 3;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// For EISA the LevelTriggered is temporarily set to FALSE.
|
|
// COM1 and COM3 use irq 4; COM2 and COM4 use irq3
|
|
//
|
|
|
|
ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
|
|
if (Port == 0x3f8 || Port == 0x3e8) {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 4;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
|
|
} else if (Port == 0x2f8 || Port == 0x2e8) {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 3;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
|
|
} else if (i == 0 || i == 2) {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 4;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 4;
|
|
} else {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 3;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 3;
|
|
}
|
|
}
|
|
|
|
ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
|
|
|
|
//
|
|
// Try to determine the interrupt vector. If we success, the
|
|
// new vector will be used to replace the default value.
|
|
//
|
|
|
|
#if !defined(_GAMBIT_)
|
|
if (HwInterruptDetection((PUCHAR)Port,
|
|
SerialInterruptRequest,
|
|
SerialInterruptDismiss,
|
|
&Vector)) {
|
|
|
|
ControlData.DescriptorList[z].u.Interrupt.Level =
|
|
(ULONG)Vector;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector =
|
|
(ULONG)Vector;
|
|
}
|
|
|
|
//
|
|
// Since the com port interrupt detection destryed some
|
|
// of the com port registers, here we do the clean up.
|
|
//
|
|
|
|
WRITE_PORT_UCHAR ((PUCHAR)(Port + INTERRUPT_ENABLE_REGISTER), 0);
|
|
WRITE_PORT_UCHAR ((PUCHAR)(Port + MODEM_CONTROL_REGISTER), 0);
|
|
#endif //_GAMBIT_
|
|
|
|
CurrentEntry->ConfigurationData =
|
|
HwSetUpResourceDescriptor(Component,
|
|
ComportName,
|
|
&ControlData,
|
|
sizeof(SerialData),
|
|
(PUCHAR)&SerialData
|
|
);
|
|
if (PreviousEntry) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
}
|
|
}
|
|
return(FirstComport);
|
|
#endif // NEC_98
|
|
}
|
|
|
|
#if !defined(_GAMBIT_)
|
|
FPFWCONFIGURATION_COMPONENT_DATA
|
|
GetLptInformation (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will attempt to detect the parallel printer port
|
|
information for the system. The information includes port address,
|
|
irq level.
|
|
|
|
Note if this code is run after user established NETWORK LPT
|
|
connection. The Network LPT will be counted as regular parallel
|
|
port.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A pointer to a stucture of type PONENT_DATA
|
|
which is the root of Parallel component list.
|
|
If no comport exists, a value of NULL is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
|
|
FPFWCONFIGURATION_COMPONENT_DATA FirstLptPort = NULL;
|
|
FPFWCONFIGURATION_COMPONENT Component;
|
|
HWCONTROLLER_DATA ControlData;
|
|
UCHAR LptPortName[] = "PARALLEL?";
|
|
USHORT i, z;
|
|
USHORT LptStatus;
|
|
ULONG Port;
|
|
|
|
#if defined(NEC_98)
|
|
ULONG Portnec;
|
|
int lptportnumnec;
|
|
UCHAR level;
|
|
UCHAR j = 0;
|
|
UCHAR tmp;
|
|
USHORT PortAddress[MAX_LPT_PORTS] = { 0, 0, 0 };
|
|
USHORT far *pPortAddress = &PortAddress;
|
|
|
|
//
|
|
// check the internal LPT port is locked.
|
|
//
|
|
|
|
if ( COM_ID_L == 0x98 && COM_ID_H == 0x21 &&
|
|
ROM_FLAG7 & LOCKED_LPT ){
|
|
|
|
// The LPT was locked .
|
|
// skip the internal LPT port.
|
|
|
|
} else {
|
|
|
|
//
|
|
// try to set full centro mode
|
|
//
|
|
_asm {
|
|
push ax
|
|
mov ah, 17h
|
|
int 1Ah
|
|
mov tmp, ah
|
|
pop ax
|
|
}
|
|
|
|
if ( BIOS_FLAG5 & PRTMODE_FULL_CENTRO ){
|
|
PortAddress[0] = 0x140; // Full centro-mode
|
|
} else {
|
|
PortAddress[0] = 0x40; // Old type.
|
|
}
|
|
j++;
|
|
}
|
|
|
|
//
|
|
// check the external LPT ports.
|
|
//
|
|
// NOTE:
|
|
// There is check codes that external port is starting LPT1 or LPT2.
|
|
// at here in PC-98's old original source.
|
|
// It read 0x054F(Int Ch Read) port and check CAON (bit2).
|
|
// If the bit is clear, then the port is starting LPT1.
|
|
// I could not understand its raison d'e^tre.
|
|
//
|
|
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)TOKI_CONTROL );
|
|
if ( tmp == 0xFF ){
|
|
//
|
|
// There is no external LPT ports.
|
|
//
|
|
|
|
PortAddress[j] = 0;
|
|
PortAddress[j+1] = 0;
|
|
} else {
|
|
//
|
|
// There is a extended card (PC-9801-94).
|
|
// It has 2 LPT ports.
|
|
// Change them to Full centro mode.
|
|
//
|
|
|
|
PortAddress[j] = 0x540;
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0549, (UCHAR)0x10 );
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x054E, (UCHAR)0x00 );
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0542, (UCHAR)0x04 );
|
|
|
|
PortAddress[j+1] = 0xD40;
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0D49, (UCHAR)0x10 );
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0D4E, (UCHAR)0x00 );
|
|
WRITE_PORT_UCHAR( (PUCHAR)0x0D42, (UCHAR)0x04 );
|
|
|
|
//
|
|
// get int level
|
|
//
|
|
|
|
tmp = READ_PORT_UCHAR( (PUCHAR)0x54F );
|
|
switch( tmp & 0x3 ){
|
|
case 0x00:
|
|
level = 3; // Extended slot INT 0
|
|
break;
|
|
case 0x01:
|
|
level = 5; // Extended slot INT 1
|
|
break;
|
|
case 0x10:
|
|
level = 6; // Extended slot INT 2
|
|
break;
|
|
case 0x11:
|
|
level = 13; // Extended slot INT 6
|
|
}
|
|
}
|
|
|
|
#else // NEC_98
|
|
//
|
|
// BIOS DATA area 40:8 is the port address of the first valid COM port
|
|
//
|
|
|
|
USHORT far *pPortAddress = (USHORT far *)0x00400008;
|
|
#endif // NEC_98
|
|
|
|
for (i = 0; i < MAX_LPT_PORTS; i++) {
|
|
|
|
Port = (ULONG)*(pPortAddress + i);
|
|
if (Port == 0) {
|
|
continue;
|
|
#if defined(NEC_98)
|
|
#else
|
|
} else {
|
|
|
|
//
|
|
// If we think we have a lpt, we will initialize it to
|
|
// a known state. In order to make printing work under
|
|
// nt, the arbitration level must be disabled. The BIOS
|
|
// init function seems to do the trick.
|
|
//
|
|
|
|
_asm {
|
|
mov ah, 1
|
|
mov dx, i
|
|
int 17h
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Initialize Controller data
|
|
//
|
|
|
|
ControlData.NumberPortEntries = 0;
|
|
ControlData.NumberIrqEntries = 0;
|
|
ControlData.NumberMemoryEntries = 0;
|
|
ControlData.NumberDmaEntries = 0;
|
|
z = 0;
|
|
|
|
#if defined(NEC_98)
|
|
//
|
|
// We do not have to determine if the port exists.
|
|
// Because it was already done.
|
|
//
|
|
|
|
LptStatus = 0;
|
|
#else // NEC_98
|
|
//
|
|
// Determine if the port exists
|
|
//
|
|
|
|
LptStatus = _bios_printer(_PRINTER_STATUS, i , 0);
|
|
#endif // NEC_98
|
|
if (!(LptStatus & 6)){
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
if (!FirstLptPort) {
|
|
FirstLptPort = CurrentEntry;
|
|
}
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
|
|
Component->Class = ControllerClass;
|
|
Component->Type = ParallelController;
|
|
Component->Flags.Output = 1;
|
|
Component->Version = 0;
|
|
Component->Key = i;
|
|
Component->AffinityMask = 0xffffffff;
|
|
|
|
//
|
|
// Set up type string.
|
|
//
|
|
|
|
LptPortName[8] = (UCHAR)i + (UCHAR)'1';
|
|
|
|
//
|
|
// Set up Port information
|
|
//
|
|
|
|
Port = (ULONG)*(pPortAddress + i);
|
|
#if defined(NEC_98)
|
|
if (Port == 0x40){
|
|
ControlData.NumberPortEntries = 4;
|
|
for ( j = 0; j < ControlData.NumberPortEntries; j++ ){
|
|
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareDeviceExclusive;
|
|
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
|
|
ControlData.DescriptorList[z].u.Port.Start.LowPart = Port + (j * 2);
|
|
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
|
|
ControlData.DescriptorList[z].u.Port.Length = 1;
|
|
z++;
|
|
}
|
|
}else{
|
|
#endif // NEC_98
|
|
ControlData.NumberPortEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareDeviceExclusive;
|
|
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
|
|
ControlData.DescriptorList[z].u.Port.Start.LowPart = Port;
|
|
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
|
|
ControlData.DescriptorList[z].u.Port.Length = 3;
|
|
z++;
|
|
#if defined(NEC_98)
|
|
}
|
|
#endif // NEC_98
|
|
|
|
//
|
|
// Set up Irq information
|
|
//
|
|
|
|
ControlData.NumberIrqEntries = 1;
|
|
ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
|
|
ControlData.DescriptorList[z].ShareDisposition =
|
|
CmResourceShareUndetermined;
|
|
ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
|
|
#if defined(NEC_98)
|
|
if (i ==0) {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 14;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 14;
|
|
} else {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = level;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = level;
|
|
}
|
|
#else // NEC_98
|
|
if (i ==0) {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 7;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 7;
|
|
} else {
|
|
ControlData.DescriptorList[z].u.Interrupt.Level = 5;
|
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 5;
|
|
}
|
|
#endif // NEC_98
|
|
|
|
if (HwBusType == MACHINE_TYPE_MCA) {
|
|
ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
|
|
} else {
|
|
|
|
//
|
|
// For EISA the LevelTriggered is temporarily set to FALSE.
|
|
//
|
|
|
|
ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
|
|
}
|
|
|
|
CurrentEntry->ConfigurationData =
|
|
HwSetUpResourceDescriptor(Component,
|
|
LptPortName,
|
|
&ControlData,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (PreviousEntry) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
}
|
|
}
|
|
return(FirstLptPort);
|
|
}
|
|
#endif //_GAMBIT_
|