bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.
This commit is contained in:
Sebastian Huber
2018-04-19 06:28:01 +02:00
parent 58adad484e
commit d7d66d7d45
236 changed files with 204 additions and 204 deletions

View File

@@ -0,0 +1,835 @@
/*===============================================================*\
| Project: RTEMS generic MPC5200 BSP |
+-----------------------------------------------------------------+
| Partially based on the code references which are named below. |
| Adaptions, modifications, enhancements and any recent parts of |
| the code are: |
| Copyright (c) 2005 |
| Embedded Brains GmbH |
| Obere Lagerstr. 30 |
| D-82178 Puchheim |
| Germany |
| rtems@embedded-brains.de |
+-----------------------------------------------------------------+
| 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. |
| |
+-----------------------------------------------------------------+
| this file contains the console driver functions |
\*===============================================================*/
/***********************************************************************/
/* */
/* Module: console.c */
/* Date: 07/17/2003 */
/* Purpose: RTEMS MPC5x00 console driver */
/* */
/*---------------------------------------------------------------------*/
/* */
/* Description: */
/* */
/* The PSCs of mpc5200 are assigned as follows */
/* */
/* Channel Device Minor Note */
/* PSC1 /dev/tty0 0 */
/* PSC2 /dev/tty1 1 */
/* PSC3 /dev/tty2 2 */
/* */
/*---------------------------------------------------------------------*/
/* */
/* Code */
/* References: Serial driver for MPC8260ads */
/* Module: console-generic.c */
/* Project: RTEMS 4.6.0pre1 / MPC8260ads BSP */
/* Version 1.3 */
/* Date: 2002/11/04 */
/* */
/* Author(s) / Copyright(s): */
/* */
/* Author: Jay Monkman (jmonkman@frasca.com) */
/* Copyright (C) 1998 by Frasca International, Inc. */
/* */
/* Derived from c/src/lib/libbsp/m68k/gen360/console/console.c */
/* written by: */
/* W. Eric Norum */
/* Saskatchewan Accelerator Laboratory */
/* University of Saskatchewan */
/* Saskatoon, Saskatchewan, CANADA */
/* eric@skatter.usask.ca */
/* */
/* COPYRIGHT (c) 1989-2008. */
/* On-Line Applications Research Corporation (OAR). */
/* */
/* 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 */
/* */
/* Modifications by Andy Dachs <a.dachs@sstl.co.uk> to add MPC8260 */
/* support. */
/* Copyright (c) 2001, Surrey Satellite Technology Ltd */
/* */
/* 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. */
/* */
/*---------------------------------------------------------------------*/
/* */
/* Partially based on the code references which are named above. */
/* Adaptions, modifications, enhancements and any recent parts of */
/* the code are under the right of */
/* */
/* IPR Engineering, Dachauer Straße 38, D-80335 München */
/* Copyright(C) 2003 */
/* */
/*---------------------------------------------------------------------*/
/* */
/* IPR Engineering makes no representation or warranties with */
/* respect to the performance of this computer program, and */
/* specifically disclaims any responsibility for any damages, */
/* special or consequential, connected with the use of this program. */
/* */
/*---------------------------------------------------------------------*/
/* */
/* Version history: 1.0 */
/* */
/***********************************************************************/
#include <assert.h>
#include <string.h>
#include <rtems.h>
#include <bsp/mpc5200.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/console.h>
#include <rtems/bspIo.h>
#include <rtems/libio.h>
#include <rtems/termiostypes.h>
#define NUM_PORTS MPC5200_PSC_NO
#define PSC1_MINOR 0
#define PSC2_MINOR 1
#define PSC3_MINOR 2
#define PSC4_MINOR 3
#define PSC5_MINOR 4
#define PSC6_MINOR 5
uint32_t mpc5200_uart_avail_mask = BSP_UART_AVAIL_MASK;
#if defined(UARTS_USE_TERMIOS_INT)
uint8_t psc_minor_to_irqname[NUM_PORTS] = {
BSP_SIU_IRQ_PSC1,
BSP_SIU_IRQ_PSC2,
BSP_SIU_IRQ_PSC3,
BSP_SIU_IRQ_PSC4,
BSP_SIU_IRQ_PSC5,
BSP_SIU_IRQ_PSC6
};
static int mpc5200_psc_irqname_to_minor(int name) {
int minor;
uint8_t *chrptr;
chrptr = memchr(psc_minor_to_irqname, name, sizeof(psc_minor_to_irqname));
if (chrptr != NULL) {
minor = chrptr - psc_minor_to_irqname;
} else {
minor = -1;
}
return minor;
}
#endif
static void A_BSP_output_char(char c);
static int A_BSP_get_char(void);
BSP_output_char_function_type BSP_output_char = A_BSP_output_char;
BSP_polling_getchar_function_type BSP_poll_char = A_BSP_get_char;
/* Used to handle premature outputs of printk */
bool console_initialized = false;
/* per channel info structure */
struct per_channel_info {
uint16_t shadow_imr;
uint8_t shadow_mode1;
uint8_t shadow_mode2;
int cur_tx_len;
int rx_interrupts;
int tx_interrupts;
int rx_characters;
int tx_characters;
int breaks_detected;
int framing_errors;
int parity_errors;
int overrun_errors;
};
/* Used to handle more than one channel */
struct per_channel_info channel_info[NUM_PORTS];
/*
* XXX: there are only 6 PSCs, but PSC6 has an extra register gap
* from PSC5, therefore we instantiate seven(!) PSC register sets
*/
uint8_t psc_minor_to_regset[MPC5200_PSC_NO] = {0,1,2,3,4,6};
/* Used to track termios private data for callbacks */
struct rtems_termios_tty *ttyp[NUM_PORTS];
static int mpc5200_psc_setAttributes(
int minor,
const struct termios *t
)
{
int baud;
uint8_t csize=0, cstopb, parenb, parodd;
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
/* Baud rate */
baud = rtems_termios_baud_to_number(t->c_ospeed);
if (baud > 0) {
/*
* Calculate baud rate
* round divider to nearest!
*/
baud = (IPB_CLOCK + baud *16) / (baud * 32);
}
/* Number of data bits */
switch ( t->c_cflag & CSIZE ) {
case CS5: csize = 0x00; break;
case CS6: csize = 0x01; break;
case CS7: csize = 0x02; break;
case CS8: csize = 0x03; break;
}
/* Stop bits */
if(csize == 0) {
if(t->c_cflag & CSTOPB)
cstopb = 0x0F; /* Two stop bits */
else
cstopb = 0x00; /* One stop bit */
} else {
if(t->c_cflag & CSTOPB)
cstopb = 0x0F; /* Two stop bits */
else
cstopb = 0x07; /* One stop bit */
}
/* Parity */
if (t->c_cflag & PARENB)
parenb = 0x00; /* Parity enabled on Tx and Rx */
else
parenb = 0x10; /* No parity on Tx and Rx */
if (t->c_cflag & PARODD)
parodd = 0x04; /* Odd parity */
else
parodd = 0x00;
/*
* Set upper timer counter
*/
psc->ctur = (uint8_t) (baud >> 8);
/*
* Set lower timer counter
*/
psc->ctlr = (uint8_t) baud;
/*
* Reset mode pointer
*/
psc->cr = ((1 << 4) << 8);
/*
* Set mode1 register
*/
channel_info[minor].shadow_mode1 &= ~(0x1F);
psc->mr = channel_info[minor].shadow_mode1 | (csize | parenb | parodd);
/*
* Set mode2 register
*/
channel_info[minor].shadow_mode2 &= ~(0x0F);
psc->mr = channel_info[minor].shadow_mode2 | cstopb;
return 0;
}
static int mpc5200_uart_setAttributes(int minor, const struct termios *t)
{
/*
* Check that port number is valid
*/
if( (minor < PSC1_MINOR) || (minor > NUM_PORTS-1) )
return 0;
return mpc5200_psc_setAttributes(minor, t);
}
#ifdef UARTS_USE_TERMIOS_INT
/*
* Interrupt handlers
*/
static void mpc5200_psc_interrupt_handler(rtems_irq_hdl_param handle)
{
unsigned char c;
uint16_t isr;
int minor = (int)handle;
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
/*
* get content of psc interrupt status
*/
isr = psc->isr_imr;
/*
* Character received?
*/
if (isr & ISR_RX_RDY_FULL) {
channel_info[minor].rx_interrupts++;
#ifndef SINGLE_CHAR_MODE
while(psc->rfnum) {
#endif
/*
* get the character
*/
c = (psc->rb_tb >> 24);
if (ttyp[minor] != NULL) {
rtems_termios_enqueue_raw_characters(
(void *)ttyp[minor], (char *)&c, (int)1);
channel_info[minor].rx_characters++;
}
#ifndef SINGLE_CHAR_MODE
}
#endif
}
/*
* Character transmitted ?
*/
if (isr & ISR_TX_RDY & channel_info[minor].shadow_imr) {
channel_info[minor].tx_interrupts++;
if (ttyp[minor] != NULL) {
#ifndef SINGLE_CHAR_MODE
rtems_termios_dequeue_characters(
(void *)ttyp[minor], channel_info[minor].cur_tx_len);
channel_info[minor].tx_characters += channel_info[minor].cur_tx_len;
#else
rtems_termios_dequeue_characters((void *)ttyp[minor], (int)1);
channel_info[minor].tx_characters++;
#endif
}
}
if(isr & ISR_ERROR) {
if(isr & ISR_RB)
channel_info[minor].breaks_detected++;
if(isr & ISR_FE)
channel_info[minor].framing_errors++;
if(isr & ISR_PE)
channel_info[minor].parity_errors++;
if(isr & ISR_OE)
channel_info[minor].overrun_errors++;
/*
* Reset error status
*/
psc->cr = ((4 << 4) << 8);
}
}
static void mpc5200_psc_enable(
const rtems_irq_connect_data* ptr
)
{
struct mpc5200_psc *psc;
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
if (minor >= 0) {
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
psc->isr_imr = channel_info[minor].shadow_imr |=
(IMR_RX_RDY_FULL | IMR_TX_RDY);
}
}
static void mpc5200_psc_disable(
const rtems_irq_connect_data* ptr
)
{
struct mpc5200_psc *psc;
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
if (minor >= 0) {
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
psc->isr_imr = channel_info[minor].shadow_imr &=
~(IMR_RX_RDY_FULL | IMR_TX_RDY);
}
}
static int mpc5200_psc_isOn(
const rtems_irq_connect_data* ptr
)
{
struct mpc5200_psc *psc;
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
if (minor >= 0) {
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
return ((psc->isr_imr & IMR_RX_RDY_FULL) & (psc->isr_imr & IMR_TX_RDY));
}
return false;
}
static rtems_irq_connect_data consoleIrqData;
#endif
static void mpc5200_uart_psc_initialize(
int minor
)
{
uint32_t baud_divider;
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
/*
* Check that minor number is valid
*/
if ((minor < PSC1_MINOR) || (minor >= (PSC1_MINOR + NUM_PORTS)))
return;
/*
* Clear per channel info
*/
memset((void *)&channel_info[minor], 0, sizeof(struct per_channel_info));
/*
* Reset receiver and transmitter
*/
psc->cr = ((2 << 4) << 8);
psc->cr = ((3 << 4) << 8);
/*
* Reset mode pointer
*/
psc->cr = ((1 << 4) << 8);
/*
* Set clock select register
*/
psc->sr_csr = 0;
/*
* Set mode1 register
*/
psc->mr = channel_info[minor].shadow_mode1 = 0x33; /* 8Bit / no parity */
/*
* Set mode2 register
*/
psc->mr = channel_info[minor].shadow_mode2 = 7; /* 1 stop bit */
/*
* Set rx FIFO alarm
*/
psc->rfalarm = RX_FIFO_SIZE - 1;
/*
* Set tx FIFO alarm
*/
psc->tfalarm = 1;
baud_divider =
(IPB_CLOCK + GEN5200_CONSOLE_BAUD *16) / (GEN5200_CONSOLE_BAUD * 32);
/*
* Set upper timer counter
*/
psc->ctur = baud_divider >> 16;
/*
* Set lower timer counter
*/
psc->ctlr = baud_divider & 0x0000ffff;
/*
* Disable Frame mode / set granularity 0
*/
psc->tfcntl = 0;
#ifdef UARTS_USE_TERMIOS_INT
/*
* Tie interrupt dependent routines
*/
consoleIrqData.on = mpc5200_psc_enable;
consoleIrqData.off = mpc5200_psc_disable;
consoleIrqData.isOn = mpc5200_psc_isOn;
consoleIrqData.handle = (rtems_irq_hdl_param)minor;
consoleIrqData.hdl = (rtems_irq_hdl)mpc5200_psc_interrupt_handler;
/*
* Tie interrupt handler
*/
consoleIrqData.name = psc_minor_to_irqname[minor];
/*
* Install rtems irq handler
*/
assert(BSP_install_rtems_irq_handler(&consoleIrqData) == 1);
#endif
/*
* Reset rx fifo errors Error/UF/OF
*/
psc->rfstat |= 0x70;
/*
* Reset tx fifo errors Error/UF/OF
*/
psc->tfstat |= 0x70;
#ifdef UARTS_USE_TERMIOS_INT
/*
* Unmask receive interrupt
*/
psc->isr_imr = channel_info[minor].shadow_imr = IMR_RX_RDY_FULL;
#endif
/*
* Enable receiver
*/
psc->cr = ((1 << 0) << 8);
/*
* Enable transmitter
*/
psc->cr = ((1 << 2) << 8);
}
static int mpc5200_uart_pollRead(
int minor
)
{
unsigned char c;
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
if (psc->sr_csr & (1 << 8))
c = (psc->rb_tb >> 24);
else
return -1;
return c;
}
static ssize_t mpc5200_uart_pollWrite(
int minor,
const char *buf,
size_t len
)
{
size_t retval = len;
const char *tmp_buf = buf;
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
while(len--) {
while(!(psc->sr_csr & (1 << 11)))
continue;
/*rtems_cache_flush_multiple_data_lines( (void *)buf, 1);*/
psc->rb_tb = (*tmp_buf << 24);
tmp_buf++;
}
return retval;
}
static ssize_t mpc5200_uart_write(
int minor,
const char *buf,
size_t len
)
{
struct mpc5200_psc *psc =
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
if (len > 0) {
int frame_len = len;
const char *frame_buf = buf;
/*
* Check tx fifo space
*/
if(len > (TX_FIFO_SIZE - psc->tfnum))
frame_len = TX_FIFO_SIZE - psc->tfnum;
#ifndef SINGLE_CHAR_MODE
channel_info[minor].cur_tx_len = frame_len;
#else
frame_len = 1;
#endif
/*rtems_cache_flush_multiple_data_lines( (void *)frame_buf, frame_len);*/
while (frame_len--)
/* perform byte write to avoid extra NUL characters */
(* (volatile char *)&(psc->rb_tb)) = *frame_buf++;
/*
* unmask interrupt
*/
psc->isr_imr = channel_info[minor].shadow_imr |= IMR_TX_RDY;
} else {
/*
* mask interrupt
*/
psc->isr_imr = channel_info[minor].shadow_imr &= ~(IMR_TX_RDY);
}
return 0;
}
/*
* Print functions prototyped in bspIo.h
*/
static void A_BSP_output_char(
char c
)
{
/*
* If we are using U-Boot, then the console is already initialized
* and we can just poll bytes out at any time.
*/
#if !defined(HAS_UBOOT)
if (console_initialized == false)
return;
#endif
#define PRINTK_WRITE mpc5200_uart_pollWrite
PRINTK_WRITE(PRINTK_MINOR, &c, 1 );
}
static int A_BSP_get_char(void)
{
/*
* If we are using U-Boot, then the console is already initialized
* and we can just poll bytes in at any time.
*/
#if !defined(HAS_UBOOT)
if (console_initialized == false)
return -1;
#endif
return mpc5200_uart_pollRead(0);
}
/*
***************
* 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;
rtems_device_minor_number console_minor;
char dev_name[] = "/dev/ttyx";
uint32_t tty_num = 0;
bool first = true;
/*
* Always use and set up TERMIOS
*/
console_minor = PSC1_MINOR;
rtems_termios_initialize();
for (console_minor = PSC1_MINOR;
console_minor < PSC1_MINOR + NUM_PORTS;
console_minor++) {
/*
* check, whether UART is available for this board
*/
if (0 != ((1 << console_minor) & (mpc5200_uart_avail_mask))) {
/*
* Do device-specific initialization and registration for Motorola IceCube
*/
mpc5200_uart_psc_initialize(console_minor); /* /dev/tty0 */
dev_name[8] = '0' + tty_num;
status = rtems_io_register_name (dev_name, major, console_minor);
assert(status == RTEMS_SUCCESSFUL);
#ifdef MPC5200_PSC_INDEX_FOR_GPS_MODULE
if (console_minor == MPC5200_PSC_INDEX_FOR_GPS_MODULE) {
status = rtems_io_register_name("/dev/gps", major, console_minor);
assert(status == RTEMS_SUCCESSFUL);
}
#endif
if (first) {
first = false;
/* Now register the RTEMS console */
status = rtems_io_register_name ("/dev/console", major, console_minor);
assert(status == RTEMS_SUCCESSFUL);
}
tty_num++;
}
}
console_initialized = true;
return RTEMS_SUCCESSFUL;
}
/*
* Open the device
*/
rtems_device_driver console_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_libio_open_close_args_t *args = arg;
rtems_status_code sc;
#ifdef UARTS_USE_TERMIOS_INT
static const rtems_termios_callbacks intrCallbacks = {
NULL, /* firstOpen */
NULL, /* lastClose */
NULL, /* pollRead */
mpc5200_uart_write, /* write */
mpc5200_uart_setAttributes, /* setAttributes */
NULL,
NULL,
1 /* outputUsesInterrupts */
};
#else
static const rtems_termios_callbacks pollCallbacks = {
NULL, /* firstOpen */
NULL, /* lastClose */
mpc5200_uart_pollRead, /* pollRead */
mpc5200_uart_pollWrite, /* write */
mpc5200_uart_setAttributes, /* setAttributes */
NULL,
NULL,
0 /* output don't use Interrupts */
};
#endif
if(minor > NUM_PORTS - 1)
return RTEMS_INVALID_NUMBER;
#ifdef UARTS_USE_TERMIOS_INT
sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
#else /* RTEMS polled I/O with termios */
sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
#endif
ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */
if ( !sc )
rtems_termios_set_initial_baud( ttyp[minor], GEN5200_CONSOLE_BAUD );
return sc;
}
/*
* Close the device
*/
rtems_device_driver console_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
ttyp[minor] = NULL; /* mark for int handler: tty no longer open */
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
)
{
if(minor > NUM_PORTS-1)
return RTEMS_INVALID_NUMBER;
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
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
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
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
return rtems_termios_ioctl(arg);
}

View File

@@ -0,0 +1,107 @@
/**
* @file
*
* @brief Console configuration.
*/
/*
* Copyright (c) 2008-2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <rtems/bspIo.h>
#include <libchip/ns16550.h>
#include <mpc83xx/mpc83xx.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/console-termios.h>
#ifdef BSP_USE_UART_INTERRUPTS
#define DEVICE_FNS &ns16550_handler_interrupt
#else
#define DEVICE_FNS &ns16550_handler_polled
#endif
static uint8_t gen83xx_console_get_register(uintptr_t addr, uint8_t i)
{
volatile uint8_t *reg = (volatile uint8_t *) addr;
return reg [i];
}
static void gen83xx_console_set_register(uintptr_t addr, uint8_t i, uint8_t val)
{
volatile uint8_t *reg = (volatile uint8_t *) addr;
reg [i] = val;
}
static ns16550_context gen83xx_uart_context_0 = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"),
.get_reg = gen83xx_console_get_register,
.set_reg = gen83xx_console_set_register,
.port = (uintptr_t) &mpc83xx.duart[0],
#if MPC83XX_CHIP_TYPE / 10 == 830
.irq = BSP_IPIC_IRQ_UART,
#else
.irq = BSP_IPIC_IRQ_UART1,
#endif
.initial_baud = BSP_CONSOLE_BAUD
};
#ifdef BSP_USE_UART2
static ns16550_context gen83xx_uart_context_1 = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"),
.get_reg = gen83xx_console_get_register,
.set_reg = gen83xx_console_set_register,
.port = (uintptr_t) &mpc83xx.duart[1],
#if MPC83XX_CHIP_TYPE / 10 == 830
.irq = BSP_IPIC_IRQ_UART,
#else
.irq = BSP_IPIC_IRQ_UART2,
#endif
.initial_baud = BSP_CONSOLE_BAUD
};
#endif
const console_device console_device_table[] = {
{
.device_file = "/dev/ttyS0",
.probe = ns16550_probe,
.handler = DEVICE_FNS,
.context = &gen83xx_uart_context_0.base
}
#ifdef BSP_USE_UART2
, {
.device_file = "/dev/ttyS1",
.probe = ns16550_probe,
.handler = DEVICE_FNS,
.context = &gen83xx_uart_context_1.base
}
#endif
};
const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table);
static void gen83xx_output_char(char c)
{
rtems_termios_device_context *ctx = console_device_table[0].context;
ns16550_polled_putchar(ctx, c);
}
BSP_output_char_function_type BSP_output_char = gen83xx_output_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2011-2012 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <bsp.h>
#include <bsp/console-generic.h>
#include <bsp/console-esci.h>
#include <bsp/console-linflex.h>
CONSOLE_GENERIC_INFO_TABLE = {
#ifdef MPC55XX_HAS_ESCI
CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 0, &mpc55xx_esci_callbacks, "/dev/ttyS0")
#ifdef ESCI_B
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 1, &mpc55xx_esci_callbacks, "/dev/ttyS1")
#endif
#ifdef ESCI_C
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 2, &mpc55xx_esci_callbacks, "/dev/ttyS2")
#endif
#ifdef ESCI_D
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 3, &mpc55xx_esci_callbacks, "/dev/ttyS3")
#endif
#endif
#ifdef MPC55XX_HAS_LINFLEX
CONSOLE_GENERIC_INFO(mpc55xx_linflex_devices + 0, &mpc55xx_linflex_callbacks, "/dev/ttyS0"),
CONSOLE_GENERIC_INFO(mpc55xx_linflex_devices + 1, &mpc55xx_linflex_callbacks, "/dev/ttyS1")
#endif
};
CONSOLE_GENERIC_INFO_COUNT;
CONSOLE_GENERIC_MINOR(MPC55XX_CONSOLE_MINOR);

View File

@@ -0,0 +1,354 @@
/**
* @file
*
* @brief Console ESCI implementation.
*/
/*
* Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <bsp/console-esci.h>
#include <bsp.h>
#include <bsp/fatal.h>
#include <bsp/irq.h>
#ifdef MPC55XX_HAS_ESCI
mpc55xx_esci_context mpc55xx_esci_devices [] = {
{
.regs = &ESCI_A,
.irq = MPC55XX_IRQ_ESCI(0)
}
#ifdef ESCI_B
, {
.regs = &ESCI_B,
.irq = MPC55XX_IRQ_ESCI(1)
}
#endif
#ifdef ESCI_C
, {
.regs = &ESCI_C,
.irq = MPC55XX_IRQ_ESCI(2)
}
#endif
#ifdef ESCI_D
, {
.regs = &ESCI_D,
.irq = MPC55XX_IRQ_ESCI(3)
}
#endif
};
static void mpc55xx_esci_poll_write(int minor, char c)
{
mpc55xx_esci_context *self = console_generic_get_context(minor);
const union ESCI_SR_tag clear_tdre = { .B = { .TDRE = 1 } };
volatile struct ESCI_tag *regs = self->regs;
rtems_interrupt_level level;
bool done = false;
bool wait_for_transmit_done = false;
rtems_interrupt_disable(level);
if (self->transmit_nest_level == 0) {
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
if (cr1.B.TIE != 0) {
cr1.B.TIE = 0;
regs->CR1.R = cr1.R;
wait_for_transmit_done = !self->transmit_in_progress;
self->transmit_nest_level = 1;
}
} else {
++self->transmit_nest_level;
}
rtems_interrupt_enable(level);
while (!done) {
rtems_interrupt_disable(level);
bool tx = self->transmit_in_progress;
if (!tx || (tx && regs->SR.B.TDRE)) {
regs->SR.R = clear_tdre.R;
regs->DR.B.D = c;
self->transmit_in_progress = true;
done = true;
}
rtems_interrupt_enable(level);
}
done = false;
while (!done) {
rtems_interrupt_disable(level);
if (wait_for_transmit_done) {
if (regs->SR.B.TDRE) {
regs->SR.R = clear_tdre.R;
self->transmit_in_progress = false;
done = true;
}
} else {
done = true;
}
if (done && self->transmit_nest_level > 0) {
--self->transmit_nest_level;
if (self->transmit_nest_level == 0) {
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
cr1.B.TIE = 1;
regs->CR1.R = cr1.R;
}
}
rtems_interrupt_enable(level);
}
}
static inline void mpc55xx_esci_interrupts_clear_and_enable(
mpc55xx_esci_context *self
)
{
volatile struct ESCI_tag *regs = self->regs;
union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
rtems_interrupt_level level;
rtems_interrupt_disable(level);
cr1.R = regs->CR1.R;
cr1.B.RIE = 1;
cr1.B.TIE = 1;
regs->CR1.R = cr1.R;
regs->SR.R = regs->SR.R;
rtems_interrupt_enable(level);
}
static inline void mpc55xx_esci_interrupts_disable(mpc55xx_esci_context *self)
{
volatile struct ESCI_tag *regs = self->regs;
union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
rtems_interrupt_level level;
rtems_interrupt_disable(level);
cr1.R = regs->CR1.R;
cr1.B.RIE = 0;
cr1.B.TIE = 0;
regs->CR1.R = cr1.R;
rtems_interrupt_enable(level);
}
static void mpc55xx_esci_interrupt_handler(void *arg)
{
mpc55xx_esci_context *self = arg;
volatile struct ESCI_tag *regs = self->regs;
union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
union ESCI_SR_tag active = MPC55XX_ZERO_FLAGS;
rtems_interrupt_level level;
/* Status */
sr.R = regs->SR.R;
/* Receive data register full? */
if (sr.B.RDRF != 0) {
active.B.RDRF = 1;
}
/* Transmit data register empty? */
if (sr.B.TDRE != 0) {
active.B.TDRE = 1;
}
/* Clear flags */
rtems_interrupt_disable(level);
regs->SR.R = active.R;
self->transmit_in_progress = false;
rtems_interrupt_enable(level);
/* Enqueue */
if (active.B.RDRF != 0) {
char c = regs->DR.B.D;
rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
}
/* Dequeue */
if (active.B.TDRE != 0) {
rtems_termios_dequeue_characters(self->tty, 1);
}
}
static int mpc55xx_esci_set_attributes(int minor, const struct termios *t)
{
mpc55xx_esci_context *self = console_generic_get_context(minor);
volatile struct ESCI_tag *regs = self->regs;
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
union ESCI_CR2_tag cr2 = MPC55XX_ZERO_FLAGS;
rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
/* Enable module */
cr2.B.MDIS = 0;
/* Interrupts */
cr1.B.TCIE = 0;
cr1.B.ILIE = 0;
cr2.B.IEBERR = 0;
cr2.B.ORIE = 0;
cr2.B.NFIE = 0;
cr2.B.FEIE = 0;
cr2.B.PFIE = 0;
/* Disable receiver wake-up standby */
cr1.B.RWU = 0;
/* Disable DMA channels */
cr2.B.RXDMA = 0;
cr2.B.TXDMA = 0;
/* Idle line type */
cr1.B.ILT = 0;
/* Disable loops */
cr1.B.LOOPS = 0;
/* Enable or disable receiver */
cr1.B.RE = (t->c_cflag & CREAD) ? 1 : 0;
/* Enable transmitter */
cr1.B.TE = 1;
/* Baud rate */
if (br > 0) {
br = bsp_clock_speed / (16 * br);
br = (br > 8191) ? 8191 : br;
} else {
br = 0;
}
cr1.B.SBR = br;
/* Number of data bits */
if ((t->c_cflag & CSIZE) != CS8) {
return -1;
}
cr1.B.M = 0;
/* Parity */
cr1.B.PE = (t->c_cflag & PARENB) ? 1 : 0;
cr1.B.PT = (t->c_cflag & PARODD) ? 1 : 0;
/* Stop bits */
if (t->c_cflag & CSTOPB ) {
/* Two stop bits */
return -1;
}
/* Disable LIN */
regs->LCR.R = 0;
/* Set control registers */
regs->CR2.R = cr2.R;
regs->CR1.R = cr1.R;
return 0;
}
static int mpc55xx_esci_first_open(int major, int minor, void *arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
int rv = 0;
mpc55xx_esci_context *self = console_generic_get_context(minor);
struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
self->tty = tty;
rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
if (rv != 0) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_BAUD);
}
rv = mpc55xx_esci_set_attributes(minor, &tty->termios);
if (rv != 0) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_ATTRIBUTES);
}
sc = mpc55xx_interrupt_handler_install(
self->irq,
"eSCI",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_DEFAULT_PRIORITY,
mpc55xx_esci_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_IRQ_INSTALL);
}
mpc55xx_esci_interrupts_clear_and_enable(self);
self->transmit_in_progress = false;
return 0;
}
static int mpc55xx_esci_last_close(int major, int minor, void* arg)
{
mpc55xx_esci_context *self = console_generic_get_context(minor);
mpc55xx_esci_interrupts_disable(self);
self->tty = NULL;
return 0;
}
static int mpc55xx_esci_poll_read(int minor)
{
mpc55xx_esci_context *self = console_generic_get_context(minor);
volatile struct ESCI_tag *regs = self->regs;
union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
rtems_interrupt_level level;
int c = -1;
rtems_interrupt_disable(level);
if (regs->SR.B.RDRF != 0) {
/* Clear flag */
sr.B.RDRF = 1;
regs->SR.R = sr.R;
/* Read */
c = regs->DR.B.D;
}
rtems_interrupt_enable(level);
return c;
}
static int mpc55xx_esci_write(int minor, const char *out, size_t n)
{
if (n > 0) {
mpc55xx_esci_context *self = console_generic_get_context(minor);
self->regs->DR.B.D = out [0];
self->transmit_in_progress = true;
}
return 0;
}
const console_generic_callbacks mpc55xx_esci_callbacks = {
.termios_callbacks = {
.firstOpen = mpc55xx_esci_first_open,
.lastClose = mpc55xx_esci_last_close,
.write = mpc55xx_esci_write,
.setAttributes = mpc55xx_esci_set_attributes,
.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
},
.poll_read = mpc55xx_esci_poll_read,
.poll_write = mpc55xx_esci_poll_write
};
#endif /* MPC55XX_HAS_ESCI */

View File

@@ -0,0 +1,168 @@
/**
* @file
*
* @brief Generic console driver implementation.
*/
/*
* Copyright (c) 2011 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <sys/cdefs.h>
#include <bsp.h>
#include <bsp/console-generic.h>
#include <bsp/fatal.h>
#include <rtems/bspIo.h>
#include <rtems/console.h>
static const struct termios console_generic_termios = {
.c_cflag = CS8 | CREAD | CLOCAL | __CONCAT(B, BSP_DEFAULT_BAUD_RATE)
};
static void console_generic_char_out(char c)
{
int minor = (int) console_generic_minor;
const console_generic_callbacks *cb =
console_generic_info_table [minor].callbacks;
(*cb->poll_write)(minor, c);
}
static int console_generic_char_in(void)
{
int minor = (int) console_generic_minor;
const console_generic_callbacks *cb =
console_generic_info_table [minor].callbacks;
return (*cb->poll_read)(minor);
}
static void console_generic_char_out_do_init(void)
{
int minor = (int) console_generic_minor;
const console_generic_callbacks *cb =
console_generic_info_table [minor].callbacks;
const struct termios *term = &console_generic_termios;
BSP_output_char = console_generic_char_out;
(*cb->termios_callbacks.setAttributes)(minor, term);
}
static void console_generic_char_out_init(char c)
{
console_generic_char_out_do_init();
console_generic_char_out(c);
}
rtems_device_driver console_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
const console_generic_info *info_table = console_generic_info_table;
rtems_device_minor_number count = console_generic_info_count;
rtems_device_minor_number console = console_generic_minor;
if (count <= 0) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_COUNT);
}
rtems_termios_initialize();
for (minor = 0; minor < count; ++minor) {
const console_generic_info *info = info_table + minor;
sc = rtems_io_register_name(info->device_path, major, minor);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_REGISTER);
}
}
sc = rtems_io_register_name(CONSOLE_DEVICE_NAME, major, console);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_REGISTER_CONSOLE);
}
console_generic_char_out_do_init();
return sc;
}
rtems_device_driver console_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
rtems_device_minor_number count = console_generic_info_count;
if (minor < count) {
const console_generic_info *info = &console_generic_info_table [minor];
sc = rtems_termios_open(
major,
minor,
arg,
&info->callbacks->termios_callbacks
);
} else {
sc = RTEMS_INVALID_ID;
}
return sc;
}
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);
}
BSP_output_char_function_type BSP_output_char = console_generic_char_out_init;
BSP_polling_getchar_function_type BSP_poll_char = console_generic_char_in;

View File

@@ -0,0 +1,417 @@
/**
* @file
*
* @brief Console LINFlexD implementation.
*/
/*
* Copyright (c) 2011-2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <bsp/console-linflex.h>
#include <bsp.h>
#include <bsp/fatal.h>
#include <bsp/irq.h>
#ifdef MPC55XX_HAS_LINFLEX
mpc55xx_linflex_context mpc55xx_linflex_devices [] = {
{
.regs = &LINFLEX0,
.irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(0),
.irq_txi = MPC55XX_IRQ_LINFLEX_TXI(0),
.irq_err = MPC55XX_IRQ_LINFLEX_ERR(0),
.tx_pcr_register = &((SIU_tag *) &SIUL)->PCR18,
.tx_pa_value = 1,
.rx_pcr_register = &((SIU_tag *) &SIUL)->PCR19,
.rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI31,
.rx_padsel_value = 0
}, {
.regs = &LINFLEX1,
.irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(1),
.irq_txi = MPC55XX_IRQ_LINFLEX_TXI(1),
.irq_err = MPC55XX_IRQ_LINFLEX_ERR(1),
.tx_pcr_register = &((SIU_tag *) &SIUL)->PCR94,
.tx_pa_value = 1,
.rx_pcr_register = &((SIU_tag *) &SIUL)->PCR95,
.rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI32,
.rx_padsel_value = 2
}
};
static void enter_init_mode(volatile LINFLEX_tag *regs)
{
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
cr1.B.SLEEP = 0;
cr1.B.INIT = 1;
regs->LINCR1.R = cr1.R;
}
static void enter_active_mode(volatile LINFLEX_tag *regs)
{
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
cr1.B.SLEEP = 0;
cr1.B.INIT = 0;
regs->LINCR1.R = cr1.R;
}
static void enter_sleep_mode(volatile LINFLEX_tag *regs)
{
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
cr1.B.SLEEP = 1;
cr1.B.INIT = 0;
regs->LINCR1.R = cr1.R;
}
static void mpc55xx_linflex_poll_write(int minor, char c)
{
mpc55xx_linflex_context *self = console_generic_get_context(minor);
volatile LINFLEX_tag *regs = self->regs;
const LINFLEX_UARTSR_32B_tag clear_dtf = { .B = { .DTF_TFF = 1 } };
rtems_interrupt_level level;
bool done = false;
bool wait_for_transmit_done = false;
rtems_interrupt_disable(level);
if (self->transmit_nest_level == 0) {
LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
if (ier.B.DTIE != 0) {
ier.B.DTIE = 0;
regs->LINIER.R = ier.R;
wait_for_transmit_done = !self->transmit_in_progress;
self->transmit_nest_level = 1;
}
} else {
++self->transmit_nest_level;
}
rtems_interrupt_enable(level);
while (!done) {
rtems_interrupt_disable(level);
bool tx = self->transmit_in_progress;
if (!tx || (tx && regs->UARTSR.B.DTF_TFF)) {
regs->UARTSR.R = clear_dtf.R;
regs->BDRL.B.DATA0 = c;
self->transmit_in_progress = true;
done = true;
}
rtems_interrupt_enable(level);
}
done = false;
while (!done) {
rtems_interrupt_disable(level);
if (wait_for_transmit_done) {
if (regs->UARTSR.B.DTF_TFF) {
regs->UARTSR.R = clear_dtf.R;
self->transmit_in_progress = false;
done = true;
}
} else {
done = true;
}
if (done && self->transmit_nest_level > 0) {
--self->transmit_nest_level;
if (self->transmit_nest_level == 0) {
LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
ier.B.DTIE = 1;
regs->LINIER.R = ier.R;
}
}
rtems_interrupt_enable(level);
}
}
static void mpc55xx_linflex_rx_interrupt_handler(void *arg)
{
mpc55xx_linflex_context *self = arg;
volatile LINFLEX_tag *regs = self->regs;
char c = regs->BDRM.B.DATA4;
const LINFLEX_UARTSR_32B_tag clear_flags = { .B = { .RMB = 1, .DRF_RFE = 1 } };
regs->UARTSR.R = clear_flags.R;
rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
}
static void mpc55xx_linflex_tx_interrupt_handler(void *arg)
{
mpc55xx_linflex_context *self = arg;
volatile LINFLEX_tag *regs = self->regs;
regs->UARTSR.B.DTF_TFF = 1; /* clear flag */
self->transmit_in_progress = false;
rtems_termios_dequeue_characters(self->tty, 1);
}
/*
static void mpc55xx_linflex_err_interrupt_handler(void *arg)
{
mpc55xx_linflex_context *self = arg;
}
*/
static int mpc55xx_linflex_set_attributes(int minor, const struct termios *t)
{
mpc55xx_linflex_context *self = console_generic_get_context(minor);
volatile LINFLEX_tag *regs = self->regs;
LINFLEX_UARTCR_32B_tag uartcr = { .R = 0 };
LINFLEX_GCR_32B_tag gcr = { .R = 0 };
LINFLEX_LINIER_32B_tag ier = { .R = 0 };
rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
LINFLEX_LINFBRR_32B_tag fbrr = { .R = 0 };
LINFLEX_LINIBRR_32B_tag ibrr = { .R = 0 };
enter_init_mode(regs);
/* Set to UART-mode */
uartcr.B.UART = 1;
regs->UARTCR.R = uartcr.R;
/* Set to buffer mode with size 1 */
uartcr.B.TDFL_TFC = 0;
uartcr.B.RDFL_RFC0 = 0;
uartcr.B.RFBM = 0;
uartcr.B.TFBM = 0;
/* Enable receiver and transmitter */
uartcr.B.RXEN = 1;
uartcr.B.TXEN = 1;
/* Number of data bits */
uartcr.B.WL1 = 0;
if ((t->c_cflag & CSIZE) == CS8) {
uartcr.B.WL0 = 1;
} else if ((t->c_cflag & CSIZE) == CS7) {
uartcr.B.WL0 = 0;
} else {
return -1;
}
/* Parity */
uartcr.B.PCE = (t->c_cflag & PARENB) ? 1 : 0;
uartcr.B.PC1 = 0;
uartcr.B.PC0 = (t->c_cflag & PARODD) ? 1 : 0;
/* Stop bits */
gcr.B.STOP = (t->c_cflag & CSTOPB) ? 1 : 0;
/* Set control registers */
regs->UARTCR.R = uartcr.R;
regs->GCR.R = gcr.R;
/* Interrupts */
ier.B.DTIE = 1;
ier.B.DRIE = 1;
regs->LINIER.R = ier.R;
/* Baud rate */
if (br > 0) {
uint32_t lfdiv_mult_32 = bsp_clock_speed * 2 / br;
if((lfdiv_mult_32 & 0x1) != 0) {
++lfdiv_mult_32;
}
fbrr.B.FBR = (lfdiv_mult_32 >> 1) & 0xF;
ibrr.B.IBR = lfdiv_mult_32 >> 5;
} else {
return -1;
}
regs->LINFBRR.R = fbrr.R;
regs->LINIBRR.R = ibrr.R;
enter_active_mode(regs);
return 0;
}
static int mpc55xx_linflex_first_open(int major, int minor, void *arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
int rv = 0;
mpc55xx_linflex_context *self = console_generic_get_context(minor);
struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
SIU_PCR_tag pcr = { .R = 0 };
SIUL_PSMI_8B_tag psmi = { .R = 0 };
self->tty = tty;
pcr.B.IBE = 1;
self->rx_pcr_register->R = pcr.R;
psmi.B.PADSEL = self->rx_padsel_value;
self->rx_psmi_register->R = psmi.R;
pcr.R = 0;
pcr.B.OBE = 1;
pcr.B.PA = self->tx_pa_value;
self->tx_pcr_register->R = pcr.R;
rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
if (rv != 0) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_BAUD);
}
rv = mpc55xx_linflex_set_attributes(minor, &tty->termios);
if (rv != 0) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ATTRIBUTES);
}
sc = mpc55xx_interrupt_handler_install(
self->irq_rxi,
"LINFlexD RXI",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_DEFAULT_PRIORITY,
mpc55xx_linflex_rx_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_INSTALL);
}
sc = mpc55xx_interrupt_handler_install(
self->irq_txi,
"LINFlexD TXI",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_DEFAULT_PRIORITY,
mpc55xx_linflex_tx_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_INSTALL);
}
/*
sc = mpc55xx_interrupt_handler_install(
self->irq_err,
"LINFlexD ERR",
RTEMS_INTERRUPT_UNIQUE,
MPC55XX_INTC_DEFAULT_PRIORITY,
mpc55xx_linflex_err_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_INSTALL);
}
*/
return 0;
}
static int mpc55xx_linflex_last_close(int major, int minor, void* arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
mpc55xx_linflex_context *self = console_generic_get_context(minor);
volatile LINFLEX_tag *regs = self->regs;
SIU_PCR_tag pcr = { .R = 0 };
SIUL_PSMI_8B_tag psmi = { .R = 0 };
/* enter initialization mode */
enter_init_mode(regs);
/* disable interrupts */
regs->LINIER.R = 0;
/* set module to sleep mode */
enter_sleep_mode(regs);
sc = rtems_interrupt_handler_remove(
self->irq_rxi,
mpc55xx_linflex_rx_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_REMOVE);
}
sc = rtems_interrupt_handler_remove(
self->irq_txi,
mpc55xx_linflex_tx_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_REMOVE);
}
/*
sc = rtems_interrupt_handler_remove(
self->irq_err,
mpc55xx_linflex_err_interrupt_handler,
self
);
if (sc != RTEMS_SUCCESSFUL) {
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_REMOVE);
}
*/
pcr.B.IBE = 1;
self->rx_pcr_register->R = pcr.R;
self->tx_pcr_register->R = pcr.R;
psmi.R = 0;
self->rx_psmi_register->R = psmi.R;
self->tty = NULL;
return 0;
}
static int mpc55xx_linflex_poll_read(int minor)
{
mpc55xx_linflex_context *self = console_generic_get_context(minor);
volatile LINFLEX_tag *regs = self->regs;
rtems_interrupt_level level;
int c = -1;
rtems_interrupt_disable(level);
if (regs->UARTSR.B.DRF_RFE != 0) {
/* Clear flag */
regs->UARTSR.B.DRF_RFE = 1;
/* Read */
c = regs->BDRM.B.DATA4;
}
rtems_interrupt_enable(level);
return c;
}
static int mpc55xx_linflex_write(int minor, const char *out, size_t n)
{
if (n > 0) {
mpc55xx_linflex_context *self = console_generic_get_context(minor);
volatile LINFLEX_tag *regs = self->regs;
regs->BDRL.B.DATA0 = out [0];
self->transmit_in_progress = true;
/* TODO: send more then one byte */
}
return 0;
}
const console_generic_callbacks mpc55xx_linflex_callbacks = {
.termios_callbacks = {
.firstOpen = mpc55xx_linflex_first_open,
.lastClose = mpc55xx_linflex_last_close,
.write = mpc55xx_linflex_write,
.setAttributes = mpc55xx_linflex_set_attributes,
.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
},
.poll_read = mpc55xx_linflex_poll_read,
.poll_write = mpc55xx_linflex_poll_write
};
#endif /* MPC55XX_HAS_LINFLEX */

View File

@@ -0,0 +1,458 @@
/*
* 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
*
* The SCCs and SMCs on the eval board are assigned as follows
*
* Channel Device Minor Termios
* SMC1 /dev/tty3 4 no
* SMC2 /dev/tty4 5 no
* SCC1 /dev/tty0 0 no
* SCC2 /dev/console 1 yes
* SCC3 /dev/tty1 2 no * USED FOR NETWORK I/F
* SCC4 /dev/tty2 3 no * USED FOR NETWORK I/F
*
* All ports support termios. The use of termios is recommended for real-time
* applications. Termios provides buffering and input processing. When not
* using termios, processing is limited to the substitution of LF for CR on
* input, and the output of a CR following the output of a LF character.
* Note that the terminal should not send CR/LF pairs when the return key
* is pressed, and that output lines are terminated with LF/CR, not CR/LF
* (although that would be easy to change).
*
* I/O may be interrupt-driven (recommended for real-time applications) or
* polled. Polled I/O may be performed by this device driver entirely, or
* in part by EPPCBug. With EPPCBug 1.1, polled I/O is limited to the
* EPPCBug debug console. This is a limitation of the firmware. Later
* firmware may be able to do I/O through any port. This code assumes
* that the EPPCBug console is the default: SMC1. If the console and
* printk ports are set to anything else with EPPCBug polled I/O, the
* system will hang. Only port SMC1 is usable with EPPCBug polled I/O.
*
* LIMITATIONS:
*
* It is not possible to use different I/O modes on the different ports. The
* exception is with printk. The printk port can use a different mode from
* the other ports. If this is done, it is important not to open the printk
* port from an RTEMS application.
*
* Currently, the I/O modes are determined at build time. It would be much
* better to have the mode selected at boot time based on parameters in
* NVRAM.
*
* Interrupt-driven I/O requires termios.
*
* TESTS:
*
* TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
* play with the interrupt masks and turn off I/O. Those tests will hang
* when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
* from the static constructors before the console is open. This test
* will not work with interrupt-driven I/O. Because of the buffering
* performed in termios, test output may not be in sequence.The tests
* should all be fixed to work with interrupt-driven I/O and to
* produce output in the expected sequence. Obviously, the termios test
* requires termios support in the driver.
*
* 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 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) 2000, National Research Council of Canada
*
* Modifications by Andy Dachs <iwe@fsmal.net> for MPC8260
* support.
*/
#include <stdarg.h>
#include <stdio.h>
#include <termios.h>
#include <rtems/console.h>
#include <rtems/bspIo.h>
#include <rtems/libio.h>
#include <bsp.h>
static void _BSP_output_char( char c );
static rtems_status_code do_poll_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
static rtems_status_code do_poll_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
BSP_output_char_function_type BSP_output_char = _BSP_output_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;
/*
* do_poll_read
*
* Input characters through polled I/O. Returns has soon as a character has
* been received. Otherwise, if we wait for the number of requested characters,
* we could be here forever!
*
* CR is converted to LF on input. The terminal should not send a CR/LF pair
* when the return or enter key is pressed.
*
* Input parameters:
* major - ignored. Should be the major number for this driver.
* minor - selected channel.
* arg->buffer - where to put the received characters.
* arg->count - number of characters to receive before returning--Ignored.
*
* Output parameters:
* arg->bytes_moved - the number of characters read. Always 1.
*
* Return value: RTEMS_SUCCESSFUL
*
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
*/
static rtems_status_code do_poll_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
)
{
rtems_libio_rw_args_t *rw_args = arg;
int c;
#define BSP_READ m8xx_uart_pollRead
while( (c = BSP_READ(minor)) == -1 );
rw_args->buffer[0] = (uint8_t)c;
if( rw_args->buffer[0] == '\r' )
rw_args->buffer[0] = '\n';
rw_args->bytes_moved = 1;
return RTEMS_SUCCESSFUL;
}
/*
* do_poll_write
*
* Output characters through polled I/O. Returns only once every character has
* been sent.
*
* CR is transmitted AFTER a LF on output.
*
* Input parameters:
* major - ignored. Should be the major number for this driver.
* minor - selected channel
* arg->buffer - where to get the characters to transmit.
* arg->count - the number of characters to transmit before returning.
*
* Output parameters:
* arg->bytes_moved - the number of characters read
*
* Return value: RTEMS_SUCCESSFUL
*
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
*/
static rtems_status_code do_poll_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
)
{
rtems_libio_rw_args_t *rw_args = arg;
uint32_t i;
char cr ='\r';
#define BSP_WRITE m8xx_uart_pollWrite
for( i = 0; i < rw_args->count; i++ ) {
BSP_WRITE(minor, &(rw_args->buffer[i]), 1);
if ( rw_args->buffer[i] == '\n' )
BSP_WRITE(minor, &cr, 1);
}
rw_args->bytes_moved = i;
return RTEMS_SUCCESSFUL;
}
/*
* Print functions prototyped in bspIo.h
*/
static void _BSP_output_char( char c )
{
/*
* Can't rely on console_initialize having been called before this function
* is used, so it may fail unless output is done through EPPC-Bug.
*/
#define PRINTK_WRITE m8xx_uart_pollWrite
PRINTK_WRITE( PRINTK_MINOR, &c, 1 );
}
/*
***************
* 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;
rtems_device_minor_number console_minor;
/*
* Set up TERMIOS if needed
*/
console_minor = CONSOLE_MINOR;
#if UARTS_USE_TERMIOS == 1
rtems_termios_initialize ();
#else
rtems_termios_initialize ();
#endif /* UARTS_USE_TERMIOS */
/*
* Do common initialization.
*/
m8xx_uart_initialize();
/*
* Do device-specific initialization
*/
#if 0
m8xx_uart_smc_initialize(SMC1_MINOR); /* /dev/tty4 */
m8xx_uart_smc_initialize(SMC2_MINOR); /* /dev/tty5 */
#endif
m8xx_uart_scc_initialize(SCC1_MINOR); /* /dev/tty0 */
m8xx_uart_scc_initialize(SCC2_MINOR); /* /dev/tty1 */
#if 0 /* used as network connections */
m8xx_uart_scc_initialize(SCC3_MINOR); /* /dev/tty2 */
m8xx_uart_scc_initialize(SCC4_MINOR); /* /dev/tty3 */
#endif
/*
* Set up interrupts
*/
m8xx_uart_interrupts_initialize();
status = rtems_io_register_name ("/dev/tty0", major, SCC1_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
chmod("/dev/tty0",0660);
chown("/dev/tty0",2,0);
status = rtems_io_register_name ("/dev/tty1", major, SCC2_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
chmod("/dev/tty1",0660);
chown("/dev/tty1",2,0);
#if 0
status = rtems_io_register_name ("/dev/tty2", major, SCC3_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
status = rtems_io_register_name ("/dev/tty3", major, SCC4_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
status = rtems_io_register_name ("/dev/tty4", major, SMC1_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
status = rtems_io_register_name ("/dev/tty5", major, SMC2_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
#endif
/* Now register the RTEMS console */
status = rtems_io_register_name ("/dev/console", major, console_minor);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
chmod("/dev/console",0666);
chown("/dev/console",2,0);
return RTEMS_SUCCESSFUL;
}
/*
* Open the device
*/
rtems_device_driver console_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
#if UARTS_IO_MODE == 1 /* RTEMS interrupt-driven I/O with termios */
/* Used to track termios private data for callbacks */
extern struct rtems_termios_tty *ttyp[];
rtems_libio_open_close_args_t *args = arg;
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
#if (UARTS_USE_TERMIOS == 1) && (UARTS_IO_MODE != 1)
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
#endif
rtems_status_code sc;
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
#if UARTS_IO_MODE == 1 /* RTEMS interrupt-driven I/O with termios */
sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */
#else /* RTEMS polled I/O with termios */
sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
#endif
#else /* UARTS_USE_TERMIOS != 1 */
/* no termios -- default to polled I/O */
sc = RTEMS_SUCCESSFUL;
#endif /* UARTS_USE_TERMIOS != 1 */
return sc;
}
/*
* Close the device
*/
rtems_device_driver console_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_close( arg );
#else
return RTEMS_SUCCESSFUL;
#endif
}
/*
* Read from the device
*/
rtems_device_driver console_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_read( arg );
#else
return do_poll_read( major, minor, arg );
#endif
}
/*
* Write to the device
*/
rtems_device_driver console_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_write( arg );
#else
/* no termios -- default to polled */
return do_poll_write( major, minor, arg );
#endif
}
/*
* Handle ioctl request.
*/
rtems_device_driver console_control(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_ioctl( arg );
#else
return RTEMS_SUCCESSFUL;
#endif
}
/*
* Support routine for console-generic
*/
int mbx8xx_console_get_configuration(void)
{
#if UARTS_IO_MODE == 1
return 0x02;
#else
return 0;
#endif
}

View File

@@ -0,0 +1,78 @@
/*
* This file contains the hardware specific portions of the TTY driver
* for the simulated serial port on the PowerPC simulator.
*/
/*
* COPYRIGHT (c) 1989-2004.
* On-Line Applications Research Corporation (OAR).
*
* 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 <bsp.h>
#include <bsp/console-polled.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <assert.h>
/*
* console_initialize_hardware
*
* This routine initializes the console hardware.
*
*/
void console_initialize_hardware(void)
{
}
/* external prototypes for monitor interface routines */
void outbyte( char );
char inbyte( void );
/*
* console_outbyte_polled
*
* This routine transmits a character using polling.
*/
void console_outbyte_polled(
int port,
char ch
)
{
outbyte( ch );
}
/*
* console_inbyte_nonblocking
*
* This routine polls for a character.
*/
int console_inbyte_nonblocking(
int port
)
{
char c;
c = inbyte();
if (!c)
return -1;
return c;
}
/*
* To support printk
*/
#include <rtems/bspIo.h>
static void PSIM_output_char(char c) { console_outbyte_polled( 0, c ); }
BSP_output_char_function_type BSP_output_char = PSIM_output_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;

View File

@@ -0,0 +1,33 @@
/*
* Adapted from the mvme-inbyte.S and mvme-outbyte.S files in libgloss.
* These should work on all targets using the ppcbug monitor.
*
* Copyright (c) 1995 Cygnus Support
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
#include "ppc-asm.h"
.file "support.s"
.text
FUNC_START(outbyte)
li r10,0x20
sc
blr
FUNC_END(outbyte)
.text
FUNC_START(inbyte)
li r10,0x0
sc
blr
FUNC_END(inbyte)

View File

@@ -0,0 +1,77 @@
/*
* This file contains the hardware specific portions of the TTY driver
* for the serial ports on the qemuppc.
*/
/*
* COPYRIGHT (c) 1989-2008.
* On-Line Applications Research Corporation (OAR).
*
* 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 <bsp.h>
#include <bsp/console-polled.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <assert.h>
static void
__outb(int port, unsigned char v)
{
*((volatile unsigned char *)(0x80000000 + port)) = v;
}
static unsigned char
__inb(int port)
{
return *((volatile unsigned char *)(0x80000000 + port));
}
/*
* console_initialize_hardware
*
* This routine initializes the console hardware.
*
*/
void console_initialize_hardware(void)
{
return;
}
/*
* console_outbyte_polled
*
* This routine transmits a character using polling.
*/
void console_outbyte_polled(
int port,
char ch
)
{
__outb(0x3f8 + 0x00, ch);
}
/*
* console_inbyte_nonblocking
*
* This routine polls for a character.
*/
int console_inbyte_nonblocking(
int port
)
{
if ( __inb(0x3f8 + 0x05) & 0x01 )
return __inb(0x3f8 + 0x00);
return -1;
}
#include <rtems/bspIo.h>
static void simBSP_output_char(char c) { console_outbyte_polled( 0, c ); }
BSP_output_char_function_type BSP_output_char = simBSP_output_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;

View File

@@ -0,0 +1,330 @@
/**
* @file
*
* @ingroup QorIQ
*
* @brief Console configuration.
*/
/*
* Copyright (c) 2010, 2017 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <string.h>
#include <libfdt.h>
#include <rtems/bspIo.h>
#include <libchip/ns16550.h>
#include <asm/epapr_hcalls.h>
#include <bsp.h>
#include <bsp/fdt.h>
#include <bsp/irq.h>
#include <bsp/qoriq.h>
#include <bsp/intercom.h>
#include <bsp/uart-bridge.h>
#include <bsp/console-termios.h>
static void output_char(char c);
#ifdef QORIQ_IS_HYPERVISOR_GUEST
typedef struct {
rtems_termios_device_context base;
uint32_t handle;
} qoriq_bc_context;
static bool qoriq_bc_probe(rtems_termios_device_context *base)
{
qoriq_bc_context *ctx;
const void *fdt;
int node;
const uint32_t *handle;
int len;
fdt = bsp_fdt_get();
node = fdt_node_offset_by_compatible(fdt, -1, "epapr,hv-byte-channel");
if (node < 0) {
return false;
}
handle = fdt_getprop(fdt, node, "hv-handle", &len);
if (handle == NULL || len != 4) {
return false;
}
ctx = (qoriq_bc_context *) base;
ctx->handle = fdt32_to_cpu(*handle);
BSP_output_char = output_char;
return true;
}
static int qoriq_bc_read_polled(rtems_termios_device_context *base)
{
qoriq_bc_context *ctx;
char buf[EV_BYTE_CHANNEL_MAX_BYTES];
unsigned int count;
unsigned int status;
ctx = (qoriq_bc_context *) base;
count = 1;
status = ev_byte_channel_receive(ctx->handle, &count, buf);
if (status != EV_SUCCESS || count == 0) {
return -1;
}
return (unsigned char) buf[0];
}
static void qoriq_bc_write_polled(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{
qoriq_bc_context *ctx;
uint32_t handle;
ctx = (qoriq_bc_context *) base;
handle = ctx->handle;
while (len > 0) {
unsigned int count;
unsigned int status;
char buf2[EV_BYTE_CHANNEL_MAX_BYTES];
const char *out;
if (len < EV_BYTE_CHANNEL_MAX_BYTES) {
count = len;
out = memcpy(buf2, buf, len);
} else {
count = EV_BYTE_CHANNEL_MAX_BYTES;
out = buf;
}
status = ev_byte_channel_send(handle, &count, out);
if (status == EV_SUCCESS) {
len -= count;
buf += count;
}
}
}
static const rtems_termios_device_handler qoriq_bc_handler_polled = {
.poll_read = qoriq_bc_read_polled,
.write = qoriq_bc_write_polled,
.mode = TERMIOS_POLLED
};
static qoriq_bc_context qoriq_bc_context_0 = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("BC 0"),
};
#endif /* QORIQ_IS_HYPERVISOR_GUEST */
#if (QORIQ_UART_0_ENABLE + QORIQ_UART_BRIDGE_0_ENABLE == 2) \
|| (QORIQ_UART_1_ENABLE + QORIQ_UART_BRIDGE_1_ENABLE == 2)
#define BRIDGE_MASTER
#elif QORIQ_UART_BRIDGE_0_ENABLE || QORIQ_UART_BRIDGE_1_ENABLE
#define BRIDGE_SLAVE
#endif
#ifdef BSP_USE_UART_INTERRUPTS
#define DEVICE_FNS &ns16550_handler_interrupt
#else
#define DEVICE_FNS &ns16550_handler_polled
#endif
#if QORIQ_UART_0_ENABLE || QORIQ_UART_1_ENABLE
static bool uart_probe(rtems_termios_device_context *base)
{
ns16550_context *ctx = (ns16550_context *) base;
ctx->clock = BSP_bus_frequency;
return ns16550_probe(base);
}
static uint8_t get_register(uintptr_t addr, uint8_t i)
{
volatile uint8_t *reg = (uint8_t *) addr;
return reg [i];
}
static void set_register(uintptr_t addr, uint8_t i, uint8_t val)
{
volatile uint8_t *reg = (uint8_t *) addr;
reg [i] = val;
}
#endif
#if QORIQ_UART_0_ENABLE
static ns16550_context qoriq_uart_context_0 = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"),
.get_reg = get_register,
.set_reg = set_register,
.port = (uintptr_t) &qoriq.uart_0,
.irq = QORIQ_IRQ_DUART_1,
.initial_baud = BSP_CONSOLE_BAUD
};
#endif
#if QORIQ_UART_1_ENABLE
static ns16550_context qoriq_uart_context_1 = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"),
.get_reg = get_register,
.set_reg = set_register,
.port = (uintptr_t) &qoriq.uart_1,
.irq = QORIQ_IRQ_DUART_1,
.initial_baud = BSP_CONSOLE_BAUD
};
#endif
#ifdef BRIDGE_MASTER
#define BRIDGE_PROBE qoriq_uart_bridge_master_probe
#define BRIDGE_FNS &qoriq_uart_bridge_master
#if QORIQ_UART_BRIDGE_0_ENABLE
static uart_bridge_master_context bridge_0_context = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"),
.device_path = "/dev/ttyS0",
.type = INTERCOM_TYPE_UART_0,
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
bridge_0_context.transmit_fifo
)
};
#define BRIDGE_0_CONTEXT &bridge_0_context.base
#endif
#if QORIQ_UART_BRIDGE_1_ENABLE
static uart_bridge_master_context bridge_1_context = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"),
.device_path = "/dev/ttyS1",
.type = INTERCOM_TYPE_UART_1,
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
bridge_1_context.transmit_fifo
)
};
#define BRIDGE_1_CONTEXT &bridge_1_context.base
#endif
#endif
#ifdef BRIDGE_SLAVE
#define BRIDGE_PROBE console_device_probe_default
#define BRIDGE_FNS &qoriq_uart_bridge_slave
#if QORIQ_UART_BRIDGE_0_ENABLE
static uart_bridge_slave_context bridge_0_context = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"),
.type = INTERCOM_TYPE_UART_0,
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
bridge_0_context.transmit_fifo
)
};
#define BRIDGE_0_CONTEXT &bridge_0_context.base
#endif
#if QORIQ_UART_BRIDGE_1_ENABLE
static uart_bridge_slave_context bridge_1_context = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"),
.type = INTERCOM_TYPE_UART_1,
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
bridge_1_context.transmit_fifo
)
};
#define BRIDGE_1_CONTEXT &bridge_1_context.base
#endif
#endif
const console_device console_device_table[] = {
#ifdef QORIQ_IS_HYPERVISOR_GUEST
{
.device_file = "/dev/ttyBC0",
.probe = qoriq_bc_probe,
.handler = &qoriq_bc_handler_polled,
.context = &qoriq_bc_context_0.base
},
#endif
#if QORIQ_UART_0_ENABLE
{
.device_file = "/dev/ttyS0",
.probe = uart_probe,
.handler = DEVICE_FNS,
.context = &qoriq_uart_context_0.base
},
#endif
#if QORIQ_UART_1_ENABLE
{
.device_file = "/dev/ttyS1",
.probe = uart_probe,
.handler = DEVICE_FNS,
.context = &qoriq_uart_context_1.base
},
#endif
#if QORIQ_UART_BRIDGE_0_ENABLE
{
#if QORIQ_UART_1_ENABLE
.device_file = "/dev/ttyB0",
#else
.device_file = "/dev/ttyS0",
#endif
.probe = BRIDGE_PROBE,
.handler = BRIDGE_FNS,
.context = BRIDGE_0_CONTEXT
},
#endif
#if QORIQ_UART_BRIDGE_1_ENABLE
{
#if QORIQ_UART_1_ENABLE
.device_file = "/dev/ttyB1",
#else
.device_file = "/dev/ttyS1",
#endif
.probe = BRIDGE_PROBE,
.handler = BRIDGE_FNS,
.context = BRIDGE_1_CONTEXT
}
#endif
};
const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table);
static void output_char(char c)
{
rtems_termios_device_context *base = console_device_table[0].context;
#ifdef QORIQ_IS_HYPERVISOR_GUEST
qoriq_bc_write_polled(base, &c, 1);
#else
ns16550_polled_putchar(base, c);
#endif
}
#ifdef QORIQ_IS_HYPERVISOR_GUEST
static void qoriq_bc_output_char_init(char c)
{
rtems_termios_device_context *base = console_device_table[0].context;
qoriq_bc_probe(base);
output_char(c);
}
BSP_output_char_function_type BSP_output_char = qoriq_bc_output_char_init;
#else
BSP_output_char_function_type BSP_output_char = output_char;
#endif
BSP_polling_getchar_function_type BSP_poll_char = NULL;

View File

@@ -0,0 +1,181 @@
/**
* @file
*
* @ingroup QorIQUartBridge
*
* @brief UART bridge master implementation.
*/
/*
* Copyright (c) 2011-2015 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <bspopts.h>
#include <bsp/uart-bridge.h>
#define TRANSMIT_EVENT RTEMS_EVENT_13
static void serial_settings(int fd)
{
struct termios term;
int rv = tcgetattr(fd, &term);
assert(rv == 0);
term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
term.c_oflag &= ~OPOST;
term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
term.c_cflag &= ~(CSIZE | PARENB);
term.c_cflag |= CS8;
term.c_cc [VMIN] = 1;
term.c_cc [VTIME] = 1;
rv = tcsetattr(fd, TCSANOW, &term);
assert(rv == 0);
}
static void uart_bridge_master_service(intercom_packet *packet, void *arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
uart_bridge_master_context *ctx = arg;
sc = rtems_chain_append_with_notification(
&ctx->transmit_fifo,
&packet->glue.node,
ctx->transmit_task,
TRANSMIT_EVENT
);
assert(sc == RTEMS_SUCCESSFUL);
}
static void receive_task(rtems_task_argument arg)
{
uart_bridge_master_context *ctx = (uart_bridge_master_context *) arg;
intercom_type type = ctx->type;
int fd = open(ctx->device_path, O_RDONLY);
assert(fd >= 0);
serial_settings(fd);
while (true) {
intercom_packet *packet = qoriq_intercom_allocate_packet(
type,
INTERCOM_SIZE_64
);
ssize_t in = read(fd, packet->data, packet->size - 1);
if (in > 0) {
packet->size = (size_t) in;
qoriq_intercom_send_packet(QORIQ_UART_BRIDGE_SLAVE_CORE, packet);
} else {
qoriq_intercom_free_packet(packet);
}
}
}
static void transmit_task(rtems_task_argument arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
uart_bridge_master_context *ctx = (uart_bridge_master_context *) arg;
rtems_chain_control *fifo = &ctx->transmit_fifo;
int fd = open(ctx->device_path, O_WRONLY);
assert(fd >= 0);
serial_settings(fd);
while (true) {
intercom_packet *packet = NULL;
sc = rtems_chain_get_with_wait(
fifo,
TRANSMIT_EVENT,
RTEMS_NO_TIMEOUT,
(rtems_chain_node **) &packet
);
assert(sc == RTEMS_SUCCESSFUL);
write(fd, packet->data, packet->size);
qoriq_intercom_free_packet(packet);
}
}
static rtems_id create_task(
char name,
rtems_task_entry entry,
uart_bridge_master_context *ctx
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
rtems_id task = RTEMS_ID_NONE;
char index = (char) ('0' + ctx->type - INTERCOM_TYPE_UART_0);
sc = rtems_task_create(
rtems_build_name('U', 'B', name, index),
QORIQ_UART_BRIDGE_TASK_PRIORITY,
0,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&task
);
assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(
task,
entry,
(rtems_task_argument) ctx
);
assert(sc == RTEMS_SUCCESSFUL);
return task;
}
bool qoriq_uart_bridge_master_probe(rtems_termios_device_context *base)
{
uart_bridge_master_context *ctx = (uart_bridge_master_context *) base;
intercom_type type = ctx->type;
qoriq_intercom_service_install(type, uart_bridge_master_service, ctx);
create_task('R', receive_task, ctx);
ctx->transmit_task = create_task('T', transmit_task, ctx);
return true;
}
static bool first_open(
struct rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
)
{
return false;
}
static bool set_attributes(
rtems_termios_device_context *base,
const struct termios *term
)
{
return false;
}
const rtems_termios_device_handler qoriq_uart_bridge_master = {
.first_open = first_open,
.set_attributes = set_attributes,
.mode = TERMIOS_POLLED
};

View File

@@ -0,0 +1,195 @@
/**
* @file
*
* @ingroup QorIQUartBridge
*
* @brief UART bridge slave implementation.
*/
/*
* Copyright (c) 2011 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 <assert.h>
#include <libchip/sersupp.h>
#include <bspopts.h>
#include <bsp/uart-bridge.h>
#define TRANSMIT_EVENT RTEMS_EVENT_13
static rtems_mode disable_preemption(void)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
rtems_mode prev_mode = 0;
sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode);
assert(sc == RTEMS_SUCCESSFUL);
return prev_mode;
}
static void restore_preemption(rtems_mode prev_mode)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
sc = rtems_task_mode (prev_mode, RTEMS_PREEMPT_MASK, &prev_mode);
assert(sc == RTEMS_SUCCESSFUL);
}
static void uart_bridge_slave_service(intercom_packet *packet, void *arg)
{
uart_bridge_slave_context *ctx = arg;
struct rtems_termios_tty *tty = ctx->tty;
/* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
rtems_mode prev_mode = disable_preemption();
rtems_termios_enqueue_raw_characters(tty, packet->data, (int) packet->size);
qoriq_intercom_free_packet(packet);
restore_preemption(prev_mode);
}
static void transmit_task(rtems_task_argument arg)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) arg;
rtems_chain_control *fifo = &ctx->transmit_fifo;
struct rtems_termios_tty *tty = ctx->tty;
while (true) {
intercom_packet *packet = NULL;
sc = rtems_chain_get_with_wait(
fifo,
TRANSMIT_EVENT,
RTEMS_NO_TIMEOUT,
(rtems_chain_node **) &packet
);
assert(sc == RTEMS_SUCCESSFUL);
/* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
rtems_mode prev_mode = disable_preemption();
size_t size = packet->size;
qoriq_intercom_send_packet(QORIQ_UART_BRIDGE_MASTER_CORE, packet);
rtems_termios_dequeue_characters(tty, (int) size);
restore_preemption(prev_mode);
}
}
static void create_transmit_task(
uart_bridge_slave_context *ctx
)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
rtems_id task = RTEMS_ID_NONE;
char index = (char) ('0' + ctx->type - INTERCOM_TYPE_UART_0);
sc = rtems_task_create(
rtems_build_name('U', 'B', 'T', index),
QORIQ_UART_BRIDGE_TASK_PRIORITY,
0,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&task
);
assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(
task,
transmit_task,
(rtems_task_argument) ctx
);
assert(sc == RTEMS_SUCCESSFUL);
ctx->transmit_task = task;
}
static bool first_open(
struct rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
)
{
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
intercom_type type = ctx->type;
ctx->tty = tty;
rtems_termios_set_initial_baud(tty, 115200);
create_transmit_task(ctx);
qoriq_intercom_service_install(type, uart_bridge_slave_service, ctx);
return true;
}
static void last_close(
struct rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args
)
{
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
qoriq_intercom_service_remove(ctx->type);
}
static void write_with_interrupts(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{
if (len > 0) {
rtems_status_code sc = RTEMS_SUCCESSFUL;
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
intercom_packet *packet = qoriq_intercom_allocate_packet(
ctx->type,
INTERCOM_SIZE_64
);
packet->size = len;
memcpy(packet->data, buf, len);
/*
* Due to the lovely Termios implementation we have to hand this over to
* another context.
*/
sc = rtems_chain_append_with_notification(
&ctx->transmit_fifo,
&packet->glue.node,
ctx->transmit_task,
TRANSMIT_EVENT
);
assert(sc == RTEMS_SUCCESSFUL);
}
}
static bool set_attributes(
rtems_termios_device_context *base,
const struct termios *term
)
{
return false;
}
const rtems_termios_device_handler qoriq_uart_bridge_slave = {
.first_open = first_open,
.last_close = last_close,
.write = write_with_interrupts,
.set_attributes = set_attributes,
.mode = TERMIOS_IRQ_DRIVEN
};

View File

@@ -0,0 +1,314 @@
/*
* console.c -- console I/O package
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* This code is based on the pc386 BSP console.c so the following
* copyright also applies :
*
* (C) Copyright 1997 -
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
*
* Till Straumann, <strauman@slac.stanford.edu>, 12/20/2001
* separate BSP specific stuff from generics...
*
* http://pandora.ist.utl.pt
*
* Instituto Superior Tecnico * Lisboa * PORTUGAL
* 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 <stdlib.h>
#include <assert.h>
#include <inttypes.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/bspIo.h>
#include <rtems/libio.h>
#include <rtems/console.h>
#include <rtems/termiostypes.h>
#include <termios.h>
#include <bsp/uart.h>
#include <rtems/bspIo.h> /* printk */
/* Definitions for BSPConsolePort */
/*
* Possible value for console input/output :
* BSP_CONSOLE_PORT_CONSOLE
* BSP_UART_COM1
* BSP_UART_COM2
*/
int BSPConsolePort = BSP_CONSOLE_PORT;
int BSPBaseBaud = BSP_UART_BAUD_BASE;
/*
* TERMIOS_OUTPUT_MODE should be a 'bspopts.h/configure'-able option;
* we could even make it a link-time option (but that would require
* small changes)...
*/
#if defined(USE_POLLED_IO)
#define TERMIOS_OUTPUT_MODE TERMIOS_POLLED
#elif defined(USE_TASK_DRIVEN_IO)
#define TERMIOS_OUTPUT_MODE TERMIOS_TASK_DRIVEN
#else
#define TERMIOS_OUTPUT_MODE TERMIOS_IRQ_DRIVEN
#endif
/*-------------------------------------------------------------------------+
| External Prototypes
+--------------------------------------------------------------------------*/
static int conSetAttr(int minor, const struct termios *);
typedef struct TtySTblRec_ {
char *name;
rtems_irq_hdl isr;
} TtySTblRec, *TtySTbl;
static TtySTblRec ttyS[]={
{ "/dev/ttyS0",
#ifdef BSP_UART_IOBASE_COM1
BSP_uart_termios_isr_com1
#else
0
#endif
},
{ "/dev/ttyS1",
#ifdef BSP_UART_IOBASE_COM2
BSP_uart_termios_isr_com2
#else
0
#endif
},
};
/*-------------------------------------------------------------------------+
| Console device driver INITIALIZE entry point.
+--------------------------------------------------------------------------+
| Initilizes the I/O console (keyboard + VGA display) driver.
+--------------------------------------------------------------------------*/
rtems_device_driver console_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_status_code status;
/*
* The video was initialized in the start.s code and does not need
* to be reinitialized.
*/
/*
* Set up TERMIOS
*/
rtems_termios_initialize();
/*
* Do device-specific initialization
*/
/* RTEMS calls this routine once with 'minor'==0; loop through
* all known instances...
*/
for (minor=0; minor < sizeof(ttyS)/sizeof(ttyS[0]); minor++) {
char *nm;
/*
* Skip ports (possibly not supported by BSP...) we have no ISR for
*/
if ( ! ttyS[minor].isr )
continue;
/*
* Register the device
*/
status = rtems_io_register_name ((nm=ttyS[minor].name), major, minor);
if ( RTEMS_SUCCESSFUL==status && BSPConsolePort == minor) {
printk("Registering /dev/console as minor %" PRIu32 " (==%s)\n",
minor,
ttyS[minor].name);
/* also register an alias */
status = rtems_io_register_name ( (nm="/dev/console"), major, minor);
}
if (status != RTEMS_SUCCESSFUL) {
printk("Error registering %s!\n",nm);
rtems_fatal_error_occurred (status);
}
}
return RTEMS_SUCCESSFUL;
} /* console_initialize */
#if !defined(USE_POLLED_IO)
static int console_first_open(int major, int minor, void *arg)
{
rtems_status_code status;
/* must not open a minor device we have no ISR for */
assert( minor>=0 && minor < sizeof(ttyS)/sizeof(ttyS[0]) && ttyS[minor].isr );
/* 9600-8-N-1 */
BSP_uart_init(minor, 9600, 0);
status = BSP_uart_install_isr(minor, ttyS[minor].isr);
if (!status) {
printk("Error installing serial console interrupt handler for '%s'!\n",
ttyS[minor].name);
rtems_fatal_error_occurred(status);
}
/*
* Pass data area info down to driver
*/
BSP_uart_termios_set(minor, ((rtems_libio_open_close_args_t *)arg)->iop->data1);
/* Enable interrupts on channel */
BSP_uart_intr_ctrl(minor, BSP_UART_INTR_CTRL_TERMIOS);
return 0;
}
#endif
#if !defined(USE_POLLED_IO)
static int console_last_close(int major, int minor, void *arg)
{
BSP_uart_remove_isr(minor, ttyS[minor].isr);
return 0;
}
#endif
/*-------------------------------------------------------------------------+
| Console device driver OPEN entry point
+--------------------------------------------------------------------------*/
rtems_device_driver console_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_status_code status;
static rtems_termios_callbacks cb =
#if defined(USE_POLLED_IO)
{
NULL, /* firstOpen */
NULL, /* lastClose */
NULL, /* pollRead */
BSP_uart_termios_write_polled, /* write */
conSetAttr, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_POLLED /* outputUsesInterrupts */
};
#else
{
console_first_open, /* firstOpen */
console_last_close, /* lastClose */
#ifdef USE_TASK_DRIVEN_IO
BSP_uart_termios_read_com, /* pollRead */
#else
NULL, /* pollRead */
#endif
BSP_uart_termios_write_com, /* write */
conSetAttr, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_OUTPUT_MODE /* outputUsesInterrupts */
};
#endif
status = rtems_termios_open (major, minor, arg, &cb);
if (status != RTEMS_SUCCESSFUL) {
printk("Error opening console device\n");
return status;
}
return RTEMS_SUCCESSFUL;
}
/*-------------------------------------------------------------------------+
| Console device driver CLOSE entry point
+--------------------------------------------------------------------------*/
rtems_device_driver
console_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
rtems_device_driver res = RTEMS_SUCCESSFUL;
res = rtems_termios_close (arg);
return res;
} /* console_close */
/*-------------------------------------------------------------------------+
| Console device driver READ entry point.
+--------------------------------------------------------------------------+
| Read characters from the I/O console. We only have stdin.
+--------------------------------------------------------------------------*/
rtems_device_driver console_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
return rtems_termios_read (arg);
} /* console_read */
/*-------------------------------------------------------------------------+
| Console device driver WRITE entry point.
+--------------------------------------------------------------------------+
| Write characters to the I/O console. Stderr and stdout are the same.
+--------------------------------------------------------------------------*/
rtems_device_driver console_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
return rtems_termios_write (arg);
} /* console_write */
/*
* Handle ioctl request.
*/
rtems_device_driver console_control(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
/* does the BSP support break callbacks ? */
#if defined(BIOCSETBREAKCB) && defined(BIOCGETBREAKCB)
rtems_libio_ioctl_args_t *ioa=arg;
switch (ioa->command) {
case BIOCSETBREAKCB: return BSP_uart_set_break_cb(minor, ioa);
case BIOCGETBREAKCB: return BSP_uart_get_break_cb(minor, ioa);
default: break;
}
#endif
return rtems_termios_ioctl (arg);
}
static int conSetAttr(
int minor,
const struct termios *t
)
{
rtems_termios_baud_t baud;
baud = rtems_termios_baud_to_number(t->c_ospeed);
if ( baud > 115200 )
rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
BSP_uart_set_baud(minor, baud);
return 0;
}

View File

