forked from Imagelibrary/rtems
836 lines
22 KiB
C
836 lines
22 KiB
C
/*===============================================================*\
|
|
| 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);
|
|
}
|