diff options
Diffstat (limited to 'c/src/lib/libbsp/powerpc/mbx8xx/console/console.c')
-rw-r--r-- | c/src/lib/libbsp/powerpc/mbx8xx/console/console.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/mbx8xx/console/console.c b/c/src/lib/libbsp/powerpc/mbx8xx/console/console.c new file mode 100644 index 0000000000..c152d17321 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mbx8xx/console/console.c @@ -0,0 +1,484 @@ +/* + * console.c + * + * This file contains the MBX8xx termios serial I/O package. + * Only asynchronous I/O is supported. + * + * The SCCs and SMCs are assigned as follows + * + * Channel Device Minor Note + * SMC1 /dev/tty0 0 + * SMC2 /dev/tty1 1 + * SCC1 2 N/A. Hardwired as ethernet port + * SCC2 /dev/tty2 3 + * SCC3 /dev/tty3 4 + * SCC4 /dev/tty4 5 + * + * All ports support termios. All I/O is interrupt-driven, unless EPPCBug + * is used to do the I/O. To use EPPCBug, define the EPPCBUG_SMC1 + * manifest constant in the configuration file (mbx8xx.cfg). EPPCBug I/O + * is currently limited to the EPPCBug debug console. This is a limitation + * of firmware revision 1.1. Later firmware should be able to do I/O + * through any port.This code assumes that the EPPCBug console is the + * default: SMC1. + * + * TO RUN THE TESTS, USE POLLED I/O THROUGH EPPCBUG. Some tests play with + * the interrupt masks and turn off I/O. Those tests will hang with when + * interrupt-driven I/O is used. + * + * Set CONSOLE_MINOR to the appropriate device minor number in the + * config file. This allows the RTEMS application console to be different + * from the EPPBug debug console or the GDB stup I/O port. + * + * This driver handles all five available serial ports: it distinguishes + * the sub-devices using minor device numbers. It is not possible to have + * other protocols running on the other ports when this driver is used as + * currently written. + * + * Based on code (alloc860.c in eth_comm port) by + * Jay Monkman (jmonkman@frasca.com), + * Copyright (C) 1998 by Frasca International, Inc. + * + * Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca> + * and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>. + * Copyright (c) 1999, National Research Council of Canada + * + */ +#include <stdarg.h> +#include <stdio.h> +#include <bsp.h> /* Must be before libio.h */ +#include <rtems/libio.h> +#include <termios.h> + +static int _EPPCBug_pollRead( int minor ); +static int _EPPCBug_pollWrite( int minor, const char *buf, int len ); + + +/* + * _EPPCBug_pollRead + * + * Read a character from the EPPCBug console, and return it. Return -1 + * if there is no character in the input FIFO. + * + * Input parameters: + * minor - selected channel + * + * Output parameters: NONE + * + * Return value: char returned as positive signed int + * -1 if no character is present in the input FIFO. + */ +int _EPPCBug_pollRead( + int minor +) +{ + extern volatile m8xx_t m8xx; + + char c; + volatile int simask; /* We must read and write m8xx.simask */ + int retval; + ISR_Level level; + + struct { + int clun; + int dlun; + char * inbuf; + int nbytes_requested; + int reserved; + } volatile input_params; + + struct { + int status; + union { + struct { + int input_char_available; + int output_possible; + int break_detected; + int modem_status; + } stat; + struct { + int nbytes_received; + } read; + } u; + } volatile output_params; + + retval = -1; + + /* Input through EPPCBug console */ + input_params.clun = 0; + input_params.dlun = 0; + input_params.reserved = 0; + + _ISR_Disable( level ); + simask = m8xx.simask; + + /* Check for a char in the input FIFO using .CIO_STAT */ + asm volatile( "li 10,0x202 + mr 3, %0 + mr 4, %1 + sc" + :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" ); + + if ( (output_params.status == 0) && output_params.u.stat.input_char_available) { + + /* Read the char and return it */ + input_params.inbuf = &c; + input_params.nbytes_requested = 1; + + asm volatile( "li 10,0x200 /* Code for .CIO_READ */ + mr 3, %0 /* Address of input_params */ + mr 4, %1 /* Address of output_params */ + sc" /* Call EPPCBUG */ + :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" ); + + if ( (output_params.status == 0) && output_params.u.read.nbytes_received) + retval = (int)c; + } + + m8xx.simask = simask; + _ISR_Enable( level ); + return retval; +} + + +/* + * _EPPCBug_pollWrite + * + * Output buffer through EPPCBug. Returns only once every character has been + * sent (polled output). + * + * Input parameters: + * minor - selected channel + * buf - output buffer + * len - number of chars to output + * + * Output parameters: NONE + * + * Return value: IGNORED + */ +int _EPPCBug_pollWrite( + int minor, + const char *buf, + int len +) +{ + extern volatile m8xx_t m8xx; + + volatile int simask; + int i, retval; + ISR_Level level; + + struct { + int clun; + int dlun; + const char * outbuf; + int nbytes_to_output; + int reserved; + } volatile input_params; + + struct { + int status; + union { + struct { + int input_char_available; + int output_possible; + int break_detected; + int modem_status; + } stat; + struct { + int nbytes_sent; + } write; + } u; + } volatile output_params; + + retval = -1; + + /* Output through EPPCBug console */ + input_params.clun = 0; + input_params.dlun = 0; + input_params.reserved = 0; + + i = 0; + + _ISR_Disable( level ); + simask = m8xx.simask; + + while (i < len) { + /* Wait for space in the output buffer */ + do { + /* Check for space in the output FIFO */ + asm volatile( "li 10,0x202 /* Code for .CIO_STAT */ + mr 3, %0 /* Address of input_params */ + mr 4, %1 /* Address of output_params */ + sc" /* Call EPPCBUG */ + :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" ); + + if (output_params.status) + goto error; + } while (!output_params.u.stat.output_possible); + + /* Output the characters until done */ + input_params.outbuf = &buf[i]; + input_params.nbytes_to_output = len - i; + + asm volatile( "li 10,0x201 /* Code for .CIO_WRITE */ + mr 3, %0 /* Address of input_params */ + mr 4, %1 /* Address of output_params */ + sc" /* Call EPPCBUG */ + :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" ); + + if (output_params.status) + goto error; + + i += output_params.u.write.nbytes_sent; + } + + /* Return something */ + m8xx.simask = simask; + _ISR_Enable( level ); + return RTEMS_SUCCESSFUL; + +error: + m8xx.simask = simask; + _ISR_Enable( level ); + return -1; +} + + +/* + * Print functions: prototyped in bsp.h + * Debug printing on Channel 1 + */ + +void printk( char *fmt, ... ) +{ + va_list ap; /* points to each unnamed argument in turn */ + static char buf[256]; + unsigned int level; + + _CPU_ISR_Disable(level); + + va_start(ap, fmt); /* make ap point to 1st unnamed arg */ + vsprintf(buf, fmt, ap); /* send output to buffer */ + + BSP_output_string(buf); /* print buffer -- Channel 1 */ + + va_end(ap); /* clean up and re-enable interrupts */ + _CPU_ISR_Enable(level); +} + + +void BSP_output_string( char * buf ) +{ + int len = strlen(buf); + int minor; /* will be ignored */ + rtems_status_code sc; + + sc = _EPPCBug_pollWrite(minor, buf, len); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); +} + + +/* + *************** + * BOILERPLATE * + *************** + * + * All these functions are prototyped in rtems/c/src/lib/include/console.h. + */ + +/* + * Initialize and register the device + */ +rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + + /* + * Set up TERMIOS + */ + rtems_termios_initialize(); + + /* + * Do common initialization. + */ + m8xx_uart_initialize(); + + /* + * Do device-specific initialization + */ +#ifndef EPPCBUG_SMC1 + m8xx_uart_smc_initialize(SMC1_MINOR); /* /dev/tty0 */ +#endif /* EPPCBUG_SMC1 */ + + m8xx_uart_smc_initialize(SMC2_MINOR); /* /dev/tty1 */ + m8xx_uart_scc_initialize(SCC2_MINOR); /* /dev/tty2 */ + +#ifdef mpc860 + m8xx_uart_scc_initialize(SCC3_MINOR); /* /dev/tty3 */ + m8xx_uart_scc_initialize(SCC4_MINOR); /* /dev/tty4 */ +#endif /* mpc860 */ + + /* + * Set up interrupts + */ + m8xx_uart_interrupts_initialize(); + + status = rtems_io_register_name ("/dev/tty0", major, SMC1_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + status = rtems_io_register_name ("/dev/tty1", major, SMC2_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + status = rtems_io_register_name ("/dev/tty2", major, SCC2_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + +#ifdef mpc860 + status = rtems_io_register_name ("/dev/tty3", major, SCC3_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + status = rtems_io_register_name ("/dev/tty4", major, SCC4_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + +#endif /* mpc860 */ + + /* Now register the RTEMS console */ + status = rtems_io_register_name ("/dev/console", major, CONSOLE_MINOR); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (status); + + return RTEMS_SUCCESSFUL; +} + + +/* + * Open the device + */ +rtems_device_driver console_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + /* Used to track termios private data for callbacks */ + extern struct rtems_termios_tty *ttyp[]; + + volatile m8xxSCCRegisters_t *sccregs; + rtems_status_code sc; + rtems_libio_open_close_args_t *args = arg; + +#ifdef EPPCBUG_SMC1 + static const rtems_termios_callbacks sccEPPCBugCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + _EPPCBug_pollRead, /* pollRead */ + _EPPCBug_pollWrite, /* write */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; +#endif + +#ifdef UARTS_USE_INTERRUPTS + static const rtems_termios_callbacks intrCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + NULL, /* pollRead */ + m8xx_uart_write, /* write */ + m8xx_uart_setAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 1 /* outputUsesInterrupts */ + }; +#else + static const rtems_termios_callbacks pollCallbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + m8xx_uart_pollRead, /* pollRead */ + m8xx_uart_pollWrite, /* write */ + m8xx_uart_setAttributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 0 /* outputUsesInterrupts */ + }; +#endif + + if ( (minor < SMC1_MINOR) || (minor > NUM_PORTS-1) ) + return RTEMS_INVALID_NUMBER; + +#ifdef EPPCBUG_SMC1 + if (minor == SMC1_MINOR) + return rtems_termios_open (major, minor, arg, &sccEPPCBugCallbacks); +#endif /* EPPCBUG_SMC1 */ + +#ifdef UARTS_USE_INTERRUPTS + sc = rtems_termios_open (major, minor, arg, &intrCallbacks); + ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */ +#else + sc = rtems_termios_open (major, minor, arg, &pollCallbacks); +#endif + return sc; +} + + +/* + * Close the device + */ +rtems_device_driver console_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + return rtems_termios_close (arg); +} + + +/* + * Read from the device + */ +rtems_device_driver console_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + return rtems_termios_read(arg); +} + + +/* + * Write to the device + */ +rtems_device_driver console_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + return rtems_termios_write(arg); +} + + +/* + * Handle ioctl request. + */ +rtems_device_driver console_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + return rtems_termios_ioctl (arg); +} + |