Move the APBUART console driver support to the shared SPARC area so that it can be reused by other BSPs. Only the console driver initialization is now BSP specific. --- c/src/lib/libbsp/sparc/leon3/Makefile.am | 7 +- c/src/lib/libbsp/sparc/leon3/console/console.c | 349 ++------------------ c/src/lib/libbsp/sparc/leon3/preinstall.am | 4 + .../libbsp/sparc/shared/include/apbuart_termios.h | 40 +++ .../lib/libbsp/sparc/shared/uart/apbuart_termios.c | 240 ++++++++++++++ 5 files changed, 315 insertions(+), 325 deletions(-) create mode 100644 c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h create mode 100644 c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am index 5dd43c3..6da563b 100644 --- a/c/src/lib/libbsp/sparc/leon3/Makefile.am +++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am @@ -65,6 +65,7 @@ libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_old.c libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_names.c libbsp_a_SOURCES += ../../sparc/shared/amba/ambapp_show.c # console +libbsp_a_SOURCES += ../../shared/console-termios.c libbsp_a_SOURCES += console/console.c # debugio libbsp_a_SOURCES += console/printk_support.c @@ -109,9 +110,11 @@ libbsp_a_SOURCES += ../../sparc/shared/spw/grspw.c \ # UART include_HEADERS += ../../sparc/shared/include/apbuart.h \ - ../../sparc/shared/include/apbuart_pci.h + ../../sparc/shared/include/apbuart_pci.h \ + ../../sparc/shared/include/apbuart_termios.h libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart.c \ - ../../sparc/shared/uart/apbuart_pci.c + ../../sparc/shared/uart/apbuart_pci.c \ + ../../sparc/shared/uart/apbuart_termios.c # I2CMST include_HEADERS += ../../sparc/shared/include/i2cmst.h diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c index 989d1cf..9012492 100644 --- a/c/src/lib/libbsp/sparc/leon3/console/console.c +++ b/c/src/lib/libbsp/sparc/leon3/console/console.c @@ -28,34 +28,17 @@ #include <bsp.h> #include <bsp/fatal.h> -#include <rtems/libio.h> -#include <stdlib.h> -#include <assert.h> -#include <rtems/bspIo.h> -#include <leon.h> -#include <rtems/termiostypes.h> -#include <apbuart.h> +#include <apbuart_termios.h> int syscon_uart_index __attribute__((weak)) = 0; /* body is in debugputs.c */ - -struct apbuart_priv { - struct apbuart_regs *regs; - unsigned int freq_hz; -#if CONSOLE_USE_INTERRUPTS - int irq; - void *cookie; - volatile int sending; - char *buf; -#endif -}; -static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS]; +static struct apbuart_context apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS]; static int uarts = 0; -static struct apbuart_priv *leon3_console_get_uart(int minor) +static struct apbuart_context *leon3_console_get_uart(int minor) { - struct apbuart_priv *uart; + struct apbuart_context *uart; if (minor == 0) uart = &apbuarts[syscon_uart_index]; @@ -65,160 +48,6 @@ static struct apbuart_priv *leon3_console_get_uart(int minor) return uart; } -#if CONSOLE_USE_INTERRUPTS - -/* Handle UART interrupts */ -static void leon3_console_isr(void *arg) -{ - struct apbuart_priv *uart = arg; - unsigned int status; - char data; - - /* Get all received characters */ - while ((status=uart->regs->status) & APBUART_STATUS_DR) { - /* Data has arrived, get new data */ - data = uart->regs->data; - - /* Tell termios layer about new character */ - rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1); - } - - if ( - (status & APBUART_STATUS_TE) - && (uart->regs->ctrl & APBUART_CTRL_TI) != 0 - ) { - /* write_interrupt will get called from this function */ - rtems_termios_dequeue_characters(uart->cookie, 1); - } -} - -/* - * Console Termios Write-Buffer Support Entry Point - * - */ -static int leon3_console_write_support(int minor, const char *buf, size_t len) -{ - struct apbuart_priv *uart = leon3_console_get_uart(minor); - int sending; - - if (len > 0) { - /* Enable TX interrupt (interrupt is edge-triggered) */ - uart->regs->ctrl |= APBUART_CTRL_TI; - - /* start UART TX, this will result in an interrupt when done */ - uart->regs->data = *buf; - - sending = 1; - } else { - /* No more to send, disable TX interrupts */ - uart->regs->ctrl &= ~APBUART_CTRL_TI; - - /* Tell close that we sent everything */ - sending = 0; - } - - uart->sending = sending; - - return 0; -} - -#else - -/* - * Console Termios Support Entry Points - */ -static ssize_t leon3_console_write_polled( - int minor, - const char *buf, - size_t len -) -{ - struct apbuart_priv *uart = leon3_console_get_uart(minor); - int nwrite = 0; - - while (nwrite < len) { - apbuart_outbyte_polled(uart->regs, *buf++, 1, 0); - nwrite++; - } - return nwrite; -} - -static int leon3_console_pollRead(int minor) -{ - struct apbuart_priv *uart = leon3_console_get_uart(minor); - - return apbuart_inbyte_nonblocking(uart->regs); -} - -#endif - -static int leon3_console_set_attributes(int minor, const struct termios *t) -{ - struct apbuart_priv *uart = leon3_console_get_uart(minor); - unsigned int scaler; - unsigned int ctrl; - int baud; - - switch (t->c_cflag & CSIZE) { - default: - case CS5: - case CS6: - case CS7: - /* Hardware doesn't support other than CS8 */ - return -1; - case CS8: - break; - } - - /* - * FIXME: This read-modify-write sequence is broken since interrupts may - * interfere. - */ - - /* Read out current value */ - ctrl = uart->regs->ctrl; - - switch (t->c_cflag & (PARENB|PARODD)) { - case (PARENB|PARODD): - /* Odd parity */ - ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS; - break; - - case PARENB: - /* Even parity */ - ctrl &= ~APBUART_CTRL_PS; - ctrl |= APBUART_CTRL_PE; - break; - - default: - case 0: - case PARODD: - /* No Parity */ - ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE); - } - - if (!(t->c_cflag & CLOCAL)) { - ctrl |= APBUART_CTRL_FL; - } else { - ctrl &= ~APBUART_CTRL_FL; - } - - /* Update new settings */ - uart->regs->ctrl = ctrl; - - /* Baud rate */ - baud = rtems_termios_baud_to_number(t->c_cflag); - if (baud > 0) { - /* Calculate Baud rate generator "scaler" number */ - scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10; - - /* Set new baud rate by setting scaler */ - uart->regs->scaler = scaler; - } - - return 0; -} - /* AMBA PP find routine. Extract AMBA PnP information into data structure. */ static int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg) { @@ -226,9 +55,7 @@ static int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg) /* Extract needed information of one APBUART */ apbuarts[uarts].regs = (struct apbuart_regs *)apb->start; -#if CONSOLE_USE_INTERRUPTS apbuarts[uarts].irq = apb->irq; -#endif /* Get APBUART core frequency, it is assumed that it is the same * as Bus frequency where the UART is situated */ @@ -251,17 +78,18 @@ static void leon3_console_scan_uarts(void) GAISLER_APBUART, find_matching_apbuart, NULL); } -/* - * Console Device Driver Entry Points - * - */ - rtems_device_driver console_initialize( rtems_device_major_number major, rtems_device_minor_number minor, void *arg ) { + const rtems_termios_device_handler *handler = +#if CONSOLE_USE_INTERRUPTS + &apbuart_handler_interrupt; +#else + &apbuart_handler_polled; +#endif rtems_status_code status; int i; char console_name[16]; @@ -297,7 +125,14 @@ rtems_device_driver console_initialize( * On a MP system one should not open UARTs that other OS instances use. */ if (syscon_uart_index < uarts) { - status = rtems_io_register_name("/dev/console", major, 0); + minor = 0; + status = rtems_termios_device_install( + CONSOLE_DEVICE_NAME, + major, + minor, + handler, + leon3_console_get_uart(syscon_uart_index) + ); if (status != RTEMS_SUCCESSFUL) bsp_fatal(LEON3_FATAL_CONSOLE_REGISTER_DEV); } @@ -306,147 +141,15 @@ rtems_device_driver console_initialize( if (i == syscon_uart_index) continue; /* skip UART that is registered as /dev/console */ console_name[13] = 'a' + i; - rtems_io_register_name( console_name, major, i+1); + minor = i + 1; + rtems_termios_device_install( + console_name, + major, + minor, + handler, + leon3_console_get_uart(syscon_uart_index) + ); } return RTEMS_SUCCESSFUL; } - -#if CONSOLE_USE_INTERRUPTS -static struct rtems_termios_tty *leon3_console_get_tty( - rtems_libio_open_close_args_t *args -) -{ - return args->iop->data1; -} -#endif - -static int leon3_console_first_open(int major, int minor, void *arg) -{ - struct apbuart_priv *uart = leon3_console_get_uart(minor); - -#if CONSOLE_USE_INTERRUPTS - rtems_status_code sc; - - uart->cookie = leon3_console_get_tty(arg); - - /* Register Interrupt handler */ - sc = rtems_interrupt_handler_install(uart->irq, "console", - RTEMS_INTERRUPT_SHARED, - leon3_console_isr, - uart); - if (sc != RTEMS_SUCCESSFUL) - return -1; - - uart->sending = 0; - /* Enable Receiver and transmitter and Turn on RX interrupts */ - uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE | - APBUART_CTRL_RI; -#else - /* Initialize UART on opening */ - uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE; -#endif - uart->regs->status = 0; - - return 0; -} - -#if CONSOLE_USE_INTERRUPTS -static int leon3_console_last_close(int major, int minor, void *arg) -{ - struct rtems_termios_tty *tty = leon3_console_get_tty(arg); - struct apbuart_priv *uart = leon3_console_get_uart(minor); - rtems_interrupt_lock_context lock_ctx; - - /* Turn off RX interrupts */ - rtems_termios_interrupt_lock_acquire(tty, &lock_ctx); - uart->regs->ctrl &= ~(APBUART_CTRL_RI); - rtems_termios_interrupt_lock_release(tty, &lock_ctx); - - /**** Flush device ****/ - while (uart->sending) { - /* Wait until all data has been sent */ - } - - /* uninstall ISR */ - rtems_interrupt_handler_remove(uart->irq, leon3_console_isr, uart); - - return 0; -} -#endif - -rtems_device_driver console_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ -#if CONSOLE_USE_INTERRUPTS - /* Interrupt mode routines */ - static const rtems_termios_callbacks Callbacks = { - leon3_console_first_open, /* firstOpen */ - leon3_console_last_close, /* lastClose */ - NULL, /* pollRead */ - leon3_console_write_support, /* write */ - leon3_console_set_attributes,/* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - 1 /* outputUsesInterrupts */ - }; -#else - /* Polling mode routines */ - static const rtems_termios_callbacks Callbacks = { - leon3_console_first_open, /* firstOpen */ - NULL, /* lastClose */ - leon3_console_pollRead, /* pollRead */ - leon3_console_write_polled, /* write */ - leon3_console_set_attributes,/* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - 0 /* outputUsesInterrupts */ - }; -#endif - - assert(minor <= uarts); - if (minor > uarts || minor == (syscon_uart_index + 1)) - return RTEMS_INVALID_NUMBER; - - return rtems_termios_open(major, minor, arg, &Callbacks); -} - -rtems_device_driver console_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_close(arg); -} - -rtems_device_driver console_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_read(arg); -} - -rtems_device_driver console_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_write(arg); -} - -rtems_device_driver console_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_ioctl(arg); -} - diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am index 33e9041..210558e 100644 --- a/c/src/lib/libbsp/sparc/leon3/preinstall.am +++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am @@ -157,6 +157,10 @@ $(PROJECT_INCLUDE)/apbuart_pci.h: ../../sparc/shared/include/apbuart_pci.h $(PRO $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_pci.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_pci.h +$(PROJECT_INCLUDE)/apbuart_termios.h: ../../sparc/shared/include/apbuart_termios.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/apbuart_termios.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/apbuart_termios.h + $(PROJECT_INCLUDE)/i2cmst.h: ../../sparc/shared/include/i2cmst.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/i2cmst.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/i2cmst.h diff --git a/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h b/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h new file mode 100644 index 0000000..4b54252 --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/include/apbuart_termios.h @@ -0,0 +1,40 @@ +/* + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * + * Modified for LEON3 BSP. + * COPYRIGHT (c) 2004. + * Gaisler Research. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef APBUART_TERMIOS_H +#define APBUART_TERMIOS_H + +#include <rtems/termiostypes.h> +#include <grlib.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct apbuart_context { + struct apbuart_regs *regs; + unsigned int freq_hz; + rtems_vector_number irq; + volatile int sending; + char *buf; +}; + +const rtems_termios_device_handler apbuart_handler_interrupt; + +const rtems_termios_device_handler apbuart_handler_polled; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* APBUART_TERMIOS_H */ diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c new file mode 100644 index 0000000..4b69e1b --- /dev/null +++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c @@ -0,0 +1,240 @@ +/* + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * + * Modified for LEON3 BSP. + * COPYRIGHT (c) 2004. + * Gaisler Research. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <apbuart_termios.h> +#include <apbuart.h> +#include <bsp.h> + +static void apbuart_isr(void *arg) +{ + rtems_termios_tty *tty = arg; + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + unsigned int status; + char data; + + /* Get all received characters */ + while ((status=uart->regs->status) & APBUART_STATUS_DR) { + /* Data has arrived, get new data */ + data = uart->regs->data; + + /* Tell termios layer about new character */ + rtems_termios_enqueue_raw_characters(tty, &data, 1); + } + + if ( + (status & APBUART_STATUS_TE) + && (uart->regs->ctrl & APBUART_CTRL_TI) != 0 + ) { + /* write_interrupt will get called from this function */ + rtems_termios_dequeue_characters(tty, 1); + } +} + +static void apbuart_write_support( + rtems_termios_tty *tty, + const char *buf, + size_t len +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + int sending; + + if (len > 0) { + /* Enable TX interrupt (interrupt is edge-triggered) */ + uart->regs->ctrl |= APBUART_CTRL_TI; + + /* start UART TX, this will result in an interrupt when done */ + uart->regs->data = *buf; + + sending = 1; + } else { + /* No more to send, disable TX interrupts */ + uart->regs->ctrl &= ~APBUART_CTRL_TI; + + /* Tell close that we sent everything */ + sending = 0; + } + + uart->sending = sending; +} + +static void apbuart_write_polled( + rtems_termios_tty *tty, + const char *buf, + size_t len +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + size_t nwrite = 0; + + while (nwrite < len) { + apbuart_outbyte_polled(uart->regs, *buf++, 1, 0); + nwrite++; + } +} + +static int apbuart_poll_read(rtems_termios_tty *tty) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + + return apbuart_inbyte_nonblocking(uart->regs); +} + +static bool apbuart_set_attributes( + rtems_termios_tty *tty, + const struct termios *t +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + rtems_interrupt_lock_context lock_context; + unsigned int scaler; + unsigned int ctrl; + int baud; + + switch (t->c_cflag & CSIZE) { + default: + case CS5: + case CS6: + case CS7: + /* Hardware doesn't support other than CS8 */ + return false; + case CS8: + break; + } + + rtems_termios_interrupt_lock_acquire(tty, &lock_context); + + /* Read out current value */ + ctrl = uart->regs->ctrl; + + switch (t->c_cflag & (PARENB|PARODD)) { + case (PARENB|PARODD): + /* Odd parity */ + ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS; + break; + + case PARENB: + /* Even parity */ + ctrl &= ~APBUART_CTRL_PS; + ctrl |= APBUART_CTRL_PE; + break; + + default: + case 0: + case PARODD: + /* No Parity */ + ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE); + } + + if (!(t->c_cflag & CLOCAL)) { + ctrl |= APBUART_CTRL_FL; + } else { + ctrl &= ~APBUART_CTRL_FL; + } + + /* Update new settings */ + uart->regs->ctrl = ctrl; + + rtems_termios_interrupt_lock_release(tty, &lock_context); + + /* Baud rate */ + baud = rtems_termios_baud_to_number(t->c_cflag); + if (baud > 0) { + /* Calculate Baud rate generator "scaler" number */ + scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10; + + /* Set new baud rate by setting scaler */ + uart->regs->scaler = scaler; + } + + return true; +} + +static bool apbuart_first_open_polled( + rtems_termios_tty *tty, + rtems_libio_open_close_args_t *args +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + + /* Initialize UART on opening */ + uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE; + uart->regs->status = 0; + + return true; +} + +static bool apbuart_first_open_interrupt( + rtems_termios_tty *tty, + rtems_libio_open_close_args_t *args +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + rtems_status_code sc; + + /* Register Interrupt handler */ + sc = rtems_interrupt_handler_install(uart->irq, "console", + RTEMS_INTERRUPT_SHARED, + apbuart_isr, + tty); + if (sc != RTEMS_SUCCESSFUL) + return false; + + uart->sending = 0; + /* Enable Receiver and transmitter and Turn on RX interrupts */ + uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE | + APBUART_CTRL_RI; + /* Initialize UART on opening */ + uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE; + uart->regs->status = 0; + + return true; +} + +static void apbuart_last_close_interrupt( + rtems_termios_tty *tty, + rtems_libio_open_close_args_t *args +) +{ + struct apbuart_context *uart = rtems_termios_get_device_context(tty); + rtems_interrupt_lock_context lock_context; + + /* Turn off RX interrupts */ + rtems_termios_interrupt_lock_acquire(tty, &lock_context); + uart->regs->ctrl &= ~(APBUART_CTRL_RI); + rtems_termios_interrupt_lock_release(tty, &lock_context); + + /**** Flush device ****/ + while (uart->sending) { + /* Wait until all data has been sent */ + } + + /* uninstall ISR */ + rtems_interrupt_handler_remove(uart->irq, apbuart_isr, tty); +} + +const rtems_termios_device_handler apbuart_handler_interrupt = { + .first_open = apbuart_first_open_interrupt, + .last_close = apbuart_last_close_interrupt, + .write = apbuart_write_support, + .set_attributes = apbuart_set_attributes, + .mode = TERMIOS_IRQ_DRIVEN +}; + +const rtems_termios_device_handler apbuart_handler_polled = { + .first_open = apbuart_first_open_polled, + .poll_read = apbuart_poll_read, + .write = apbuart_write_polled, + .set_attributes = apbuart_set_attributes, + .mode = TERMIOS_POLLED +}; -- 1.7.7 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel