summaryrefslogtreecommitdiffstats
path: root/c/src/libchip/serial/ns16550.c
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2008-09-22 11:46:15 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2008-09-22 11:46:15 +0000
commite97e0e0886a2075ef1be095e0a07f0e7a15e8b12 (patch)
treef7f50f2530677edfd1ab0c599283bb3fe63680b1 /c/src/libchip/serial/ns16550.c
parentInclude required header files. Some internal functions have now static linka... (diff)
downloadrtems-e97e0e0886a2075ef1be095e0a07f0e7a15e8b12.tar.bz2
Include required header files. Removed support for old PowerPC exception handling. Various fixes for interrupt related routines. Added support for BSPs with IRQ extension API.
Diffstat (limited to 'c/src/libchip/serial/ns16550.c')
-rw-r--r--c/src/libchip/serial/ns16550.c268
1 files changed, 126 insertions, 142 deletions
diff --git a/c/src/libchip/serial/ns16550.c b/c/src/libchip/serial/ns16550.c
index 32f7f5b467..58dd7909be 100644
--- a/c/src/libchip/serial/ns16550.c
+++ b/c/src/libchip/serial/ns16550.c
@@ -20,16 +20,33 @@
* This driver uses the termios pseudo driver.
*/
+#include <stdlib.h>
+
#include <rtems.h>
#include <rtems/libio.h>
-#include <stdlib.h>
#include <rtems/ringbuf.h>
+#include <rtems/bspIo.h>
#include <libchip/serial.h>
#include <libchip/sersupp.h>
-#include <rtems/bspIo.h>
+
+#include <bsp/irq.h>
+
#include "ns16550_p.h"
+#ifdef BSP_FEATURE_IRQ_EXTENSION
+ /* Nothing to do */
+#elif defined BSP_FEATURE_IRQ_LEGACY
+ /* Nothing to do */
+#elif defined __PPC__
+ #define BSP_FEATURE_IRQ_LEGACY
+ #ifdef BSP_SHARED_HANDLER_SUPPORT
+ #define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+ #endif
+#else
+ #warning No interrupt support available
+#endif
+
/*
* Flow control is only supported when using interrupts
*/
@@ -68,14 +85,6 @@ console_fns ns16550_fns_polled = {
false /* deviceOutputUsesInterrupts */
};
-#if defined(__PPC__)
-#ifdef _OLD_EXCEPTIONS
-extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
-#else
-#include <bsp/irq.h>
-#endif
-#endif
-
/*
* ns16550_init
*/
@@ -92,6 +101,11 @@ NS16550_STATIC void ns16550_init(int minor)
pns16550Context=(ns16550_context *)malloc(sizeof(ns16550_context));
+ if (pns16550Context == NULL) {
+ printk( "%s: Error: Not enough memory\n", __func__);
+ rtems_fatal_error_occurred( 0xdeadbeef);
+ }
+
Console_Port_Data[minor].pDeviceContext=(void *)pns16550Context;
pns16550Context->ucModemCtrl=SP_MODEM_IRQ;
@@ -117,8 +131,8 @@ NS16550_STATIC void ns16550_init(int minor)
(*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
/* XXX */
- (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
- (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
+ (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, (uint8_t) (ulBaudDivisor & 0xffU));
+ (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (uint8_t) ((ulBaudDivisor >> 8) & 0xffU));
/* Clear the divisor latch and set the character size to eight bits */
/* with one stop bit and no parity checking. */
@@ -441,10 +455,11 @@ NS16550_STATIC int ns16550_set_attributes(
* This routine is the console interrupt handler for A port.
*/
-NS16550_STATIC void ns16550_process(
- int minor
-)
+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;
@@ -452,22 +467,22 @@ NS16550_STATIC void ns16550_process(
getRegister_f getReg;
setRegister_f setReg;
- pNS16550 = Console_Port_Tbl[minor].ulCtrlPort1;
- getReg = Console_Port_Tbl[minor].getRegister;
- setReg = Console_Port_Tbl[minor].setRegister;
+ pNS16550 = c->ulCtrlPort1;
+ getReg = c->getRegister;
+ setReg = c->setRegister;
do {
/*
* Deal with any received characters
*/
- while(true) {
+ while (true) {
ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
- if(~ucLineStatus & SP_LSR_RDY) {
+ if (~ucLineStatus & SP_LSR_RDY) {
break;
}
cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
rtems_termios_enqueue_raw_characters(
- Console_Port_Data[minor].termios_data,
+ d->termios_data,
&cChar,
1
);
@@ -477,82 +492,31 @@ NS16550_STATIC void ns16550_process(
* TX all the characters we can
*/
- 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;
- }
-
-#if 0
- /* XXX flow control not completely supported in libchip */
-
- if(Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
- ns16550_negate_RTS(minor);
- }
-#endif
+ 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;
+ }
- rtems_termios_dequeue_characters(Console_Port_Data[minor].termios_data, 1);
- if (rtems_termios_dequeue_characters(
- Console_Port_Data[minor].termios_data, 1)) {
- if (Console_Port_Tbl[minor].pDeviceFlow != &ns16550_flow_RTSCTS) {
+ if (rtems_termios_dequeue_characters( d->termios_data, 1) == 0) {
+ if (c->pDeviceFlow != &ns16550_flow_RTSCTS) {
ns16550_negate_RTS(minor);
}
- Console_Port_Data[minor].bActive = FALSE;
+ d->bActive = false;
ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
break;
}
-
- ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID);
- }
- } while((ucInterruptId&0xf)!=0x1);
-}
-
-#if defined(__PPC__)
-#ifdef _OLD_EXCEPTIONS
-
-/*
- * ns16550_isr
- */
-
-NS16550_STATIC rtems_isr ns16550_isr(
- rtems_vector_number vector
-)
-{
- int minor;
-
- for(minor=0;minor<Console_Port_Count;minor++) {
- if(Console_Port_Tbl[minor].ulIntVector == vector &&
- Console_Port_Tbl[minor].deviceType == SERIAL_NS16550 ) {
- ns16550_process(minor);
}
- }
-}
-
-#else
-
-NS16550_STATIC rtems_isr ns16550_isr(
- void *entry
-)
-{
- console_tbl *ptr = entry;
- int minor;
-
- for(minor=0;minor<Console_Port_Count;minor++) {
- if( &Console_Port_Tbl[minor] == ptr ) {
- ns16550_process(minor);
- }
- }
+ ucInterruptId = (*getReg)(pNS16550, NS16550_INTERRUPT_ID);
+ } while((ucInterruptId&0xf)!=0x1);
}
-#endif
-#endif
-
/*
* ns16550_enable_interrupts
*
@@ -573,68 +537,88 @@ NS16550_STATIC void ns16550_enable_interrupts(
(*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
}
+#ifdef BSP_FEATURE_IRQ_EXTENSION
+ NS16550_STATIC void ns16550_isr( rtems_vector_number vector, void *arg)
+ {
+ int minor = (int) arg;
+
+ ns16550_process( minor);
+ }
+#elif defined BSP_FEATURE_IRQ_LEGACY
+ NS16550_STATIC rtems_isr ns16550_isr( void *arg)
+ {
+ int minor = (int) arg;
+
+ ns16550_process( minor);
+ }
+#endif
+
/*
* ns16550_initialize_interrupts
*
* This routine initializes the port to operate in interrupt driver mode.
*/
-
-#if defined(__PPC__)
-#ifdef _OLD_EXCEPTIONS
-NS16550_STATIC void ns16550_initialize_interrupts(int minor)
+NS16550_STATIC void ns16550_initialize_interrupts( int minor)
{
- ns16550_init(minor);
-
- Console_Port_Data[minor].bActive = FALSE;
-
- set_vector(ns16550_isr, Console_Port_Tbl[minor].ulIntVector, 1);
+ console_tbl *c = &Console_Port_Tbl [minor];
+ console_data *d = &Console_Port_Data [minor];
+
+ ns16550_init( minor);
+
+ d->bActive = false;
+
+ #ifdef BSP_FEATURE_IRQ_EXTENSION
+ {
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ sc = rtems_interrupt_handler_install(
+ c->ulIntVector,
+ "NS16550",
+ RTEMS_INTERRUPT_SHARED,
+ ns16550_isr,
+ (void *) minor
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ /* FIXME */
+ printk( "%s: Error: Install interrupt handler\n", __func__);
+ rtems_fatal_error_occurred( 0xdeadbeef);
+ }
+ }
+ #elif defined BSP_FEATURE_IRQ_LEGACY
+ {
+ int rv = 0;
+ #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
+ rtems_irq_connect_data cd = {
+ c->ulIntVector,
+ ns16550_isr,
+ (void *) minor
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+ rv = BSP_install_rtems_shared_irq_handler( &cd);
+ #else
+ rtems_irq_connect_data cd = {
+ c->ulIntVector,
+ ns16550_isr,
+ (void *) minor
+ NULL,
+ NULL,
+ NULL
+ };
+ rv = BSP_install_rtems_irq_handler( &cd);
+ #endif
+ if (rv == 0) {
+ /* FIXME */
+ printk( "%s: Error: Install interrupt handler\n", __func__);
+ rtems_fatal_error_occurred( 0xdeadbeef);
+ }
+ }
+ #endif
- ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR);
-}
-#else
-
-NS16550_STATIC void ns16550_initialize_interrupts(int minor)
-{
-#ifdef BSP_SHARED_HANDLER_SUPPORT
- rtems_irq_connect_data IrqData = {0,
- ns16550_isr,
- &Console_Port_Data[minor],
- NULL,
- NULL,
- NULL,
- NULL
- };
-#else
- rtems_irq_connect_data IrqData = {0,
- ns16550_isr,
- &Console_Port_Data[minor],
- NULL,
- NULL,
- NULL
- };
-#endif
-
- ns16550_init(minor);
-
- Console_Port_Data[minor].bActive = FALSE;
-
- IrqData.name = (rtems_irq_number)(Console_Port_Tbl[minor].ulIntVector );
-
-#ifdef BSP_SHARED_HANDLER_SUPPORT
- if (!BSP_install_rtems_shared_irq_handler (&IrqData)) {
-#else
- if (!BSP_install_rtems_irq_handler(&IrqData)) {
-#endif
- printk("Error installing interrupt handler!\n");
- rtems_fatal_error_occurred(1);
- }
-
- ns16550_enable_interrupts(minor, NS16550_ENABLE_ALL_INTR);
+ ns16550_enable_interrupts( minor, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
}
-#endif
-#endif
-
/*
* ns16550_write_support_int
*
@@ -667,8 +651,8 @@ NS16550_STATIC int ns16550_write_support_int(
}
rtems_interrupt_disable(Irql);
- if ( Console_Port_Data[minor].bActive == FALSE) {
- Console_Port_Data[minor].bActive = TRUE;
+ 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);