📄 ns16550sio.c
字号:
if (pChan->options & CLOCAL)
REG(IER, pChan) = pChan->ier | RxFIFO_BIT | TxFIFO_BIT;
else
{
mask = REG(MSR, pChan) & MSR_CTS;
/* if the CTS is asserted enable Tx interrupt */
if (mask & MSR_CTS)
pChan->ier |= TxFIFO_BIT; /* enable Tx interrupt */
else
pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */
REG(IER, pChan) = pChan->ier;
}
}
else
{
/* disable all ns16550 interrupts */
REG(IER, pChan) = 0;
}
pChan->channelMode = newMode;
intUnlock (oldlevel);
return (OK);
}
/*******************************************************************************
*
* ns16550Ioctl - 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 command SIO_HUP is sent by ttyDrv when the last close() function
* call is made. Likewise SIO_OPEN is sent when the first open() function call
* is made.
*
* RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
* request.
*/
LOCAL STATUS ns16550Ioctl
(
NS16550_CHAN * pChan, /* pointer to channel */
int request, /* request code */
int arg /* some argument */
)
{
FAST STATUS status;
status = OK;
switch (request)
{
case SIO_BAUD_SET:
if (arg < NS16550_MIN_RATE || arg > NS16550_MAX_RATE)
status = EIO; /* baud rate out of range */
else
status = ns16550BaudSet (pChan, arg);
break;
case SIO_BAUD_GET:
*(int *)arg = pChan->baudRate;
break;
case SIO_MODE_SET:
status = (ns16550ModeSet (pChan, arg) == OK) ? OK : EIO;
break;
case SIO_MODE_GET:
*(int *)arg = pChan->channelMode;
break;
case SIO_AVAIL_MODES_GET:
*(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
break;
case SIO_HW_OPTS_SET:
status = (ns16550OptsSet (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 = ns16550Hup (pChan);
break;
case SIO_OPEN:
/* check if hupcl option is enabled */
if (pChan->options & HUPCL)
status = ns16550Open (pChan);
break;
default:
status = ENOSYS;
}
return (status);
}
/*******************************************************************************
*
* ns16550IntWr - handle a transmitter interrupt
*
* This routine handles write interrupts from the UART. It reads a character
* and puts it in the transmit holding register of the device for transfer.
*
* If there are no more characters to transmit, transmission is disabled by
* clearing the transmit interrupt enable bit in the IER(int enable register).
*
* RETURNS: N/A
*
*/
void ns16550IntWr
(
NS16550_CHAN * pChan /* pointer to channel */
)
{
char outChar;
UINT8 intStatus;
if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
REG(THR,pChan) = outChar; /* write char to Transmit Holding Reg */
else
{
pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */
REG(IER, pChan) = pChan->ier;
}
intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */
}
/*******************************************************************************
*
* ns16550IntRd - handle a receiver interrupt
*
* This routine handles read interrupts from the UART.
*
* RETURNS: N/A
*
*/
void ns16550IntRd
(
NS16550_CHAN * pChan /* pointer to channel */
)
{
char inchar;
/* read character from Receive Holding Reg. */
inchar = REG(RBR, pChan);
(*pChan->putRcvChar) (pChan->putRcvArg, inchar);
}
/*******************************************************************************
*
* ns16550IntEx - miscellaneous interrupt processing
*
* This routine handles miscellaneous interrupts on the UART.
* Not implemented yet.
*
* RETURNS: N/A
*
*/
void ns16550IntEx
(
NS16550_CHAN *pChan /* pointer to channel */
)
{
/* Nothing for now... */
}
/********************************************************************************
*
* ns16550Int - interrupt level processing
*
* This routine handles four sources of interrupts from the UART. They are
* prioritized in the following order by the Interrupt Identification Register:
* Receiver Line Status, Received Data Ready, Transmit Holding Register Empty
* and Modem Status.
*
* When a modem status interrupt occurs, the transmit interrupt is enabled if
* the CTS signal is TRUE.
*
* RETURNS: N/A
*
*/
void ns16550Int
(
NS16550_CHAN * pChan /* pointer to channel */
)
{
FAST volatile char intStatus;
/* read the Interrrupt Status Register (Int. Ident.) */
intStatus = (REG(IIR, pChan)) & 0x0f;
/*
* This UART chip always produces level active interrupts, and the IIR
* only indicates the highest priority interrupt.
* In the case that receive and transmit interrupts happened at
* the same time, we must clear both interrupt pending to prevent
* edge-triggered interrupt(output from interrupt controller) from locking
* up. One way doing it is to disable all the interrupts at the beginning
* of the ISR and enable at the end.
*/
REG(IER,pChan) = 0; /* disable interrupt */
switch (intStatus)
{
case IIR_RLS:
/* overrun,parity error and break interrupt */
intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */
break;
case IIR_RDA: /* received data available */
case IIR_TIMEOUT:
/*
* receiver FIFO interrupt. In some case, IIR_RDA will
* not be indicated in IIR register when there is more
* than one character in FIFO.
*/
ns16550IntRd (pChan); /* RxChar Avail */
break;
case IIR_THRE: /* transmitter holding register ready */
{
char outChar;
if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
REG(THR, pChan) = outChar; /* char to Transmit Holding Reg */
else
pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */
}
intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */
break;
case IIR_MSTAT: /* modem status register */
{
char msr;
msr = REG(MSR, pChan);
/* if CTS is asserted by modem, enable tx interrupt */
if ((msr & MSR_CTS) && (msr & MSR_DCTS))
pChan->ier |= TxFIFO_BIT;
else
pChan->ier &= (~TxFIFO_BIT);
}
break;
default:
break;
}
REG(IER, pChan) = pChan->ier; /* enable interrupts accordingly */
}
/*******************************************************************************
*
* ns16550TxStartup - 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, or ENOSYS if in polled mode.
*/
LOCAL int ns16550TxStartup
(
NS16550_CHAN * pChan /* pointer to channel */
)
{
char mask;
if (pChan->channelMode == SIO_MODE_INT)
{
if (pChan->options & CLOCAL)
{
/* No modem control */
pChan->ier |= TxFIFO_BIT;
REG(IER,pChan) = pChan->ier;
}
else
{
mask = REG(MSR, pChan) & MSR_CTS;
/* if the CTS is asserted enable Tx interrupt */
if (mask & MSR_CTS)
pChan->ier |= TxFIFO_BIT; /* enable Tx interrupt */
else
pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */
REG(IER, pChan) = pChan->ier;
}
return (OK);
}
else
{
return (ENOSYS);
}
}
/******************************************************************************
*
* ns16550PollOutput - output a character in polled mode.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the output buffer if full.
*/
LOCAL int ns16550PollOutput
(
NS16550_CHAN * pChan, /* pointer to channel */
char outChar /* char to send */
)
{
char pollStatus = REG(LSR, pChan);
char msr = REG(MSR, pChan);
/* is the transmitter ready to accept a character? */
if ((pollStatus & LSR_THRE) == 0x00)
return (EAGAIN);
if (!(pChan->options & CLOCAL)) /* modem flow control ? */
{
if (msr & MSR_CTS)
REG(THR, pChan) = outChar;
else
return (EAGAIN);
}
else
REG(THR, pChan) = outChar; /* transmit character */
return (OK);
}
/******************************************************************************
*
* ns16550PollInput - poll the device for input.
*
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN
* if the input buffer if empty.
*/
LOCAL int ns16550PollInput
(
NS16550_CHAN * pChan, /* pointer to channel */
char * pChar /* pointer to char */
)
{
char pollStatus = REG(LSR, pChan);
if ((pollStatus & LSR_DR) == 0x00)
return (EAGAIN);
/* got a character */
*pChar = REG(RBR, pChan);
return (OK);
}
/******************************************************************************
*
* ns16550CallbackInstall - install ISR callbacks to get/put chars.
*
* This routine installs the callback functions for the driver
*
* RETURNS: OK on success or ENOSYS on unsupported callback type.
*/
LOCAL int ns16550CallbackInstall
(
SIO_CHAN * pSioChan, /* pointer to device to control */
int callbackType, /* callback type(tx or receive) */
STATUS (*callback)(), /* pointer to callback function */
void * callbackArg /* callback function argument */
)
{
NS16550_CHAN * pChan = (NS16550_CHAN *)pSioChan;
switch (callbackType)
{
case SIO_CALLBACK_GET_TX_CHAR:
pChan->getTxChar = callback;
pChan->getTxArg = callbackArg;
return (OK);
case SIO_CALLBACK_PUT_RCV_CHAR:
pChan->putRcvChar = callback;
pChan->putRcvArg = callbackArg;
return (OK);
default:
return (ENOSYS);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -