📄 i8250sio.c
字号:
if (options & STOPB)
lcr |= I8250_LCR_2_STB;
else
lcr |= I8250_LCR_1_STB;
switch (options & (PARENB | PARODD))
{
case PARENB|PARODD:
lcr |= I8250_LCR_PEN; break;
case PARENB:
lcr |= (I8250_LCR_PEN | I8250_LCR_EPS); break;
default:
case 0:
lcr |= I8250_LCR_PDIS; break;
}
(*pChan->outByte) (pChan->ier, 0x00);
if (!(options & CLOCAL))
{
/* !clocal enables hardware flow control(DTR/DSR) */
mcr |= (I8250_MCR_DTR | I8250_MCR_RTS);
ier |= I8250_IER_MSI; /* enable modem status interrupt */
mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;
/* if the CTS is asserted enable Tx interrupt */
if (mask & I8250_MSR_CTS)
ier |= I8250_IER_TBE;
else
ier &= (~I8250_IER_TBE);
}
else
ier &= ~I8250_IER_MSI; /* disable modem status interrupt */
oldlevel = intLock ();
(*pChan->outByte) (pChan->lcr, lcr);
(*pChan->outByte) (pChan->mdc, mcr);
/* now clear the port */
(*pChan->inByte) (pChan->data);
if (options & CREAD)
ier |= I8250_IER_RXRDY;
if (pChan->channelMode == SIO_MODE_INT)
{
(*pChan->outByte) (pChan->ier, ier);
}
intUnlock (oldlevel);
pChan->options = options;
return OK;
}
/*******************************************************************************
*
* i8250Ioctl - special device control
*
* Includes commands to get/set baud rate, mode(INT, POLL), hardware options(
* parity, number of data bits), and modem control(RTS/CTS and DTR/DSR).
* The ioctl commands SIO_HUP and SIO_OPEN are implemented to provide the
* HUPCL( hang up on last close) function.
*
* RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
* request.
*/
static int i8250Ioctl
(
I8250_CHAN * pChan, /* device to control */
int request, /* request code */
int arg /* some argument */
)
{
int ix;
int baudH;
int baudL;
int oldlevel;
UINT8 lcr;
int status = OK;
switch (request)
{
case SIO_BAUD_SET:
status = (i8250BaudSet(pChan, arg) == OK) ? OK : EIO;
break;
case SIO_BAUD_GET:
oldlevel = intLock();
status = EIO;
lcr = (*pChan->inByte) (pChan->lcr);
(*pChan->outByte) (pChan->lcr, (char)(I8250_LCR_DLAB | lcr));
baudH = (*pChan->inByte)(pChan->brdh);
baudL = (*pChan->inByte)(pChan->brdl);
(*pChan->outByte) (pChan->lcr, lcr);
for (ix = 0; ix < NELEMENTS (baudTable); ix++)
{
if ( baudH == MSB (baudTable[ix].preset) &&
baudL == LSB (baudTable[ix].preset) )
{
*(int *)arg = baudTable[ix].rate;
status = OK;
}
}
intUnlock(oldlevel);
break;
case SIO_MODE_SET:
status = (i8250ModeSet (pChan, arg) == OK) ? OK : EIO;
break;
case SIO_MODE_GET:
*(int *)arg = pChan->channelMode;
return (OK);
case SIO_AVAIL_MODES_GET:
*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
return (OK);
case SIO_HW_OPTS_SET:
status = (i8250OptsSet (pChan, arg) == OK) ? OK : EIO;
break;
case SIO_HW_OPTS_GET:
*(int *)arg = pChan->options;
break;
case SIO_HUP:
/* check if hupcl option is enabled */
if (pChan->options & HUPCL)
status = i8250Hup (pChan);
break;
case SIO_OPEN:
/* check if hupcl option is enabled */
if (pChan->options & HUPCL)
status = i8250Open (pChan);
break;
default:
status = ENOSYS;
break;
}
return (status);
}
/*******************************************************************************
*
* i8250Int - handle a receiver/transmitter interrupt
*
* This routine handles four sources of interrupts from the UART. If there is
* another character to be transmitted, the character is sent. When a modem
* status interrupt occurs, the transmit interrupt is enabled if the CTS signal
* is TRUE.
*
* INTERNAL
* The UART interrupts are prioritized in the following order by the Interrupt
* Identification Register:
*
* Bit 2 bit 1 bit 0 Priority Interrupt ID
* -------------------------------------------------------
* 0 0 1 none none
* 1 1 0 0 serialization error or BREAK
* 1 0 0 1 received data
* 0 1 0 2 transmitter buffer empty
* 0 0 0 3 RS-232 input
*
* In the table, priority level 0 is the highest priority. These priorities
* are not typically configurable via software. The interrupt is expressed as
* a two-bit integer. Bit 0, the pending bit, is negative logic - a value 0
* means that an interrupt is pending.
*
* When nested interrupts occur, the second interrupt is identified in the
* Interrupt Identification Register (IIR) as soon as the first interrupt is
* cleared. Therefore, the interrupt service routine must continue to read IIR
* until bit-0 is 1.
*
* When the 8250 generates an interrupt, all interrupts with an equal or
* lower priority are locked out until the current interrupt has been cleared.
* The operation required to clear an interrupt varies according to the source.
* The actions typically required to clear an interrupt are as follows:
*
* Source of interrupt Response required to reset
* ---------------------------------------------------------------------
* receiver error or BREAK read serialization status register
* received data read data from receiver register
* transmit buffer empty write to the transmitter or read
* the interrupt ID register
* RS-232 input read the RS-232 status register
*
* In response to an empty transmit buffer (TBE), the interrupt can be
* cleared by writing a byte to the transmitter buffer register. It can
* also be cleared by reading the interrupt identification register.
*
* Failure to clear all interrupts before returning will leave an interrupt
* pending and prevent the UART from generating further interrupt requests
* to the CPU.
*
* RETURNS: N/A
*/
void i8250Int
(
I8250_CHAN * pChan
)
{
char outChar; /* store a byte for transmission */
char interruptID; /* store contents of interrupt ID register */
char lineStatus; /* store contents of line status register */
char ier; /* store contents of interrupt enable register */
int ix = 0; /* allows us to return just in case IP never clears */
ier = (*pChan->inByte) (pChan->ier);
/* service UART interrupts until IP bit set or read counter expires */
FOREVER
{
interruptID = ((*pChan->inByte)(pChan->iid) & I8250_IIR_MASK);
if ((interruptID == I8250_IIR_IP) || (++ix > I8250_IIR_READ_MAX))
{
break; /* interrupt cleared or loop counter expired */
}
/* filter possible anomalous interrupt ID from PC87307VUL (SPR 26117) */
interruptID &= 0x06; /* clear odd-bit to find interrupt ID */
if (interruptID == I8250_IIR_SEOB)
{
lineStatus = (*pChan->inByte) (pChan->lst);
}
else if (interruptID == I8250_IIR_RBRF)
{
if (pChan->putRcvChar != NULL)
(*pChan->putRcvChar)(pChan->putRcvArg,
(*pChan->inByte) (pChan->data));
else
(*pChan->inByte) (pChan->data);
}
else if (interruptID == I8250_IIR_THRE)
{
if ((pChan->getTxChar != NULL) &&
(*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK
)
{
(*pChan->outByte) (pChan->data, outChar);
}
/* There are no bytes available for transmission. Reading
* the IIR at the top of this loop will clear the interrupt.
*/
}
else if (interruptID == I8250_IIR_MSTAT) /* modem status register */
{
char msr = (*(pChan)->inByte) (pChan->msr);
/* (|=) ... DON'T CLOBBER BITS ALREADY SET IN THE IER */
ier |= (I8250_IER_RXRDY | I8250_IER_MSI);
/* if CTS is asserted by modem, enable tx interrupt */
if ((msr & I8250_MSR_CTS) && (msr & I8250_MSR_DCTS))
{
(*pChan->outByte) (pChan->ier, (I8250_IER_TBE | ier));
}
else /* turn off TBE interrupt until CTS from modem */
{
(*pChan->outByte) (pChan->ier, (ier & (~I8250_IER_TBE)));
}
}
} /* FOREVER */
}
/*******************************************************************************
*
* i8250Startup - transmitter startup routine
*
* Call interrupt level character output routine and enable interrupt if it is
* in interrupt mode with no hardware flow control.
* If the option for hardware flow control is enabled and CTS is set TRUE,
* then the Tx interrupt is enabled.
*
* RETURNS: OK
*/
LOCAL int i8250Startup
(
I8250_CHAN * pChan /* tty device to start up */
)
{
char ier = I8250_IER_RXRDY;
char mask;
if (pChan->channelMode == SIO_MODE_INT)
{
if (pChan->options & CLOCAL)
{
/* No modem control */
ier |= I8250_IER_TBE;
}
else
{
mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;
/* if the CTS is asserted enable Tx interrupt */
if (mask & I8250_MSR_CTS)
ier |= (I8250_IER_TBE | I8250_IER_MSI);
else
ier |= (I8250_IER_MSI);
}
(*pChan->outByte) (pChan->ier, ier);
}
return (OK);
}
/******************************************************************************
*
* i8250PRxChar - poll the device for input.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the input buffer if empty.
*/
LOCAL int i8250PRxChar
(
I8250_CHAN * pChan, /* pointer to channel */
char * pChar /* pointer to char */
)
{
char pollStatus;
pollStatus = ( *(pChan)->inByte) (pChan->lst);
if ((pollStatus & I8250_LSR_RXRDY) == 0x00)
return (EAGAIN);
/* got a character */
*pChar = ( *(pChan)->inByte) (pChan->data);
return (OK);
}
/******************************************************************************
*
* i8250PTxChar - output a character in polled mode.
*
* Checks if the transmitter is empty. If empty, a character is written to
* the data register.
*
* If the hardware flow control is enabled the handshake signal CTS has to be
* asserted in order to send a character.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the output buffer if full.
*/
LOCAL int i8250PTxChar
(
I8250_CHAN * pChan, /* pointer to channel */
char outChar /* char to send */
)
{
char pollStatus;
char msr;
pollStatus = ( *(pChan)->inByte) (pChan->lst);
msr = (*(pChan)->inByte) (pChan->msr);
/* is the transmitter ready to accept a character? */
if ((pollStatus & I8250_LSR_TEMT) == 0x00)
return (EAGAIN);
if (!(pChan->options & CLOCAL)) /* modem flow control ? */
{
if (msr & I8250_MSR_CTS)
(*(pChan)->outByte) ((pChan)->data, outChar);
else
return (EAGAIN);
}
else
(*(pChan)->outByte) ((pChan)->data, outChar);
return (OK);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -