summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-07-17 13:53:24 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-07-17 13:53:24 +0000
commitec5d45053b71f052d978e423f08ad4e28e1b800d (patch)
treee816f35f7d24a8a6c99bcdd60a18ca5227ff8bee /c
parentARM bsp maintenance (diff)
downloadrtems-ec5d45053b71f052d978e423f08ad4e28e1b800d.tar.bz2
code cleanup
Diffstat (limited to 'c')
-rw-r--r--c/src/ChangeLog6
-rw-r--r--c/src/libchip/serial/ns16550.c212
-rw-r--r--c/src/libchip/serial/ns16550_p.h55
3 files changed, 119 insertions, 154 deletions
diff --git a/c/src/ChangeLog b/c/src/ChangeLog
index 79cdd52b4b..9c780033d0 100644
--- a/c/src/ChangeLog
+++ b/c/src/ChangeLog
@@ -5,6 +5,12 @@
now use the same macros.
* aclocal/bsp-bspcleanup-options.m4: New file.
+2009-07-15 Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+ * libchip/serial/ns16550.c, libchip/serial/ns16550_p.h: Removed
+ obsolete defines and declarations. Set initial baud during device
+ open. Fixed interrupt mode.
+
2009-06-12 Joel Sherrill <joel.sherrill@oarcorp.com>
* libchip/i2c/spi-sd-card.c, libchip/ide/ata.c: Eliminate using the
diff --git a/c/src/libchip/serial/ns16550.c b/c/src/libchip/serial/ns16550.c
index f31ddf7a04..631625e6a9 100644
--- a/c/src/libchip/serial/ns16550.c
+++ b/c/src/libchip/serial/ns16550.c
@@ -30,6 +30,7 @@
#include <rtems/libio.h>
#include <rtems/ringbuf.h>
#include <rtems/bspIo.h>
+#include <rtems/termiostypes.h>
#include <libchip/serial.h>
#include <libchip/sersupp.h>
@@ -164,20 +165,24 @@ NS16550_STATIC void ns16550_init(int minor)
*/
NS16550_STATIC int ns16550_open(
- int major,
- int minor,
- void * arg
+ int major,
+ int minor,
+ void *arg
)
{
- /*
- * Assert DTR
- */
+ rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
+ struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
+ console_tbl *c = &Console_Port_Tbl [minor];
- if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_DTRCTS) {
- ns16550_assert_DTR(minor);
+ /* Assert DTR */
+ if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
+ ns16550_assert_DTR( minor);
}
- return(RTEMS_SUCCESSFUL);
+ /* Set initial baud */
+ rtems_termios_set_initial_baud( tty, (int) c->pDeviceParams);
+
+ return RTEMS_SUCCESSFUL;
}
/*
@@ -203,15 +208,22 @@ NS16550_STATIC int ns16550_close(
/**
* @brief Polled write for NS16550.
*/
-NS16550_STATIC void ns16550_write_polled( int minor, char c)
+NS16550_STATIC void ns16550_write_polled( int minor, char out)
{
- uint32_t port = Console_Port_Tbl [minor].ulCtrlPort1;
- getRegister_f get = Console_Port_Tbl [minor].getRegister;
- setRegister_f set = Console_Port_Tbl [minor].setRegister;
- uint32_t status;
+ console_tbl *c = &Console_Port_Tbl [minor];
+ uint32_t port = c->ulCtrlPort1;
+ getRegister_f get = c->getRegister;
+ setRegister_f set = c->setRegister;
+ uint32_t status = 0;
rtems_interrupt_level level;
- while (1) {
+ /* Save port interrupt mask */
+ uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
+
+ /* Disable port interrupts */
+ ns16550_enable_interrupts( minor, NS16550_DISABLE_ALL_INTR);
+
+ while (true) {
/* Try to transmit the character in a critical section */
rtems_interrupt_disable( level);
@@ -219,7 +231,7 @@ NS16550_STATIC void ns16550_write_polled( int minor, char c)
status = get( port, NS16550_LINE_STATUS);
if ((status & SP_LSR_THOLD) != 0) {
/* Transmit character */
- set( port, NS16550_TRANSMIT_BUFFER, c);
+ set( port, NS16550_TRANSMIT_BUFFER, out);
/* Finished */
rtems_interrupt_enable( level);
@@ -233,6 +245,9 @@ NS16550_STATIC void ns16550_write_polled( int minor, char c)
status = get( port, NS16550_LINE_STATUS);
} while ((status & SP_LSR_THOLD) == 0);
}
+
+ /* Restore port interrupt mask */
+ set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
}
/*
@@ -448,72 +463,91 @@ NS16550_STATIC int ns16550_set_attributes(
}
#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
-/*
- * ns16550_process
- *
- * This routine is the console interrupt handler for A port.
- */
-NS16550_STATIC void ns16550_process(int minor)
+/**
+ * @brief Process interrupt.
+ */
+NS16550_STATIC void ns16550_process( int minor)
{
console_tbl *c = &Console_Port_Tbl [minor];
console_data *d = &Console_Port_Data [minor];
-
- uint32_t pNS16550;
- volatile uint8_t ucLineStatus;
- volatile uint8_t ucInterruptId;
- char cChar;
- getRegister_f getReg;
- setRegister_f setReg;
-
- pNS16550 = c->ulCtrlPort1;
- getReg = c->getRegister;
- setReg = c->setRegister;
-
+ ns16550_context *ctx = d->pDeviceContext;
+ uint32_t port = c->ulCtrlPort1;
+ getRegister_f get = c->getRegister;
+ setRegister_f set = c->setRegister;
+ int i = 0;
+ char buf [SP_FIFO_SIZE];
+
+ /* Iterate until no more interrupts are pending */
do {
- /*
- * Deal with any received characters
- */
- while (true) {
- ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
- if (~ucLineStatus & SP_LSR_RDY) {
+ /* Fetch received characters */
+ for (i = 0; i < SP_FIFO_SIZE; ++i) {
+ if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
+ buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
+ } else {
break;
}
- cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
- rtems_termios_enqueue_raw_characters(
- d->termios_data,
- &cChar,
- 1
- );
}
- /*
- * TX all the characters we can
- */
+ /* Enqueue fetched characters */
+ rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
- while (true) {
- 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;
- }
+ /* Check if we can dequeue transmitted characters */
+ if (ctx->transmitFifoChars > 0
+ && (get( port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
+ unsigned chars = ctx->transmitFifoChars;
+
+ /*
+ * We finished the transmission, so clear the number of characters in the
+ * transmit FIFO.
+ */
+ ctx->transmitFifoChars = 0;
- if (rtems_termios_dequeue_characters( d->termios_data, 1) == 0) {
- if (c->pDeviceFlow != &ns16550_flow_RTSCTS) {
- ns16550_negate_RTS(minor);
- }
+ /* Dequeue transmitted characters */
+ if (rtems_termios_dequeue_characters( d->termios_data, chars) == 0) {
+ /* Nothing to do */
d->bActive = false;
- ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
- break;
+ ns16550_enable_interrupts( minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
}
}
+ } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
+}
+#endif
+
+/**
+ * @brief Transmits up to @a len characters from @a buf.
+ *
+ * This routine is invoked either from task context with disabled interrupts to
+ * start a new transmission process with exactly one character in case of an
+ * idle output state or from the interrupt handler to refill the transmitter.
+ *
+ * Returns always zero.
+ */
+NS16550_STATIC int ns16550_write_support_int(
+ int minor,
+ const char *buf,
+ int len
+)
+{
+ console_tbl *c = &Console_Port_Tbl [minor];
+ console_data *d = &Console_Port_Data [minor];
+ ns16550_context *ctx = d->pDeviceContext;
+ uint32_t port = c->ulCtrlPort1;
+ setRegister_f set = c->setRegister;
+ int i = 0;
+ int out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
+
+ for (i = 0; i < out; ++i) {
+ set( port, NS16550_TRANSMIT_BUFFER, buf [i]);
+ }
+
+ if (len > 0) {
+ ctx->transmitFifoChars = out;
+ d->bActive = true;
+ ns16550_enable_interrupts( minor, NS16550_ENABLE_ALL_INTR);
+ }
- ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID);
- } while((ucInterruptId&0xf)!=0x1);
+ return 0;
}
/*
@@ -521,8 +555,6 @@ NS16550_STATIC void ns16550_process(int minor)
*
* This routine initializes the port to have the specified interrupts masked.
*/
-#endif
-
NS16550_STATIC void ns16550_enable_interrupts(
int minor,
int mask
@@ -622,48 +654,6 @@ NS16550_STATIC void ns16550_initialize_interrupts( int minor)
}
/*
- * ns16550_write_support_int
- *
- * Console Termios output entry point.
- */
-
-NS16550_STATIC int ns16550_write_support_int(
- int minor,
- const char *buf,
- int len
-)
-{
- uint32_t Irql;
- uint32_t pNS16550;
- setRegister_f setReg;
-
- setReg = Console_Port_Tbl[minor].setRegister;
- pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1;
-
- /*
- * We are using interrupt driven output and termios only sends us
- * one character at a time.
- */
-
- if ( !len )
- return 0;
-
- if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
- ns16550_assert_RTS(minor);
- }
-
- 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;
-}
-
-/*
* ns16550_write_support_polled
*
* Console Termios output entry point.
diff --git a/c/src/libchip/serial/ns16550_p.h b/c/src/libchip/serial/ns16550_p.h
index 480d3ea5e1..a32b46f969 100644
--- a/c/src/libchip/serial/ns16550_p.h
+++ b/c/src/libchip/serial/ns16550_p.h
@@ -29,24 +29,11 @@ extern "C" {
#define NS16550_STATIC static
-/*
- * Define serial port read registers structure.
- */
-
-typedef volatile struct _SP_READ_REGISTERS {
- unsigned char ReceiveBuffer;
- unsigned char InterruptEnable;
- unsigned char InterruptId;
- unsigned char LineControl;
- unsigned char ModemControl;
- unsigned char LineStatus;
- unsigned char ModemStatus;
- unsigned char ScratchPad;
-} SP_READ_REGISTERS, *PSP_READ_REGISTERS;
-
#define NS16550_RECEIVE_BUFFER 0
+#define NS16550_TRANSMIT_BUFFER 0
#define NS16550_INTERRUPT_ENABLE 1
#define NS16550_INTERRUPT_ID 2
+#define NS16550_FIFO_CONTROL 2
#define NS16550_LINE_CONTROL 3
#define NS16550_MODEM_CONTROL 4
#define NS16550_LINE_STATUS 5
@@ -54,24 +41,6 @@ typedef volatile struct _SP_READ_REGISTERS {
#define NS16550_SCRATCH_PAD 7
/*
- * Define serial port write registers structure.
- */
-
-typedef volatile struct _SP_WRITE_REGISTERS {
- unsigned char TransmitBuffer;
- unsigned char InterruptEnable;
- unsigned char FifoControl;
- unsigned char LineControl;
- unsigned char ModemControl;
- unsigned char Reserved1;
- unsigned char ModemStatus;
- unsigned char ScratchPad;
-} SP_WRITE_REGISTERS, *PSP_WRITE_REGISTERS;
-
-#define NS16550_TRANSMIT_BUFFER 0
-#define NS16550_FIFO_CONTROL 2
-
-/*
* Define serial port interrupt enable register structure.
*/
@@ -85,15 +54,13 @@ typedef volatile struct _SP_WRITE_REGISTERS {
#define NS16550_ENABLE_ALL_INTR_EXCEPT_TX (SP_INT_RX_ENABLE)
/*
- * Define serial port interrupt id register structure.
+ * Define serial port interrupt ID register structure.
*/
-typedef struct _SP_INTERRUPT_ID {
- unsigned char InterruptPending : 1;
- unsigned char Identification : 3;
- unsigned char Reserved1 : 2;
- unsigned char FifoEnabled : 2;
-} SP_INTERRUPT_ID, *PSP_INTERRUPT_ID;
+#define SP_IID_0 0x01
+#define SP_IID_1 0x02
+#define SP_IID_2 0x04
+#define SP_IID_3 0x08
/*
* Define serial port fifo control register structure.
@@ -105,6 +72,8 @@ typedef struct _SP_INTERRUPT_ID {
#define SP_FIFO_DMA 0x08
#define SP_FIFO_RXLEVEL 0xc0
+#define SP_FIFO_SIZE 16
+
/*
* Define serial port line control register structure.
*/
@@ -156,9 +125,9 @@ typedef struct _SP_INTERRUPT_ID {
#define SP_LSR_TX 0x40
#define SP_LSR_EFIFO 0x80
-typedef struct _ns16550_context
-{
- uint8_t ucModemCtrl;
+typedef struct {
+ uint8_t ucModemCtrl;
+ int transmitFifoChars;
} ns16550_context;
/*