diff options
Diffstat (limited to 'bsps/i386/pc386/console/tty_drv.c')
-rw-r--r-- | bsps/i386/pc386/console/tty_drv.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/bsps/i386/pc386/console/tty_drv.c b/bsps/i386/pc386/console/tty_drv.c new file mode 100644 index 0000000000..121820061a --- /dev/null +++ b/bsps/i386/pc386/console/tty_drv.c @@ -0,0 +1,413 @@ +/*************************************************************************** + * + * MODULE DESCRIPTION: + * This module implements the RTEMS drivers for the PC serial ports + * as /dev/ttyS1 for COM1 and /dev/ttyS2 as COM2. If one of the ports + * is used as the console, this driver would fail to initialize. + * + * This code was based on the console driver. It is based on the + * current termios framework. This is just a shell around the + * termios support. + * + * by: Rosimildo da Silva: + * rdasilva@connecttel.com + * http://www.connecttel.com + * + ****************************************************************************/ + + +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/bspIo.h> +#include <rtems/libio.h> +#include <rtems/termiostypes.h> +#include <termios.h> +#include <uart.h> +#include <libcpu/cpuModel.h> +#include <bsp/tty_drv.h> + +int BSP_poll_read(int); + +/* Internal routines */ +static int tty1_conSetAttr( int minor, const struct termios *t); +static int tty2_conSetAttr( int minor, const struct termios *t); + +extern BSP_polling_getchar_function_type BSP_poll_char; +extern int BSPConsolePort; +extern void rtems_set_waiting_id_comx( int port, rtems_id id, rtems_event_set event ); + +/* + * TTYS1 - device driver INITIALIZE entry point. + */ +rtems_device_driver +tty1_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; + + /* Check if this port is not been used as console */ + if( BSPConsolePort == BSP_UART_COM1 ) + { + status = -1; + printk("TTYS1: port selected as console.\n"); + rtems_fatal_error_occurred( status ); + } + + /* + * Set up TERMIOS + */ + rtems_termios_initialize(); + + /* + * Do device-specific initialization + */ + /* 9600-8-N-1, without hardware flow control */ + BSP_uart_init( BSP_UART_COM1, 9600, CHR_8_BITS, 0, 0, 0 ); + status = rtems_interrupt_handler_install( + BSP_UART_COM1_IRQ, + "tty_drv", + RTEMS_INTERRUPT_UNIQUE, + BSP_uart_termios_isr_com1, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + /* + * Register the device + */ + status = rtems_io_register_name ("/dev/ttyS1", major, 0); + if (status != RTEMS_SUCCESSFUL) + { + printk("Error registering ttyS1 device!\n"); + rtems_fatal_error_occurred (status); + } + printk("Device: /dev/ttyS1 initialized.\n"); + return RTEMS_SUCCESSFUL; +} /* tty_initialize */ + +static int tty1_last_close(int major, int minor, void *arg) +{ + rtems_status_code status; + + status = rtems_interrupt_handler_remove( + BSP_UART_COM1_IRQ, + BSP_uart_termios_isr_com1, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + return 0; +} + +/* + * TTY1 - device driver OPEN entry point + */ +rtems_device_driver +tty1_open(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; +#ifndef USE_TASK_DRIVEN + static rtems_termios_callbacks cb = + { + NULL, /* firstOpen */ + tty1_last_close, /* lastClose */ + NULL, /* poll read */ + BSP_uart_termios_write_com1, /* write */ + tty1_conSetAttr, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ + }; +#else + static rtems_termios_callbacks cb = + { + NULL, /* firstOpen */ + NULL, /* lastClose */ + BSP_uart_termios_read_com1, /* poll read */ + BSP_uart_termios_write_com1, /* write */ + tty1_conSetAttr, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */ + }; +#endif + + status = rtems_termios_open( major, minor, arg, &cb ); + if(status != RTEMS_SUCCESSFUL) + { + printk("Error openning tty1 device\n"); + return status; + } + + /* + * Pass data area info down to driver + */ + BSP_uart_termios_set( BSP_UART_COM1, + ((rtems_libio_open_close_args_t *)arg)->iop->data1 ); + /* Enable interrupts on channel */ + BSP_uart_intr_ctrl( BSP_UART_COM1, BSP_UART_INTR_CTRL_TERMIOS); + return RTEMS_SUCCESSFUL; +} + +/* + * TTY - device driver CLOSE entry point + */ +rtems_device_driver +tty_close(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + + return (rtems_termios_close (arg)); + +} /* tty_close */ + +/* + * TTY device driver READ entry point. + * Read characters from the tty device. + */ +rtems_device_driver +tty_read(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + return rtems_termios_read (arg); +} /* tty_read */ + +/* + * TTY device driver WRITE entry point. + * Write characters to the tty device. + */ +rtems_device_driver +tty_write(rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg) +{ + return rtems_termios_write (arg); + +} /* tty_write */ + +/* + * Handle ioctl request. This is a generic internal + * routine to handle both devices. + */ +static rtems_device_driver tty_control( int port, void *arg ) +{ + rtems_libio_ioctl_args_t *args = arg; + switch( args->command ) + { + default: + return rtems_termios_ioctl (arg); + break; + } + args->ioctl_return = 0; + return RTEMS_SUCCESSFUL; +} + +/* + * Handle ioctl request for ttyS1. + */ +rtems_device_driver +tty1_control(rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return tty_control( BSP_UART_COM1, arg ); +} + +static int +conSetAttr(int port, int minor, const struct termios *t) +{ + unsigned long baud, databits, parity, stopbits; + + baud = rtems_termios_baud_to_number(t->c_ospeed); + if ( baud > 115200 ) + rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR); + + if (t->c_cflag & PARENB) { + /* Parity is enabled */ + if (t->c_cflag & PARODD) { + /* Parity is odd */ + parity = PEN; + } + else { + /* Parity is even */ + parity = PEN | EPS; + } + } + else { + /* No parity */ + parity = 0; + } + + switch (t->c_cflag & CSIZE) { + case CS5: databits = CHR_5_BITS; break; + case CS6: databits = CHR_6_BITS; break; + case CS7: databits = CHR_7_BITS; break; + default: /* just to avoid warnings -- all cases are covered */ + case CS8: databits = CHR_8_BITS; break; + } + + if (t->c_cflag & CSTOPB) { + /* 2 stop bits */ + stopbits = STB; + } + else { + /* 1 stop bit */ + stopbits = 0; + } + + printk("Setting attributes, port=%X, baud=%" PRId32 ", linemode = 0x%02" PRIx32 "\n", + port, baud, databits | parity | stopbits ); + BSP_uart_set_attributes(port, baud, databits, parity, stopbits); + return 0; +} + +/* + * Handle ioctl request for ttyS2. + */ +static int +tty1_conSetAttr( int minor, const struct termios *t) +{ + return conSetAttr( BSP_UART_COM1, minor, t ); +} + +/* + * TTY2 device driver INITIALIZE entry point. + */ +rtems_device_driver +tty2_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; + + /* Check if this port is not been used as console */ + if( BSPConsolePort == BSP_UART_COM2 ) + { + status = -1; + printk("TTY2: port selected as console.\n"); + rtems_fatal_error_occurred( status ); + } + + /* + * Set up TERMIOS + */ + rtems_termios_initialize(); + + /* + * Do device-specific initialization + */ + /* 9600-8-N-1, without hardware flow control */ + BSP_uart_init( BSP_UART_COM2, 9600, CHR_8_BITS, 0, 0, 0); + status = rtems_interrupt_handler_install( + BSP_UART_COM2_IRQ, + "tty_drv", + RTEMS_INTERRUPT_UNIQUE, + BSP_uart_termios_isr_com2, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + + /* + * Register the device + */ + status = rtems_io_register_name ("/dev/ttyS2", major, 0); + if (status != RTEMS_SUCCESSFUL) + { + printk("Error registering tty2 device!\n"); + rtems_fatal_error_occurred (status); + } + printk("Device: /dev/ttyS2 initialized.\n"); + return RTEMS_SUCCESSFUL; +} /* tty_initialize */ + +static int tty2_last_close(int major, int minor, void *arg) +{ + rtems_status_code status; + + status = rtems_interrupt_handler_remove( + BSP_UART_COM2_IRQ, + BSP_uart_termios_isr_com2, + NULL + ); + assert(status == RTEMS_SUCCESSFUL); + return 0; +} + +/* + * TTY2 device driver OPEN entry point + */ +rtems_device_driver +tty2_open(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) +{ + rtems_status_code status; +#ifndef USE_TASK_DRIVEN + static rtems_termios_callbacks cb = + { + NULL, /* firstOpen */ + tty2_last_close, /* lastClose */ + NULL, /* poll read */ + BSP_uart_termios_write_com2, /* write */ + tty2_conSetAttr, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ + }; +#else + static rtems_termios_callbacks cb = + { + NULL, /* firstOpen */ + NULL, /* lastClose */ + BSP_uart_termios_read_com2, /* poll read */ + BSP_uart_termios_write_com2, /* write */ + tty2_conSetAttr, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */ + }; +#endif + + status = rtems_termios_open (major, minor, arg, &cb); + if(status != RTEMS_SUCCESSFUL) + { + printk("Error openning tty1 device\n"); + return status; + } + + /* + * Pass data area info down to driver + */ + BSP_uart_termios_set( BSP_UART_COM2, + ((rtems_libio_open_close_args_t *)arg)->iop->data1 ); + /* Enable interrupts on channel */ + BSP_uart_intr_ctrl( BSP_UART_COM2, BSP_UART_INTR_CTRL_TERMIOS); + return RTEMS_SUCCESSFUL; +} + +/* + * Handle ioctl request for TTY2 + */ +rtems_device_driver +tty2_control(rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + return tty_control( BSP_UART_COM2, arg ); +} + +static int +tty2_conSetAttr( int minor, const struct termios *t) +{ + return conSetAttr( BSP_UART_COM2, minor, t ); +} |