summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-25 16:53:21 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-25 16:53:21 +0000
commit70a94515a7f0e6de540894beae14fb9534cdc21e (patch)
tree882c6eead3c679b983e391ea53239b21da37475d /c/src/libchip
parentRemoved TX ring buffer. (diff)
downloadrtems-70a94515a7f0e6de540894beae14fb9534cdc21e.tar.bz2
Rewrote NS16550 TX interrupt processing to use termios for the buffer
and manage the interrupt sources like the other drivers. This let use remove the ns16550_flush() routine.
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/serial/STATUS5
-rw-r--r--c/src/libchip/serial/ns16550.c193
-rw-r--r--c/src/libchip/serial/ns16550_p.h11
3 files changed, 84 insertions, 125 deletions
diff --git a/c/src/libchip/serial/STATUS b/c/src/libchip/serial/STATUS
index c5cf7da1b7..16c256615e 100644
--- a/c/src/libchip/serial/STATUS
+++ b/c/src/libchip/serial/STATUS
@@ -35,9 +35,8 @@ NS16650
+ Not tested in libchip context. Based on Radstone PPC2 driver which worked
well.
-+ Interrupt code needs to be reworked to eliminate Ring_buffer usage. This
- will probably require managing the interrupt mask register as is
- done in the mc68681 and z85c30 drivers.
++ Interrupt code has been reworked to not use ring buffer and may be broken
+ as it has not been tested since this was done.
+ Missing set attributes function.
diff --git a/c/src/libchip/serial/ns16550.c b/c/src/libchip/serial/ns16550.c
index 8b962b9844..21bc839002 100644
--- a/c/src/libchip/serial/ns16550.c
+++ b/c/src/libchip/serial/ns16550.c
@@ -48,7 +48,7 @@ console_fns ns16550_fns =
{
libchip_serial_default_probe, /* deviceProbe */
ns16550_open, /* deviceFirstOpen */
- ns16550_flush, /* deviceLastClose */
+ NULL, /* deviceLastClose */
NULL, /* deviceRead */
ns16550_write_support_int, /* deviceWrite */
ns16550_initialize_interrupts, /* deviceInitialize */
@@ -97,13 +97,15 @@ NS16550_STATIC void ns16550_init(int minor)
*/
(*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
- (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, 0x0);
+ ns16550_enable_interrupts(minor, NS16550_DISABLE_ALL_INTR);
/* Set the divisor latch and set the baud rate. */
ulBaudDivisor=NS16550_Baud((unsigned32)Console_Port_Tbl[minor].pDeviceParams);
ucDataByte = SP_LINE_DLAB;
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
+
+ /* XXX */
(*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
(*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
@@ -119,11 +121,7 @@ NS16550_STATIC void ns16550_init(int minor)
ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
(*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
- /*
- * Disable interrupts
- */
- ucDataByte = 0;
- (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, ucDataByte);
+ ns16550_enable_interrupts(minor, NS16550_DISABLE_ALL_INTR);
/* Set data terminal ready. */
/* And open interrupt tristate line */
@@ -169,6 +167,7 @@ NS16550_STATIC int ns16550_close(
/*
* ns16550_write_polled
*/
+
NS16550_STATIC void ns16550_write_polled(
int minor,
char cChar
@@ -335,7 +334,7 @@ NS16550_STATIC void ns16550_process(
unsigned32 pNS16550;
volatile unsigned8 ucLineStatus;
volatile unsigned8 ucInterruptId;
- char cChar;
+ unsigned char cChar;
getRegister_f getReg;
setRegister_f setReg;
@@ -360,39 +359,42 @@ NS16550_STATIC void ns16550_process(
);
}
+ /*
+ * TX all the characters we can
+ */
+
while(TRUE) {
- if(Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
- Console_Port_Data[minor].bActive=FALSE;
- if(Console_Port_Tbl[minor].pDeviceFlow !=&ns16550_flow_RTSCTS) {
- ns16550_negate_RTS(minor);
+ ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
+ if(~ucLineStatus & SP_LSR_THOLD) {
+ /*
+ * We'll get another interrupt when
+ * the transmitter holding reg. becomes
+ * free again
+ */
+ break;
}
- /*
- * There is no data to transmit
- */
- break;
- }
+#if 0
+ /* XXX flow control not completely supported in libchip */
- ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
- if(~ucLineStatus & SP_LSR_THOLD) {
- /*
- * We'll get another interrupt when
- * the transmitter holding reg. becomes
- * free again
- */
+ if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
+ ns16550_negate_RTS(minor);
+ }
+#endif
+
+ if (!rtems_termios_dequeue_characters(
+ Console_Port_Data[minor].termios_data, 1)) {
+ if (Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
+ ns16550_negate_RTS(minor);
+ }
+ Console_Port_Data[minor].bActive = FALSE;
+ ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
break;
}
- Ring_buffer_Remove_character( &Console_Port_Data[minor].TxBuffer, cChar);
- /*
- * transmit character
- */
- (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, cChar);
+ ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID);
}
-
- ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID);
- }
- while((ucInterruptId&0xf)!=0x1);
+ } while((ucInterruptId&0xf)!=0x1);
}
NS16550_STATIC rtems_isr ns16550_isr(
@@ -410,132 +412,82 @@ NS16550_STATIC rtems_isr ns16550_isr(
}
/*
- * ns16550_flush
- */
-NS16550_STATIC int ns16550_flush(int major, int minor, void *arg)
-{
- while(!Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
- /*
- * Yield while we wait
- */
- if(_System_state_Is_up(_System_state_Get())) {
- rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
- }
- }
-
- ns16550_close(major, minor, arg);
-
- return(RTEMS_SUCCESSFUL);
-}
-
-/*
- * ns16550_initialize_interrupts
- *
- * This routine initializes the console's receive and transmit
- * ring buffers and loads the appropriate vectors to handle the interrupts.
+ * ns16550_enable_interrupts
*
- * Input parameters: NONE
- *
- * Output parameters: NONE
- *
- * Return values: NONE
+ * This routine initializes the port to have the specified interrupts masked.
*/
NS16550_STATIC void ns16550_enable_interrupts(
- int minor
+ int minor,
+ int mask
)
{
- unsigned32 pNS16550;
- unsigned8 ucDataByte;
- setRegister_f setReg;
+ unsigned32 pNS16550;
+ setRegister_f setReg;
pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1;
setReg = Console_Port_Tbl[minor].setRegister;
- /*
- * Enable interrupts
- */
- ucDataByte = SP_INT_RX_ENABLE | SP_INT_TX_ENABLE;
- (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, ucDataByte);
-
+ (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
}
+/*
+ * ns16550_initialize_interrupts
+ *
+ * This routine initializes the port to operate in interrupt driver mode.
+ */
+
NS16550_STATIC void ns16550_initialize_interrupts(int minor)
{
ns16550_init(minor);
- Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer);
-
Console_Port_Data[minor].bActive = FALSE;
set_vector(ns16550_isr, Console_Port_Tbl[minor].ulIntVector, 1);
- ns16550_enable_interrupts(minor);
+ ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR);
}
/*
* ns16550_write_support_int
*
* Console Termios output entry point.
- *
*/
+
NS16550_STATIC int ns16550_write_support_int(
int minor,
const char *buf,
int len
)
{
- int i;
- unsigned32 Irql;
-
- for(i=0; i<len;) {
- if(Ring_buffer_Is_full(&Console_Port_Data[minor].TxBuffer)) {
- if(!Console_Port_Data[minor].bActive) {
- /*
- * Wake up the device
- */
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive = TRUE;
- if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
- ns16550_assert_RTS(minor);
- }
- ns16550_process(minor);
- rtems_interrupt_enable(Irql);
- } else {
- /*
- * Yield
- */
- rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
- }
+ unsigned32 Irql;
+ unsigned32 pNS16550;
+ setRegister_f setReg;
- /*
- * Wait for ring buffer to empty
- */
- continue;
- }
- else {
- Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]);
- i++;
- }
- }
+ setReg = Console_Port_Tbl[minor].setRegister;
+ pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1;
/*
- * Ensure that characters are on the way
+ * We are using interrupt driven output and termios only sends us
+ * one character at a time.
*/
- if(!Console_Port_Data[minor].bActive) {
- /*
- * Wake up the device
- */
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive = TRUE;
- if(Console_Port_Tbl[minor].pDeviceFlow !=&ns16550_flow_RTSCTS) {
- ns16550_assert_RTS(minor);
- }
- ns16550_process(minor);
- rtems_interrupt_enable(Irql);
+
+ if ( !len )
+ return 0;
+
+ if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
+ ns16550_assert_RTS(minor);
}
- return (len);
+ rtems_interrupt_disable(Irql);
+ if ( Console_Port_Data[minor].bActive == FALSE) {
+ Console_Port_Data[minor].bActive = TRUE;
+ ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR);
+ }
+ (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, *buf);
+ rtems_interrupt_enable(Irql);
+
+ return 1;
}
/*
@@ -544,6 +496,7 @@ NS16550_STATIC int ns16550_write_support_int(
* Console Termios output entry point.
*
*/
+
NS16550_STATIC int ns16550_write_support_polled(
int minor,
const char *buf,
diff --git a/c/src/libchip/serial/ns16550_p.h b/c/src/libchip/serial/ns16550_p.h
index 95d4ec77b1..1ffd0725c7 100644
--- a/c/src/libchip/serial/ns16550_p.h
+++ b/c/src/libchip/serial/ns16550_p.h
@@ -82,6 +82,10 @@ typedef volatile struct _SP_WRITE_REGISTERS {
#define SP_INT_LS_ENABLE 0x04
#define SP_INT_MS_ENABLE 0x08
+#define NS16550_ENABLE_ALL_INTR (SP_INT_RX_ENABLE | SP_INT_TX_ENABLE)
+#define NS16550_DISABLE_ALL_INTR 0x00
+#define NS16550_ENABLE_ALL_INTR_EXCEPT_TX (SP_INT_RX_ENABLE)
+
/*
* Define serial port interrupt id register structure.
*/
@@ -201,8 +205,6 @@ NS16550_STATIC int ns16550_negate_DTR(
NS16550_STATIC void ns16550_initialize_interrupts(int minor);
-NS16550_STATIC int ns16550_flush(int major, int minor, void *arg);
-
NS16550_STATIC int ns16550_write_support_int(
int minor,
const char *buf,
@@ -219,6 +221,11 @@ NS16550_STATIC int ns16550_inbyte_nonblocking_polled(
int minor
);
+NS16550_STATIC void ns16550_enable_interrupts(
+ int minor,
+ int mask
+);
+
#ifdef __cplusplus
}
#endif