@@ -0,0 +1,781 @@
/*
* This software is Copyright (C) 1998 by T.sqware - all rights limited
* It is provided in to the public domain "as is", can be freely modified
* as far as this copyight notice is kept unchanged, but does not imply
* an endorsement by T.sqware of the product in which it is included.
*/
#include <stdint.h>
#include <stdio.h>
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/uart.h>
#include <rtems/libio.h>
#include <rtems/bspIo.h>
#include <rtems/termiostypes.h>
#include <termios.h>
#include <assert.h>
/*
* Basic 16552 driver
*/
struct uart_data
{
unsigned long ioBase;
int irq;
int hwFlow;
int baud;
BSP_UartBreakCbRec breakCallback;
int ioMode;
};
/*
* Initialization of BSP specific data.
* The constants are pulled in from a BSP
* specific file, whereas all of the code
* in this file is generic and makes no
* assumptions about addresses, irq vectors
* etc...
*/
#define UART_UNSUPP ((unsigned long)(-1))
static struct uart_data uart_data[2] = {
{
#ifdef BSP_UART_IOBASE_COM1
BSP_UART_IOBASE_COM1,
BSP_UART_COM1_IRQ,
#else
UART_UNSUPP,
-1,
#endif
},
{
#ifdef BSP_UART_IOBASE_COM2
BSP_UART_IOBASE_COM2,
BSP_UART_COM2_IRQ,
#else
UART_UNSUPP,
-1,
#endif
},
};
#define MAX_UARTS (sizeof(uart_data)/sizeof(uart_data[0]))
#define SANITY_CHECK(uart) \
assert( MAX_UARTS > (unsigned)(uart) && uart_data[(uart)].ioBase != UART_UNSUPP )
/*
* Macros to read/write register of uart, if configuration is
* different just rewrite these macros
*/
static inline unsigned char
uread(int uart, unsigned int reg)
{
return in_8((uint8_t*)(uart_data[uart].ioBase + reg));
}
static inline void
uwrite(int uart, int reg, unsigned int val)
{
out_8((uint8_t*)(uart_data[uart].ioBase + reg), val);
}
static void
uartError(int uart, void *termiosPrivate)
{
unsigned char uartStatus, dummy;
BSP_UartBreakCbProc h;
uartStatus = uread(uart, LSR);
dummy = uread(uart, RBR);
#ifdef UARTDEBUG
if (uartStatus & OE)
printk("********* Over run Error **********\n");
if (uartStatus & PE)
printk("********* Parity Error **********\n");
if (uartStatus & FE)
printk("********* Framing Error **********\n");
if (uartStatus & BI) {
printk("********* BREAK INTERRUPT *********\n");
#endif
if ((h=uart_data[uart].breakCallback.handler)) {
h(uart,
(dummy<<8)|uartStatus,
termiosPrivate,
uart_data[uart].breakCallback.private);
}
#ifdef UARTDEBUG
if (uartStatus & ERFIFO)
printk("********* Error receive Fifo **********\n");
#endif
}
/*
* Uart initialization, it is hardcoded to 8 bit, no parity,
* one stop bit, FIFO, things to be changed
* are baud rate and nad hw flow control,
* and longest rx fifo setting
*/
void
BSP_uart_init(int uart, int baud, int hwFlow)
{
unsigned char tmp;
/* Sanity check */
SANITY_CHECK(uart);
/* Make sure any printk activity drains before
* re-initializing.
*/
while ( ! (uread(uart, LSR) & TEMT) )
;
switch(baud)
{
case 50:
case 75:
case 110:
case 134:
case 300:
case 600:
case 1200:
case 2400:
case 9600:
case 19200:
case 38400:
case 57600:
case 115200:
break;
default:
assert(0);
return;
}
/* Set DLAB bit to 1 */
uwrite(uart, LCR, DLAB);
if ( (int)BSPBaseBaud <= 0 ) {
/* Use current divisor assuming BSPBaseBaud gives us the current speed */
BSPBaseBaud = BSPBaseBaud ? -BSPBaseBaud : 9600;
BSPBaseBaud *= ((uread(uart, DLM) << 8) | uread(uart, DLL));
}
/* Set baud rate */
uwrite(uart, DLL, (BSPBaseBaud/baud) & 0xff);
uwrite(uart, DLM, ((BSPBaseBaud/baud) >> 8) & 0xff);
/* 8-bit, no parity , 1 stop */
uwrite(uart, LCR, CHR_8_BITS);
/* Set DTR, RTS and OUT2 high */
uwrite(uart, MCR, DTR | RTS | OUT_2);
/* Enable FIFO */
uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
/* Disable Interrupts */
uwrite(uart, IER, 0);
/* Read status to clear them */
tmp = uread(uart, LSR);
tmp = uread(uart, RBR);
tmp = uread(uart, MSR);
(void) tmp; /* avoid set but not used warning */
/* Remember state */
uart_data[uart].hwFlow = hwFlow;
uart_data[uart].baud = baud;
return;
}
/*
* Set baud
*/
void
BSP_uart_set_baud(int uart, int baud)
{
unsigned char mcr, ier;
/* Sanity check */
SANITY_CHECK(uart);
/*
* This function may be called whenever TERMIOS parameters
* are changed, so we have to make sure that baud change is
* indeed required.
*/
if(baud == uart_data[uart].baud)
{
return;
}
mcr = uread(uart, MCR);
ier = uread(uart, IER);
BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
uwrite(uart, MCR, mcr);
uwrite(uart, IER, ier);
return;
}
/*
* Enable/disable interrupts
*/
void
BSP_uart_intr_ctrl(int uart, int cmd)
{
SANITY_CHECK(uart);
switch(cmd)
{
case BSP_UART_INTR_CTRL_DISABLE:
uwrite(uart, IER, INTERRUPT_DISABLE);
break;
case BSP_UART_INTR_CTRL_ENABLE:
if(uart_data[uart].hwFlow)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
break;
case BSP_UART_INTR_CTRL_TERMIOS:
if(uart_data[uart].hwFlow)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
break;
case BSP_UART_INTR_CTRL_GDB:
uwrite(uart, IER, RECEIVE_ENABLE);
break;
default:
assert(0);
break;
}
return;
}
void
BSP_uart_throttle(int uart)
{
unsigned int mcr;
SANITY_CHECK(uart);
if(!uart_data[uart].hwFlow)
{
/* Should not happen */
assert(0);
return;
}
mcr = uread (uart, MCR);
/* RTS down */
mcr &= ~RTS;
uwrite(uart, MCR, mcr);
return;
}
void
BSP_uart_unthrottle(int uart)
{
unsigned int mcr;
SANITY_CHECK(uart);
if(!uart_data[uart].hwFlow)
{
/* Should not happen */
assert(0);
return;
}
mcr = uread (uart, MCR);
/* RTS up */
mcr |= RTS;
uwrite(uart, MCR, mcr);
return;
}
/*
* Status function, -1 if error
* detected, 0 if no received chars available,
* 1 if received char available, 2 if break
* is detected, it will eat break and error
* chars. It ignores overruns - we cannot do
* anything about - it execpt count statistics
* and we are not counting it.
*/
int
BSP_uart_polled_status(int uart)
{
unsigned char val;
SANITY_CHECK(uart);
val = uread(uart, LSR);
if(val & BI)
{
/* BREAK found, eat character */
uread(uart, RBR);
return BSP_UART_STATUS_BREAK;
}
if((val & (DR | OE | FE)) == 1)
{
/* No error, character present */
return BSP_UART_STATUS_CHAR;
}
if((val & (DR | OE | FE)) == 0)
{
/* Nothing */
return BSP_UART_STATUS_NOCHAR;
}
/*
* Framing or parity error
* eat character
*/
uread(uart, RBR);
return BSP_UART_STATUS_ERROR;
}
/*
* Polled mode write function
*/
void
BSP_uart_polled_write(int uart, int val)
{
unsigned char val1;
/* Sanity check */
SANITY_CHECK(uart);
for(;;)
{
if((val1=uread(uart, LSR)) & THRE)
{
break;
}
}
if(uart_data[uart].hwFlow)
{
for(;;)
{
if(uread(uart, MSR) & CTS)
{
break;
}
}
}
uwrite(uart, THR, val & 0xff);
return;
}
void
BSP_output_char_via_serial(const char val)
{
BSP_uart_polled_write(BSPConsolePort, val);
}
/*
* Polled mode read function
*/
int
BSP_uart_polled_read(int uart)
{
unsigned char val;
SANITY_CHECK(uart);
for(;;)
{
if(uread(uart, LSR) & DR)
{
break;
}
}
val = uread(uart, RBR);
return (int)(val & 0xff);
}
unsigned
BSP_poll_char_via_serial()
{
return BSP_uart_polled_read(BSPConsolePort);
}
static void
uart_noop(const rtems_irq_connect_data *unused)
{
return;
}
/* note that the IRQ names contain _ISA_ for legacy
* reasons. They can be any interrupt, depending
* on the particular BSP...
*/
static int
uart_isr_is_on(const rtems_irq_connect_data *irq)
{
int uart;
uart = (irq->name == BSP_UART_COM1_IRQ) ?
BSP_UART_COM1 : BSP_UART_COM2;
return uread(uart,IER);
}
static int
doit(int uart, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*))
{
rtems_irq_connect_data d={0};
d.name = uart_data[uart].irq;
d.off = d.on = uart_noop;
d.isOn = uart_isr_is_on;
d.hdl = handler;
return p(&d);
}
int
BSP_uart_install_isr(int uart, rtems_irq_hdl handler)
{
/* Using shared interrupts by default might break things.. the
* shared IRQ installer uses malloc() and if a BSP had called this
* during early init it might not work...
*/
#ifdef BSP_UART_USE_SHARED_IRQS
return doit(uart, handler, BSP_install_rtems_shared_irq_handler);
#else
return doit(uart, handler, BSP_install_rtems_irq_handler);
#endif
}
int
BSP_uart_remove_isr(int uart, rtems_irq_hdl handler)
{
return doit(uart, handler, BSP_remove_rtems_irq_handler);
}
/* ================ Termios support =================*/
static volatile int termios_stopped_com[2] = {0,0};
static volatile int termios_tx_active_com[2] = {0,0};
static void* termios_ttyp_com[2] = {NULL,NULL};
static char termios_tx_hold_com[2] = {0,0};
static volatile char termios_tx_hold_valid_com[2] = {0,0};
/*
* Set channel parameters
*/
void
BSP_uart_termios_set(int uart, void *p)
{
struct rtems_termios_tty *ttyp = p;
unsigned char val;
SANITY_CHECK(uart);
if(uart_data[uart].hwFlow)
{
val = uread(uart, MSR);
termios_stopped_com[uart] = (val & CTS) ? 0 : 1;
}
else
{
termios_stopped_com[uart] = 0;
}
termios_tx_active_com[uart] = 0;
termios_ttyp_com[uart] = ttyp;
termios_tx_hold_com[uart] = 0;
termios_tx_hold_valid_com[uart] = 0;
uart_data[uart].ioMode = ttyp->device.outputUsesInterrupts;
return;
}
ssize_t
BSP_uart_termios_write_polled(int minor, const char *buf, size_t len)
{
int uart=minor; /* could differ, theoretically */
int nwrite;
const char *b = buf;
for (nwrite=0 ; nwrite < len ; nwrite++) {
BSP_uart_polled_write(uart, *b++);
}
return nwrite;
}
ssize_t
BSP_uart_termios_write_com(int minor, const char *buf, size_t len)
{
int uart=minor; /* could differ, theoretically */
if(len <= 0)
{
return 0;
}
/* If the TX buffer is busy - something is royally screwed up */
/* assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
if(termios_stopped_com[uart])
{
/* CTS low */
termios_tx_hold_com[uart] = *buf;
termios_tx_hold_valid_com[uart] = 1;
return 0;
}
/* Write character */
uwrite(uart, THR, *buf & 0xff);
/* Enable interrupts if necessary */
if(!termios_tx_active_com[uart] && uart_data[uart].hwFlow)
{
termios_tx_active_com[uart] = 1;
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else if(!termios_tx_active_com[uart])
{
termios_tx_active_com[uart] = 1;
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
return 0;
}
int
BSP_uart_termios_read_com(int uart)
{
int off = (int)0;
char buf[40];
rtems_interrupt_level l;
/* read bytes */
while (( off < sizeof(buf) ) && ( uread(uart, LSR) & DR )) {
buf[off++] = uread(uart, RBR);
}
/* write out data */
if ( off > 0 ) {
rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart], buf, off);
}
/* enable receive interrupts */
rtems_interrupt_disable(l);
uwrite(uart, IER, uread(uart, IER) | (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE));
rtems_interrupt_enable(l);
return ( EOF );
}
static void
BSP_uart_termios_isr_com(int uart)
{
unsigned char buf[40];
unsigned char val, ier;
int off, ret, vect;
off = 0;
for(;;)
{
vect = uread(uart, IIR) & 0xf;
switch(vect)
{
case MODEM_STATUS :
val = uread(uart, MSR);
if(uart_data[uart].hwFlow)
{
if(val & CTS)
{
/* CTS high */
termios_stopped_com[uart] = 0;
if(termios_tx_hold_valid_com[uart])
{
termios_tx_hold_valid_com[uart] = 0;
BSP_uart_termios_write_com(uart, &termios_tx_hold_com[uart],
1);
}
}
else
{
/* CTS low */
termios_stopped_com[uart] = 1;
}
}
break;
case NO_MORE_INTR :
/* No more interrupts */
if(off != 0)
{
/* Update rx buffer */
rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart],
(char *)buf,
off);
}
return;
case TRANSMITTER_HODING_REGISTER_EMPTY :
/*
* TX holding empty: we have to disable these interrupts
* if there is nothing more to send.
*/
ret = rtems_termios_dequeue_characters(termios_ttyp_com[uart], 1);
/* If nothing else to send disable interrupts */
if(ret == 0 && uart_data[uart].hwFlow)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
termios_tx_active_com[uart] = 0;
}
else if(ret == 0)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
termios_tx_active_com[uart] = 0;
}
break;
case RECEIVER_DATA_AVAIL :
case CHARACTER_TIMEOUT_INDICATION:
if ( uart_data[uart].ioMode == TERMIOS_TASK_DRIVEN )
{
/* ensure interrupts are enabled */
if ( (ier = uread(uart,IER)) & RECEIVE_ENABLE )
{
/* disable interrupts and notify termios */
ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
uwrite(uart, IER, ier);
rtems_termios_rxirq_occured(termios_ttyp_com[uart]);
}
}
else
{
/* RX data ready */
assert(off < sizeof(buf));
while ( off < sizeof(buf) && ( DR & uread(uart, LSR) ) )
buf[off++] = uread(uart, RBR);
}
break;
case RECEIVER_ERROR:
/* RX error: eat character */
uartError(uart, termios_ttyp_com[uart]);
break;
default:
/* Should not happen */
assert(0);
return;
}
}
}
/*
* XXX - Note that this can now be one isr with the uart
* passed as the parameter.
*/
void
BSP_uart_termios_isr_com1(void *unused)
{
BSP_uart_termios_isr_com(BSP_UART_COM1);
}
void
BSP_uart_termios_isr_com2(void *unused)
{
BSP_uart_termios_isr_com(BSP_UART_COM2);
}
/* retrieve 'break' handler info */
int
BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
{
BSP_UartBreakCb cb=arg->buffer;
unsigned long flags;
SANITY_CHECK(uart);
rtems_interrupt_disable(flags);
*cb = uart_data[uart].breakCallback;
rtems_interrupt_enable(flags);
arg->ioctl_return=0;
return RTEMS_SUCCESSFUL;
}
/* install 'break' handler */
int
BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
{
BSP_UartBreakCb cb=arg->buffer;
unsigned long flags;
SANITY_CHECK(uart);
rtems_interrupt_disable(flags);
uart_data[uart].breakCallback = *cb;
rtems_interrupt_enable(flags);
arg->ioctl_return=0;
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,371 @@
/*
* console.c
*
* This file contains the Intec SS555 termios serial I/O package.
*
* The SCI channels are assigned as follows
*
* Channel Device Minor
* SCI1 /dev/tty0 0
* SCI2 /dev/tty1 1
*
* All ports support termios. The use of termios is recommended for real-time
* applications. Termios provides buffering and input processing. When not
* using termios, processing is limited to the substitution of LF for CR on
* input, and the output of a CR following the output of a LF character.
* Note that the terminal should not send CR/LF pairs when the return key
* is pressed, and that output lines are terminated with LF/CR, not CR/LF
* (although that would be easy to change).
*
* I/O may be interrupt-driven (recommended for real-time applications) or
* polled.
*
* LIMITATIONS:
*
* It is not possible to use different I/O modes on the different ports. The
* exception is with printk. The printk port can use a different mode from
* the other ports. If this is done, it is important not to open the printk
* port from an RTEMS application.
*
* Currently, the I/O modes are determined at build time. It would be much
* better to have the mode selected at boot time based on parameters in
* NVRAM.
*
* Interrupt-driven I/O requires termios.
*
* TESTS:
*
* TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
* play with the interrupt masks and turn off I/O. Those tests will hang
* when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
* from the static constructors before the console is open. This test
* will not work with interrupt-driven I/O. Because of the buffering
* performed in termios, test output may not be in sequence.The tests
* should all be fixed to work with interrupt-driven I/O and to
* produce output in the expected sequence. Obviously, the termios test
* requires termios support in the driver.
*
* Set CONSOLE_MINOR to the appropriate device minor number in the
* config file. This allows the RTEMS application console to be different
* from the GDB port.
*
* This driver handles both 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.
*
*
* SS555 port sponsored by Defence Research and Development Canada - Suffield
* Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
*
* Derived from c/src/lib/libbsp/powerpc/mbx8xx/console/console.c:
*
* 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) 2000, National Research Council of Canada
*
*/
#include <stdarg.h>
#include <stdio.h>
#include <termios.h>
#include <rtems/console.h>
#include <rtems/bspIo.h>
#include <rtems/libio.h>
#include <bsp.h> /* Must be before libio.h */
static void _BSP_output_char( char c );
static rtems_status_code do_poll_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
static rtems_status_code do_poll_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
static void _BSP_null_char( char c ) {return;}
BSP_output_char_function_type BSP_output_char = _BSP_null_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;
/*
* do_poll_read
*
* Input characters through polled I/O. Returns as soon as a character has
* been received. Otherwise, if we wait for the number of requested
* characters, we could be here forever!
*
* CR is converted to LF on input. The terminal should not send a CR/LF pair
* when the return or enter key is pressed.
*
* Input parameters:
* major - ignored. Should be the major number for this driver.
* minor - selected channel.
* arg->buffer - where to put the received characters.
* arg->count - number of characters to receive before returning--Ignored.
*
* Output parameters:
* arg->bytes_moved - the number of characters read. Always 1.
*
* Return value: RTEMS_SUCCESSFUL
*
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
*/
static rtems_status_code do_poll_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
)
{
rtems_libio_rw_args_t *rw_args = arg;
int c;
while( (c = m5xx_uart_pollRead(minor)) == -1 );
rw_args->buffer[0] = (uint8_t)c;
if( rw_args->buffer[0] == '\r' )
rw_args->buffer[0] = '\n';
rw_args->bytes_moved = 1;
return RTEMS_SUCCESSFUL;
}
/*
* do_poll_write
*
* Output characters through polled I/O. Returns only once every character has
* been sent.
*
* CR is transmitted AFTER a LF on output.
*
* Input parameters:
* major - ignored. Should be the major number for this driver.
* minor - selected channel
* arg->buffer - where to get the characters to transmit.
* arg->count - the number of characters to transmit before returning.
*
* Output parameters:
* arg->bytes_moved - the number of characters read
*
* Return value: RTEMS_SUCCESSFUL
*
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
*/
static rtems_status_code do_poll_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
)
{
rtems_libio_rw_args_t *rw_args = arg;
uint32_t i;
char cr ='\r';
for( i = 0; i < rw_args->count; i++ ) {
m5xx_uart_pollWrite(minor, &(rw_args->buffer[i]), 1);
if ( rw_args->buffer[i] == '\n' )
m5xx_uart_pollWrite(minor, &cr, 1);
}
rw_args->bytes_moved = i;
return RTEMS_SUCCESSFUL;
}
/*
* Print functions prototyped in bspIo.h
*/
static void _BSP_output_char( char c )
{
char cr = '\r';
/*
* Can't rely on console_initialize having been called before this
* function is used, so it may fail.
*/
m5xx_uart_pollWrite( PRINTK_MINOR, &c, 1 );
if( c == '\n' )
m5xx_uart_pollWrite( PRINTK_MINOR, &cr, 1 );
}
/*
***************
* 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 if needed
*/
#if UARTS_USE_TERMIOS == 1
rtems_termios_initialize ();
#endif /* UARTS_USE_TERMIOS */
/*
* Do device-specific initialization
*/
BSP_output_char = _BSP_output_char;
m5xx_uart_initialize(SCI1_MINOR);
status = rtems_io_register_name ("/dev/tty0", major, SCI1_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
m5xx_uart_initialize(SCI2_MINOR);
status = rtems_io_register_name ("/dev/tty1", major, SCI2_MINOR);
if (status != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (status);
/* 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
)
{
rtems_status_code sc;
if ( minor > NUM_PORTS - 1 )
return RTEMS_INVALID_NUMBER;
#if (UARTS_USE_TERMIOS == 1)
{
#if (UARTS_IO_MODE == 1) /* RTEMS interrupt-driven I/O with termios */
static const rtems_termios_callbacks callbacks = {
m5xx_uart_firstOpen, /* firstOpen */
m5xx_uart_lastClose, /* lastClose */
NULL, /* pollRead */
m5xx_uart_write, /* write */
m5xx_uart_setAttributes, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
};
sc = rtems_termios_open( major, minor, arg, &callbacks );
#else /* UARTS_IO_MODE != 1 */ /* RTEMS polled I/O with termios */
static const rtems_termios_callbacks callbacks = {
m5xx_uart_firstOpen, /* firstOpen */
m5xx_uart_lastClose, /* lastClose */
m5xx_uart_pollRead, /* pollRead */
m5xx_uart_pollWrite, /* write */
m5xx_uart_setAttributes, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_POLLED /* outputUsesInterrupts */
};
sc = rtems_termios_open( major, minor, arg, &callbacks );
#endif
return sc;
}
#else /* no termios -- default to polled I/O */
{
sc = RTEMS_SUCCESSFUL;
}
#endif
return sc;
}
/*
* Close the device
*/
rtems_device_driver console_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_close( arg );
#else
return RTEMS_SUCCESSFUL;
#endif
}
/*
* Read from the device
*/
rtems_device_driver console_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_read( arg );
#else
return do_poll_read( major, minor, arg );
#endif
}
/*
* Write to the device
*/
rtems_device_driver console_write(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_write( arg );
#else
return do_poll_write( major, minor, arg );
#endif
}
/*
* Handle ioctl request.
*/
rtems_device_driver console_control(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
if ( minor > NUM_PORTS-1 )
return RTEMS_INVALID_NUMBER;
#if UARTS_USE_TERMIOS == 1
return rtems_termios_ioctl( arg );
#else
return RTEMS_SUCCESSFUL;
#endif
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2012, 2015 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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.
*/
/*
* Console driver for Lauterbach Trace32 Simulator. The implementation is
* based on the example in "demo/powerpc/etc/terminal/terminal_mpc85xx.cmm" in
* the Trace32 system directory.
*/
#include <rtems/bspIo.h>
#include <rtems/console.h>
#include <rtems/termiostypes.h>
volatile unsigned char messagebufferin[256];
volatile unsigned char messagebufferout[256];
typedef struct {
rtems_termios_device_context base;
int input_size;
int input_index;
} t32_console_context;
static t32_console_context t32_console_instance;
static bool t32_console_first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
)
{
rtems_termios_set_initial_baud(tty, 115200);
return true;
}
static int t32_console_read_polled(rtems_termios_device_context *base)
{
t32_console_context *ctx = (t32_console_context *) base;
int c;
if (ctx->input_size == 0) {
int new_bufsize = messagebufferin[0];
if (new_bufsize != 0) {
ctx->input_size = new_bufsize;
ctx->input_index = 0;
} else {
return -1;
}
}
c = messagebufferin[4 + ctx->input_index];
++ctx->input_index;
if (ctx->input_index >= ctx->input_size) {
messagebufferin[0] = 0;
ctx->input_size = 0;
}
return c;
}
static void t32_console_write_char_polled(char c)
{
while (messagebufferout[0] != 0) {
/* Wait for ready */
}
messagebufferout[4] = (unsigned char) c;
messagebufferout[0] = 1;
}
static void t32_console_write_polled(
rtems_termios_device_context *base,
const char *s,
size_t n
)
{
size_t i;
for (i = 0; i < n; ++i) {
t32_console_write_char_polled(s[i]);
}
}
const rtems_termios_device_handler t32_console_handler = {
.first_open = t32_console_first_open,
.poll_read = t32_console_read_polled,
.write = t32_console_write_polled,
.mode = TERMIOS_POLLED
};
rtems_device_driver console_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg
)
{
t32_console_context *ctx = &t32_console_instance;
rtems_termios_initialize();
rtems_termios_device_context_initialize(&ctx->base, "T32 Console");
rtems_termios_device_install(
CONSOLE_DEVICE_NAME,
&t32_console_handler,
NULL,
&ctx->base
);
return RTEMS_SUCCESSFUL;
}
BSP_output_char_function_type BSP_output_char = t32_console_write_char_polled;
BSP_polling_getchar_function_type BSP_poll_char = NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,425 @@
/*
* This file contains the console driver for the xilinx uart lite.
*
* Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
* COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland.
*
* Derived from libbsp/no_cpu/no_bsp/console.c and therefore also:
*
* COPYRIGHT (c) 1989-1999.
* On-Line Applications Research Corporation (OAR).
*
* 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 <assert.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <bsp/irq.h>
#include <bsp.h>
#include <libchip/serial.h>
#include <libchip/sersupp.h>
#include RTEMS_XPARAMETERS_H
/* Status Register Masks */
#define PARITY_ERROR 0x80 /* Parity Error */
#define FRAME_ERROR 0x40 /* Frame Error */
#define OVERRUN_ERROR 0x20 /* Overrun Error */
#define STATUS_REG_ERROR_MASK ( PARITY_ERROR | FRAME_ERROR | OVERRUN_ERROR )
#define INTR_ENABLED 0x10 /* Interrupts are enabled */
#define TX_FIFO_FULL 0x08 /* Transmit FIFO is full */
#define TX_FIFO_EMPTY 0x04 /* Transmit FIFO is empty */
#define RX_FIFO_FULL 0x02 /* Receive FIFO is full */
#define RX_FIFO_VALID_DATA 0x01 /* Receive FIFO has valid data */
/* Control Register Masks*/
#define ENABLE_INTR 0x10 /* Enable interrupts */
#define RST_RX_FIFO 0x02 /* Reset and clear RX FIFO */
#define RST_TX_FIFO 0x01 /* Reset and clear TX FIFO */
/* General Defines */
#define TX_FIFO_SIZE 16
#define RX_FIFO_SIZE 16
#define RECV_REG 0
#define TRAN_REG 4
#define STAT_REG 8
#define CTRL_REG 12
RTEMS_INLINE_ROUTINE uint32_t xlite_uart_control(uint32_t base)
{
uint32_t c = *((volatile uint32_t*)(base+CTRL_REG));
return c;
}
RTEMS_INLINE_ROUTINE uint32_t xlite_uart_status(uint32_t base)
{
uint32_t c = *((volatile uint32_t*)(base+STAT_REG));
return c;
}
RTEMS_INLINE_ROUTINE uint32_t xlite_uart_read(uint32_t base)
{
uint32_t c = *((volatile uint32_t*)(base+RECV_REG));
return c;
}
RTEMS_INLINE_ROUTINE void xlite_uart_write(uint32_t base, char ch)
{
*(volatile uint32_t*)(base+TRAN_REG) = (uint32_t)ch;
return;
}
static int xlite_write_char(uint32_t base, char ch)
{
uint32_t retrycount= 0, idler, status;
while( ((status = xlite_uart_status(base)) & TX_FIFO_FULL) != 0 )
{
++retrycount;
/* uart tx is busy */
if( retrycount == 0x4000 )
{
/* retrycount is arbitrary- just make it big enough so the uart is sure to be timed out before it trips */
return -1;
}
/* spin for a bit so we can sample the register rather than
* continually reading it */
for( idler= 0; idler < 0x2000; idler++);
}
xlite_uart_write(base, ch);
return 1;
}
static void xlite_init(int minor )
{
/* Nothing to do */
}
#if VIRTEX_CONSOLE_USE_INTERRUPTS
static void xlite_interrupt_handler(void *arg)
{
int minor = (int) arg;
const console_tbl *ct = Console_Port_Tbl[minor];
console_data *cd = &Console_Port_Data[minor];
uint32_t base = ct->ulCtrlPort1;
uint32_t status = xlite_uart_status(base);
while ((status & RX_FIFO_VALID_DATA) != 0) {
char c = (char) xlite_uart_read(base);
rtems_termios_enqueue_raw_characters(cd->termios_data, &c, 1);
status = xlite_uart_status(base);
}
if (cd->bActive) {
rtems_termios_dequeue_characters(cd->termios_data, 1);
}
}
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
static int xlite_open(
int major,
int minor,
void *arg
)
{
const console_tbl *ct = Console_Port_Tbl[minor];
uint32_t base = ct->ulCtrlPort1;
#if VIRTEX_CONSOLE_USE_INTERRUPTS
rtems_status_code sc;
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
/* clear status register */
*((volatile uint32_t*)(base+STAT_REG)) = 0;
/* clear control register; reset fifos */
*((volatile uint32_t*)(base+CTRL_REG)) = RST_RX_FIFO | RST_TX_FIFO;
#if VIRTEX_CONSOLE_USE_INTERRUPTS
*((volatile uint32_t*)(base+CTRL_REG)) = ENABLE_INTR;
sc = rtems_interrupt_handler_install(
ct->ulIntVector,
"xlite",
RTEMS_INTERRUPT_UNIQUE,
xlite_interrupt_handler,
(void *) minor
);
assert(sc == RTEMS_SUCCESSFUL);
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
return 0;
}
static int xlite_close(
int major,
int minor,
void *arg
)
{
const console_tbl *ct = Console_Port_Tbl[minor];
uint32_t base = ct->ulCtrlPort1;
#if VIRTEX_CONSOLE_USE_INTERRUPTS
rtems_status_code sc;
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
*((volatile uint32_t*)(base+CTRL_REG)) = 0;
#if VIRTEX_CONSOLE_USE_INTERRUPTS
sc = rtems_interrupt_handler_remove(
ct->ulIntVector,
xlite_interrupt_handler,
(void *) minor
);
assert(sc == RTEMS_SUCCESSFUL);
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
return 0;
}
static int xlite_read_polled (int minor )
{
uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
unsigned int status = xlite_uart_status(base);
if(status & RX_FIFO_VALID_DATA)
return (int)xlite_uart_read(base);
else
return -1;
}
#if VIRTEX_CONSOLE_USE_INTERRUPTS
static ssize_t xlite_write_interrupt_driven(
int minor,
const char *buf,
size_t len
)
{
console_data *cd = &Console_Port_Data[minor];
if (len > 0) {
const console_tbl *ct = Console_Port_Tbl[minor];
uint32_t base = ct->ulCtrlPort1;
xlite_uart_write(base, buf[0]);
cd->bActive = true;
} else {
cd->bActive = false;
}
return 0;
}
#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
static ssize_t xlite_write_buffer_polled(
int minor,
const char *buf,
size_t len
)
{
uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
int nwrite = 0;
/*
* poll each byte in the string out of the port.
*/
while (nwrite < len)
{
if( xlite_write_char(base, *buf++) < 0 ) break;
nwrite++;
}
/*
* return the number of bytes written.
*/
return nwrite;
}
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
static void xlite_write_char_polled(
int minor,
char c
)
{
uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
xlite_write_char(base, c);
return;
}
static int xlite_set_attributes(int minor, const struct termios *t)
{
return RTEMS_SUCCESSFUL;
}
static const console_fns xlite_fns_polled =
{
.deviceProbe = libchip_serial_default_probe,
.deviceFirstOpen = xlite_open,
.deviceLastClose = xlite_close,
.deviceRead = xlite_read_polled,
.deviceInitialize = xlite_init,
.deviceWritePolled = xlite_write_char_polled,
.deviceSetAttributes = xlite_set_attributes,
#if VIRTEX_CONSOLE_USE_INTERRUPTS
.deviceWrite = xlite_write_interrupt_driven,
.deviceOutputUsesInterrupts = true
#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
.deviceWrite = xlite_write_buffer_polled,
.deviceOutputUsesInterrupts = false
#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
};
/*
** Set ulCtrlPort1 to the base address of each UART Lite instance. Set in vhdl model.
*/
console_tbl Console_Configuration_Ports[] = {
{
"/dev/ttyS0", /* sDeviceName */
SERIAL_CUSTOM, /* deviceType */
&xlite_fns_polled, /* pDeviceFns */
NULL, /* deviceProbe, assume it is there */
NULL, /* pDeviceFlow */
16, /* ulMargin */
8, /* ulHysteresis */
(void *) NULL, /* NULL */ /* pDeviceParams */
STDIN_BASEADDRESS, /* ulCtrlPort1 */
0, /* ulCtrlPort2 */
0, /* ulDataPort */
NULL, /* getRegister */
NULL, /* setRegister */
NULL, /* unused */ /* getData */
NULL, /* unused */ /* setData */
0, /* ulClock */
#ifdef XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
.ulIntVector = XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
#else
.ulIntVector = 0
#endif
},
#ifdef XPAR_UARTLITE_1_BASEADDR
{
"/dev/ttyS1", /* sDeviceName */
SERIAL_CUSTOM, /* deviceType */
&xlite_fns_polled, /* pDeviceFns */
NULL, /* deviceProbe, assume it is there */
NULL, /* pDeviceFlow */
16, /* ulMargin */
8, /* ulHysteresis */
(void *) NULL, /* NULL */ /* pDeviceParams */
XPAR_UARTLITE_1_BASEADDR, /* ulCtrlPort1 */
0, /* ulCtrlPort2 */
0, /* ulDataPort */
NULL, /* getRegister */
NULL, /* setRegister */
NULL, /* unused */ /* getData */
NULL, /* unused */ /* setData */
0, /* ulClock */
0 /* ulIntVector -- base for port */
},
#endif
#ifdef XPAR_UARTLITE_2_BASEADDR
{
"/dev/ttyS2", /* sDeviceName */
SERIAL_CUSTOM, /* deviceType */
&xlite_fns_polled, /* pDeviceFns */
NULL, /* deviceProbe, assume it is there */
NULL, /* pDeviceFlow */
16, /* ulMargin */
8, /* ulHysteresis */
(void *) NULL, /* NULL */ /* pDeviceParams */
XPAR_UARTLITE_2_BASEADDR, /* ulCtrlPort1 */
0, /* ulCtrlPort2 */
0, /* ulDataPort */
NULL, /* getRegister */
NULL, /* setRegister */
NULL, /* unused */ /* getData */
NULL, /* unused */ /* setData */
0, /* ulClock */
0 /* ulIntVector -- base for port */
},
#endif
#ifdef XPAR_UARTLITE_2_BASEADDR
{
"/dev/ttyS3", /* sDeviceName */
SERIAL_CUSTOM, /* deviceType */
&xlite_fns_polled, /* pDeviceFns */
NULL, /* deviceProbe, assume it is there */
NULL, /* pDeviceFlow */
16, /* ulMargin */
8, /* ulHysteresis */
(void *) NULL, /* NULL */ /* pDeviceParams */
XPAR_UARTLITE_3_BASEADDR, /* ulCtrlPort1 */
0, /* ulCtrlPort2 */
0, /* ulDataPort */
NULL, /* getRegister */
NULL, /* setRegister */
NULL, /* unused */ /* getData */
NULL, /* unused */ /* setData */
0, /* ulClock */
0 /* ulIntVector -- base for port */
}
#endif
};
unsigned long Console_Configuration_Count =
RTEMS_ARRAY_SIZE(Console_Configuration_Ports);
#include <rtems/bspIo.h>
static void outputChar(char ch)
{
xlite_write_char_polled( 0, ch );
}
static int inputChar(void)
{
return xlite_read_polled(0);
}
BSP_output_char_function_type BSP_output_char = outputChar;
BSP_polling_getchar_function_type BSP_poll_char = inputChar;