summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-25 16:20:14 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1998-07-25 16:20:14 +0000
commit04c5ac7112a8f4fa3f7a312e778aae65bd108f8e (patch)
treef03f03307b7b5728c234b7305df3657d27310f0b
parentChanged comment on TxBuffer. (diff)
downloadrtems-04c5ac7112a8f4fa3f7a312e778aae65bd108f8e.tar.bz2
Removed z85c30_flush().
Reworked transmit interrupt processing to remove ring buffer and to mask the TX empty interrupt when it was not expected. This code now uses termios to buffer TX output.
-rw-r--r--c/src/lib/libchip/serial/z85c30.c203
-rw-r--r--c/src/libchip/serial/z85c30.c203
2 files changed, 158 insertions, 248 deletions
diff --git a/c/src/lib/libchip/serial/z85c30.c b/c/src/lib/libchip/serial/z85c30.c
index bc14c9959a..cd9779e1aa 100644
--- a/c/src/lib/libchip/serial/z85c30.c
+++ b/c/src/lib/libchip/serial/z85c30.c
@@ -63,7 +63,7 @@ console_fns z85c30_fns =
{
libchip_serial_default_probe, /* deviceProbe */
z85c30_open, /* deviceFirstOpen */
- z85c30_flush, /* deviceLastClose */
+ NULL, /* deviceLastClose */
NULL, /* deviceRead */
z85c30_write_support_int, /* deviceWrite */
z85c30_initialize_interrupts, /* deviceInitialize */
@@ -215,6 +215,9 @@ Z85C30_STATIC int z85c30_open(
void *arg
)
{
+
+ z85c30_initialize_port(minor);
+
/*
* Assert DTR
*/
@@ -287,8 +290,6 @@ Z85C30_STATIC void z85c30_init(int minor)
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_B_RST);
}
-
- z85c30_initialize_port(minor);
}
/*
@@ -549,6 +550,7 @@ Z85C30_STATIC void z85c30_process(
/*
* Deal with any received characters
*/
+
while (ucIntPend&SCC_RR3_B_RX_IP)
{
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
@@ -569,8 +571,16 @@ Z85C30_STATIC void z85c30_process(
);
}
- while (TRUE)
- {
+ /*
+ * There could be a race condition here if there is not yet a TX
+ * interrupt pending but the buffer is empty. This condition has
+ * been seen before on other z8530 drivers but has not been seen
+ * with this one. The typical solution is to use "vector includes
+ * status" or to only look at the interrupts actually pending
+ * in RR3.
+ */
+
+ while (TRUE) {
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
if (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
/*
@@ -581,6 +591,7 @@ Z85C30_STATIC void z85c30_process(
break;
}
+#if 0
if (!Z85C30_Status_Is_CTS_asserted(z85c30_status)) {
/*
* We can't transmit yet
@@ -591,34 +602,22 @@ Z85C30_STATIC void z85c30_process(
*/
break;
}
+#endif
- if (Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
- Console_Port_Data[minor].bActive=FALSE;
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
+ if (!rtems_termios_dequeue_characters(
+ Console_Port_Data[minor].termios_data, 1)) {
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
z85c30_negate_RTS(minor);
}
- /*
- * There is no data to transmit
- */
+ Console_Port_Data[minor].bActive = FALSE;
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
break;
}
- Ring_buffer_Remove_character( &Console_Port_Data[minor].TxBuffer, cChar);
-
- /*
- * transmit character
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, cChar);
-
- /*
- * Interrupt once FIFO has room
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
- break;
}
- if (ucIntPend&SCC_RR3_B_EXT_IP) {
+ if (ucIntPend & SCC_RR3_B_EXT_IP) {
/*
* Clear the external status interrupt
*/
@@ -670,91 +669,66 @@ Z85C30_STATIC rtems_isr z85c30_isr(
}
/*
- * z85c30_flush
+ * z85c30_enable_interrupts
+ *
+ * This routine enables the specified interrupts for this minor.
*/
-Z85C30_STATIC int z85c30_flush(
- int major,
+Z85C30_STATIC void z85c30_enable_interrupts(
int minor,
- void *arg
+ int interrupt_mask
)
{
- 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);
- }
- }
+ unsigned32 ulCtrlPort;
+ setRegister_f setReg;
- z85c30_close(major, minor, arg);
+ ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
+ setReg = Console_Port_Tbl[minor].setRegister;
- return(RTEMS_SUCCESSFUL);
+ (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR1, interrupt_mask);
}
/*
* z85c30_initialize_interrupts
*
- * This routine initializes the console's receive and transmit
- * ring buffers and loads the appropriate vectors to handle the interrupts.
- *
- * Input parameters: NONE
- *
- * Output parameters: NONE
- *
- * Return values: NONE
+ * This routine initializes the port to use interrupts.
*/
-Z85C30_STATIC void z85c30_enable_interrupts(
+Z85C30_STATIC void z85c30_initialize_interrupts(
int minor
)
{
- unsigned32 ulCtrlPort;
+ unsigned32 ulCtrlPort1;
+ unsigned32 ulCtrlPort2;
setRegister_f setReg;
- ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
- setReg = Console_Port_Tbl[minor].setRegister;
+ ulCtrlPort1 = Console_Port_Tbl[minor].ulCtrlPort1;
+ ulCtrlPort2 = Console_Port_Tbl[minor].ulCtrlPort2;
+ setReg = Console_Port_Tbl[minor].setRegister;
- /*
- * Enable interrupts
- */
- (*setReg)(
- ulCtrlPort,
- SCC_WR0_SEL_WR1,
- SCC_WR1_EXT_INT_EN | SCC_WR1_TX_INT_EN | SCC_WR1_INT_ALL_RX
- );
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR2, 0);
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
- /*
- * Reset interrupts
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
-}
-
-Z85C30_STATIC void z85c30_initialize_interrupts(
- int minor
-)
-{
z85c30_init(minor);
- Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer);
-
Console_Port_Data[minor].bActive=FALSE;
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
+
+ z85c30_initialize_port( minor );
+
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
z85c30_negate_RTS(minor);
}
- if (Console_Port_Tbl[minor].ulCtrlPort1== Console_Port_Tbl[minor].ulCtrlPort2) {
- /*
- * Only do this for Channel A
- */
+ set_vector(z85c30_isr, Console_Port_Tbl[minor].ulIntVector, 1);
- set_vector(z85c30_isr, Console_Port_Tbl[minor].ulIntVector, 1);
- }
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
+
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR2, 0); /* XXX vector */
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
- z85c30_enable_interrupts(minor);
+ /*
+ * Reset interrupts
+ */
+
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
}
/*
@@ -769,56 +743,37 @@ Z85C30_STATIC int z85c30_write_support_int(
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
- */
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
- z85c30_assert_RTS(minor);
- }
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive=TRUE;
- z85c30_process(minor, SCC_RR3_B_TX_IP);
- rtems_interrupt_enable(Irql);
- } else {
- /*
- * Yield while we await an interrupt
- */
- rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
- }
+ unsigned32 Irql;
+ unsigned32 ulCtrlPort;
+ setRegister_f setReg;
- /*
- * Wait for ring buffer to empty
- */
- continue;
- } else {
- Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]);
- i++;
- }
- }
+ ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
+ setReg = Console_Port_Tbl[minor].setRegister;
/*
- * 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
- */
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
- z85c30_assert_RTS(minor);
- }
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive=TRUE;
- z85c30_process(minor, SCC_RR3_B_TX_IP);
- rtems_interrupt_enable(Irql);
+
+ if ( !len )
+ return 0;
+
+ /*
+ * Put the character out and enable interrupts if necessary.
+ */
+
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
+ z85c30_assert_RTS(minor);
}
+ rtems_interrupt_disable(Irql);
+ if ( Console_Port_Data[minor].bActive == FALSE) {
+ Console_Port_Data[minor].bActive = TRUE;
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR);
+ }
+ (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, *buf);
+ rtems_interrupt_enable(Irql);
- return (len);
+ return 1;
}
/*
diff --git a/c/src/libchip/serial/z85c30.c b/c/src/libchip/serial/z85c30.c
index bc14c9959a..cd9779e1aa 100644
--- a/c/src/libchip/serial/z85c30.c
+++ b/c/src/libchip/serial/z85c30.c
@@ -63,7 +63,7 @@ console_fns z85c30_fns =
{
libchip_serial_default_probe, /* deviceProbe */
z85c30_open, /* deviceFirstOpen */
- z85c30_flush, /* deviceLastClose */
+ NULL, /* deviceLastClose */
NULL, /* deviceRead */
z85c30_write_support_int, /* deviceWrite */
z85c30_initialize_interrupts, /* deviceInitialize */
@@ -215,6 +215,9 @@ Z85C30_STATIC int z85c30_open(
void *arg
)
{
+
+ z85c30_initialize_port(minor);
+
/*
* Assert DTR
*/
@@ -287,8 +290,6 @@ Z85C30_STATIC void z85c30_init(int minor)
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_CH_B_RST);
}
-
- z85c30_initialize_port(minor);
}
/*
@@ -549,6 +550,7 @@ Z85C30_STATIC void z85c30_process(
/*
* Deal with any received characters
*/
+
while (ucIntPend&SCC_RR3_B_RX_IP)
{
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
@@ -569,8 +571,16 @@ Z85C30_STATIC void z85c30_process(
);
}
- while (TRUE)
- {
+ /*
+ * There could be a race condition here if there is not yet a TX
+ * interrupt pending but the buffer is empty. This condition has
+ * been seen before on other z8530 drivers but has not been seen
+ * with this one. The typical solution is to use "vector includes
+ * status" or to only look at the interrupts actually pending
+ * in RR3.
+ */
+
+ while (TRUE) {
z85c30_status = (*getReg)(ulCtrlPort, SCC_WR0_SEL_RD0);
if (!Z85C30_Status_Is_TX_buffer_empty(z85c30_status)) {
/*
@@ -581,6 +591,7 @@ Z85C30_STATIC void z85c30_process(
break;
}
+#if 0
if (!Z85C30_Status_Is_CTS_asserted(z85c30_status)) {
/*
* We can't transmit yet
@@ -591,34 +602,22 @@ Z85C30_STATIC void z85c30_process(
*/
break;
}
+#endif
- if (Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
- Console_Port_Data[minor].bActive=FALSE;
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
+ if (!rtems_termios_dequeue_characters(
+ Console_Port_Data[minor].termios_data, 1)) {
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
z85c30_negate_RTS(minor);
}
- /*
- * There is no data to transmit
- */
+ Console_Port_Data[minor].bActive = FALSE;
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
(*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
break;
}
- Ring_buffer_Remove_character( &Console_Port_Data[minor].TxBuffer, cChar);
-
- /*
- * transmit character
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, cChar);
-
- /*
- * Interrupt once FIFO has room
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_TX_INT);
- break;
}
- if (ucIntPend&SCC_RR3_B_EXT_IP) {
+ if (ucIntPend & SCC_RR3_B_EXT_IP) {
/*
* Clear the external status interrupt
*/
@@ -670,91 +669,66 @@ Z85C30_STATIC rtems_isr z85c30_isr(
}
/*
- * z85c30_flush
+ * z85c30_enable_interrupts
+ *
+ * This routine enables the specified interrupts for this minor.
*/
-Z85C30_STATIC int z85c30_flush(
- int major,
+Z85C30_STATIC void z85c30_enable_interrupts(
int minor,
- void *arg
+ int interrupt_mask
)
{
- 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);
- }
- }
+ unsigned32 ulCtrlPort;
+ setRegister_f setReg;
- z85c30_close(major, minor, arg);
+ ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
+ setReg = Console_Port_Tbl[minor].setRegister;
- return(RTEMS_SUCCESSFUL);
+ (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR1, interrupt_mask);
}
/*
* z85c30_initialize_interrupts
*
- * This routine initializes the console's receive and transmit
- * ring buffers and loads the appropriate vectors to handle the interrupts.
- *
- * Input parameters: NONE
- *
- * Output parameters: NONE
- *
- * Return values: NONE
+ * This routine initializes the port to use interrupts.
*/
-Z85C30_STATIC void z85c30_enable_interrupts(
+Z85C30_STATIC void z85c30_initialize_interrupts(
int minor
)
{
- unsigned32 ulCtrlPort;
+ unsigned32 ulCtrlPort1;
+ unsigned32 ulCtrlPort2;
setRegister_f setReg;
- ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
- setReg = Console_Port_Tbl[minor].setRegister;
+ ulCtrlPort1 = Console_Port_Tbl[minor].ulCtrlPort1;
+ ulCtrlPort2 = Console_Port_Tbl[minor].ulCtrlPort2;
+ setReg = Console_Port_Tbl[minor].setRegister;
- /*
- * Enable interrupts
- */
- (*setReg)(
- ulCtrlPort,
- SCC_WR0_SEL_WR1,
- SCC_WR1_EXT_INT_EN | SCC_WR1_TX_INT_EN | SCC_WR1_INT_ALL_RX
- );
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR2, 0);
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
- /*
- * Reset interrupts
- */
- (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
-}
-
-Z85C30_STATIC void z85c30_initialize_interrupts(
- int minor
-)
-{
z85c30_init(minor);
- Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer);
-
Console_Port_Data[minor].bActive=FALSE;
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
+
+ z85c30_initialize_port( minor );
+
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
z85c30_negate_RTS(minor);
}
- if (Console_Port_Tbl[minor].ulCtrlPort1== Console_Port_Tbl[minor].ulCtrlPort2) {
- /*
- * Only do this for Channel A
- */
+ set_vector(z85c30_isr, Console_Port_Tbl[minor].ulIntVector, 1);
- set_vector(z85c30_isr, Console_Port_Tbl[minor].ulIntVector, 1);
- }
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR_EXCEPT_TX);
+
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR2, 0); /* XXX vector */
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR9, SCC_WR9_MIE);
- z85c30_enable_interrupts(minor);
+ /*
+ * Reset interrupts
+ */
+
+ (*setReg)(ulCtrlPort1, SCC_WR0_SEL_WR0, SCC_WR0_RST_INT);
}
/*
@@ -769,56 +743,37 @@ Z85C30_STATIC int z85c30_write_support_int(
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
- */
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
- z85c30_assert_RTS(minor);
- }
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive=TRUE;
- z85c30_process(minor, SCC_RR3_B_TX_IP);
- rtems_interrupt_enable(Irql);
- } else {
- /*
- * Yield while we await an interrupt
- */
- rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
- }
+ unsigned32 Irql;
+ unsigned32 ulCtrlPort;
+ setRegister_f setReg;
- /*
- * Wait for ring buffer to empty
- */
- continue;
- } else {
- Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]);
- i++;
- }
- }
+ ulCtrlPort = Console_Port_Tbl[minor].ulCtrlPort1;
+ setReg = Console_Port_Tbl[minor].setRegister;
/*
- * 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
- */
- if (Console_Port_Tbl[minor].pDeviceFlow !=&z85c30_flow_RTSCTS) {
- z85c30_assert_RTS(minor);
- }
- rtems_interrupt_disable(Irql);
- Console_Port_Data[minor].bActive=TRUE;
- z85c30_process(minor, SCC_RR3_B_TX_IP);
- rtems_interrupt_enable(Irql);
+
+ if ( !len )
+ return 0;
+
+ /*
+ * Put the character out and enable interrupts if necessary.
+ */
+
+ if (Console_Port_Tbl[minor].pDeviceFlow != &z85c30_flow_RTSCTS) {
+ z85c30_assert_RTS(minor);
}
+ rtems_interrupt_disable(Irql);
+ if ( Console_Port_Data[minor].bActive == FALSE) {
+ Console_Port_Data[minor].bActive = TRUE;
+ z85c30_enable_interrupts(minor, SCC_ENABLE_ALL_INTR);
+ }
+ (*setReg)(ulCtrlPort, SCC_WR0_SEL_WR8, *buf);
+ rtems_interrupt_enable(Irql);
- return (len);
+ return 1;
}
/*