/*
* General Serial I/O functions.
*
* This file contains the functions for performing serial I/O.
* The actual system calls (console_*) should be in the BSP part
* of the source tree. That way different BSPs can use whichever
* SMCs and SCCs they want. Originally, all the stuff was in
* this file, and it caused problems with one BSP using SCC2
* as /dev/console, others using SMC1 for /dev/console, etc.
*
* On-chip resources used:
* resource minor note
* SMC1 0
* SMC2 1
* SCC1 2 (shared with ethernet driver)
* SCC2 3
* SCC3 4
* SCC4 5
* BRG1
* BRG2
* BRG3
* BRG4
* Author: Jay Monkman (jmonkman@frasca.com)
* Copyright (C) 1998 by Frasca International, Inc.
*
* Derived from c/src/lib/libbsp/m68k/gen360/console/console.c:
*
* Author:
* W. Eric Norum
* Saskatchewan Accelerator Laboratory
* University of Saskatchewan
* Saskatoon, Saskatchewan, CANADA
* eric@skatter.usask.ca
*
* COPYRIGHT (c) 1989-1998.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp.h>
#include <rtems/libio.h>
#include <mpc860.h>
#include <mpc860/console.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#define NIFACES 6 /* number of console devices (serial ports) */
extern rtems_cpu_table Cpu_table; /* owned by BSP */
static Buf_t *rxBufList[NIFACES];
static Buf_t *rxBufListTail[NIFACES];
/*
* Interrupt-driven input buffer
*/
#define RXBUFSIZE 16
/*
* I/O buffers and pointers to buffer descriptors
*/
static volatile char txBuf[NIFACES];
static volatile m860BufferDescriptor_t *RxBd[NIFACES], *TxBd[NIFACES];
/*
* Device-specific routines
*/
static int m860_get_brg_cd(int);
unsigned char m860_get_brg_clk(int);
void m860_console_reserve_resources(rtems_configuration_table *);
unsigned char m860_get_brg_clk(int);
/*
* Compute baud-rate-generator configuration register value
*/
static int
m860_get_brg_cd (int baud)
{
int divisor;
int div16 = 0;
divisor = ((Cpu_table.clock_speed / 16) + (baud / 2)) / baud;
if (divisor > 4096) {
div16 = 1;
divisor = (divisor + 8) / 16;
}
return M860_BRG_EN | M860_BRG_EXTC_BRGCLK |
((divisor - 1) << 1) | div16;
}
/* this function will fail if more that 4 baud rates have been selected */
/* at any time since the OS started. It needs to be fixed. FIXME */
unsigned char m860_get_brg_clk(int baud)
{
static short brg_spd[4];
static char brg_used[4];
int i;
/* first try to find a BRG that is already at the right speed */
for (i=0; i<4; i++) {
if (brg_spd[i] == baud) {
break;
}
}
if (i==4) { /* I guess we didn't find one */
for (i=0; i<4; i++) {
if (brg_used[i] == 0) {
break;
}
}
}
if (i != 4) {
brg_used[i]++;
brg_spd[i]=baud;
switch (i) {
case 0:
m860.brgc1 = M860_BRG_RST;
m860.brgc1 = m860_get_brg_cd(baud);
break;
case 1:
m860.brgc2 = M860_BRG_RST;
m860.brgc2 = m860_get_brg_cd(baud);
break;
case 2:
m860.brgc3 = M860_BRG_RST;
m860.brgc3 = m860_get_brg_cd(baud);
break;
case 3:
m860.brgc4 = M860_BRG_RST;
m860.brgc4 = m860_get_brg_cd(baud);
break;
}
return i;
}
else
return 0xff;
}
/*
* Hardware-dependent portion of tcsetattr().
*/
int
m860_smc_set_attributes (int minor, const struct termios *t)
{
/*
* minor must be 0 or 1
*/
int baud;
int brg;
switch (t->c_cflag & CBAUD) {
default: baud = -1; break;
case B50: baud = 50; break;
case B75: baud = 75; break;
case B110: baud = 110; break;
case B134: baud = 134; break;
case B150: baud = 150; break;
case B200: baud = 200; break;
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B1800: baud = 1800; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B19200: baud = 19200; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
}
if (baud > 0) {
brg = m860_get_brg_clk(baud); /* 4 BRGs, 6 serial ports - hopefully */
/* at least 2 ports will be the same */
m860.simode |= brg << (12 + ((minor) * 16));
}
return 0;
}
int
m860_scc_set_attributes (int minor, const struct termios *t)
{
/*
* minor must be 2, 3, 4 or 5
*/
int baud;
int brg;
switch (t->c_cflag & CBAUD) {
default: baud = -1; break;
case B50: baud = 50; break;
case B75: baud = 75; break;
case B110: baud = 110; break;
case B134: baud = 134; break;
case B150: baud = 150; break;
case B200: baud = 200; break;
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B1800: baud = 1800; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B19200: baud = 19200; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
}
if (baud > 0) {
brg = m860_get_brg_clk(baud); /* 4 BRGs, 5 serial ports - hopefully */
/* at least 2 ports will be the same */
m860.sicr |= (brg << (3 + ((minor-2) * 8))) |
(brg << ((minor-2) * 8));
}
return 0;
}
void
m860_scc_initialize (int port) /* port is the SCC # (i.e. 1, 2, 3 or 4) */
{
unsigned char brg;
volatile m860SCCparms_t *sccparms;
volatile m860SCCRegisters_t *sccregs;
/*
* Allocate buffer descriptors
*/
RxBd[port+1] = M860AllocateBufferDescriptors(1);
TxBd[port+1] = M860AllocateBufferDescriptors(1);
/*
* Configure ports A and B to enable TXDx and RXDx pins
*/
m860.papar |= (0xC << ((port-2) * 2));
m860.padir &= ~(0xC << ((port-2) * 2));
m860.pbdir |= (0x04 << (port-2));
m860.paodr &= ~(0x8 << ((port-2) * 2));
m860.pbdat &= ~(0x04 << (port-2));
/* SCC2 is the only one with handshaking lines */
/*
if (port == 2) {
m860.pcpar |= (0x02);
m860.pcpar &= ~(0xc0);
m860.pcdir &= ~(0xc2);
m860.pcso |= (0xc0);
}
*/
brg = m860_get_brg_clk(9600); /* 4 BRGs, 5 serial ports - hopefully */
/* at least 2 ports will be the same */
/*
* Set up SDMA
*/
m860.sdcr = 0x01; /* as recommended p 16-80, sec 16.10.2.1 MPC860UM/AD */
m860.sicr &= ~(0xff << ((port-1) * 8));
m860.sicr |= (brg << (3 + ((port-1) * 8))) | (brg << ((port-1) * 8));
/*
* Set up SMC1 parameter RAM common to all protocols
*/
if (port == 1) {
sccparms = (m860SCCparms_t*)&m860.scc1p;
sccregs = &m860.scc1;
}
else if (port == 2) {
sccparms = &m860.scc2p;
sccregs = &m860.scc2;
}
else if (port == 3) {
sccparms = &m860.scc3p;
sccregs = &m860.scc3;
}
else {
sccparms = &m860.scc4p;
sccregs = &m860.scc4;
}
sccparms->rbase = (char *)RxBd[port+1] - (char *)&m860;
sccparms->tbase = (char *)TxBd[port+1] - (char *)&m860;
if (port == 1)
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC1);
else if (port == 2)
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC2);
else if (port == 3)
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC3);
else if (port == 4)
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC4);
sccparms->rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0);
sccparms->tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0);
sccparms->mrblr = RXBUFSIZE;
sccparms->un.uart.max_idl = 10;
sccparms->un.uart.brklen = 0;
sccparms->un.uart.brkec = 0;
sccparms->un.uart.brkcr = 1;
sccparms->un.uart.parec = 0;
sccparms->un.uart.frmec = 0;
sccparms->un.uart.nosec = 0;
sccparms->un.uart.uaddr[0] = 0;
sccparms->un.uart.uaddr[1] = 0;
sccparms->un.uart.toseq = 0;
sccparms->un.uart.character[0] = 0x8000;
sccparms->un.uart.character[1] = 0x8000;
sccparms->un.uart.character[2] = 0x8000;
sccparms->un.uart.character[3] = 0x8000;
sccparms->un.uart.character[4] = 0x8000;
sccparms->un.uart.character[5] = 0x8000;
sccparms->un.uart.character[6] = 0x8000;
sccparms->un.uart.character[7] = 0x8000;
sccparms->un.uart.rccm = 0xc0ff;
/*
* Set up the Receive Buffer Descriptor
*/
RxBd[port+1]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
RxBd[port+1]->length = 0;
RxBd[port+1]->buffer = malloc(RXBUFSIZE);
/*
* Setup the Transmit Buffer Descriptor
*/
TxBd[port+1]->status = M860_BD_WRAP;
/*
* Set up SCCx general and protocol-specific mode registers
*/
sccregs->scce = 0xffff;
sccregs->sccm = 0x0000;
sccregs->gsmr_h = 0x00000020;
sccregs->gsmr_l = 0x00028004;
sccregs->psmr = 0x3000;
sccregs->gsmr_l = 0x00028034;
}
void
m860_smc_initialize (int port) /* port is the SMC number (i.e. 1 or 2) */
{
unsigned char brg;
/*
* Allocate buffer descriptors
*/
RxBd[port-1] = M860AllocateBufferDescriptors (1);
TxBd[port-1] = M860AllocateBufferDescriptors (1);
/*
* Configure port B pins to enable SMTXDx and SMRXDx pins
*/
m860.pbpar |= (0xC0 << ((port-1) * 4));
m860.pbdir &= ~(0xC0 << ((port-1) * 4));
m860.pbdir |= (0x01 << (port-1));
m860.pbodr &= ~(0xC0 << ((port-1) * 4));
m860.pbdat &= ~(0x01 << (port-1));
/*
* Set up BRG1 (9,600 baud)
*/
brg = m860_get_brg_clk(9600); /* 4 BRGs, 5 serial ports - hopefully */
/* at least 2 ports will be the same */
/*
* Put SMC in NMSI mode, connect SMC to BRG
*/
m860.simode &= ~0x7000 << ((port-1) * 8);
m860.simode |= brg << (12 + ((port-1) * 8));
/*
* Set up SMC1 parameter RAM common to all protocols
*/
if (port == 1) {
m860.smc1p.rbase = (char *)RxBd[port-1] - (char *)&m860;
m860.smc1p.tbase = (char *)TxBd[port-1] - (char *)&m860;
m860.smc1p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0);
m860.smc1p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0);
m860.smc1p.mrblr = RXBUFSIZE;
/*
* Set up SMC1 parameter RAM UART-specific parameters
*/
m860.smc1p.un.uart.max_idl = 10;
m860.smc1p.un.uart.brklen = 0;
m860.smc1p.un.uart.brkec = 0;
m860.smc1p.un.uart.brkcr = 0;
}
else {
m860.smc2p.rbase = (char *)RxBd[port-1] - (char *)&m860;
m860.smc2p.tbase = (char *)TxBd[port-1] - (char *)&m860;
m860.smc2p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0);
m860.smc2p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0);
m860.smc2p.mrblr = RXBUFSIZE;
/*
* Set up SMC2 parameter RAM UART-specific parameters
*/
m860.smc2p.un.uart.max_idl = 10;
m860.smc2p.un.uart.brklen = 0;
m860.smc2p.un.uart.brkec = 0;
m860.smc2p.un.uart.brkcr = 0;
}
/*
* Set up the Receive Buffer Descriptor
*/
RxBd[port-1]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
RxBd[port-1]->length = 0;
RxBd[port+3]->buffer = malloc(RXBUFSIZE);
/*
* Setup the Transmit Buffer Descriptor
*/
TxBd[port-1]->status = M860_BD_WRAP;
/*
* Set up SMCx general and protocol-specific mode registers
*/
if (port == 1) {
m860.smc1.smce = ~0; /* Clear any pending events */
m860.smc1.smcm = 0; /* Mask all interrupt/event sources */
m860.smc1.smcmr = M860_SMCMR_CLEN(9) | M860_SMCMR_SM_UART;
/*
* Send "Init parameters" command
*/
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SMC1);
/*
* Enable receiver and transmitter
*/
m860.smc1.smcmr |= M860_SMCMR_TEN | M860_SMCMR_REN;
}
else {
m860.smc2.smce = ~0; /* Clear any pending events */
m860.smc2.smcm = 0; /* Mask all interrupt/event sources */
m860.smc2.smcmr = M860_SMCMR_CLEN(9) | M860_SMCMR_SM_UART;
/*
* Send "Init parameters" command
*/
M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SMC2);
/*
* Enable receiver and transmitter
*/
m860.smc2.smcmr |= M860_SMCMR_TEN | M860_SMCMR_REN;
}
}
int
m860_char_poll_read (int minor)
{
unsigned char c;
rtems_unsigned32 level;
_CPU_ISR_Disable(level);
if (RxBd[minor]->status & M860_BD_EMPTY) {
_CPU_ISR_Enable(level);
return -1;
}
c = ((char *)RxBd[minor]->buffer)[0];
RxBd[minor]->status = M860_BD_EMPTY | M860_BD_WRAP;
_CPU_ISR_Enable(level);
return c;
}
int
m860_char_poll_write (int minor, const char *buf, int len)
{
while (len--) {
while (TxBd[minor]->status & M860_BD_READY)
continue;
txBuf[minor] = *buf++;
TxBd[minor]->buffer = &txBuf[minor];
TxBd[minor]->length = 1;
TxBd[minor]->status = M860_BD_READY | M860_BD_WRAP;
}
return 0;
}
/*
* Interrupt handler
*/
rtems_isr
m860_scc1_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if ((m860.scc1.sccm & 0x1) && (m860.scc1.scce & 0x1)) {
m860.scc1.scce = 0x1;
/* m860.scc1.sccm &= ~0x1;*/
while ((RxBd[SCC1_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SCC1_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SCC1_MINOR]->next) {
rxBufListTail[SCC1_MINOR] = rxBufListTail[SCC1_MINOR]->next;
rxBufListTail[SCC1_MINOR]->buf = RxBd[SCC1_MINOR]->buffer;
rxBufListTail[SCC1_MINOR]->len = RxBd[SCC1_MINOR]->length;
rxBufListTail[SCC1_MINOR]->pos = 0;
rxBufListTail[SCC1_MINOR]->next = 0;
RxBd[SCC1_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SCC1_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
}
rtems_isr
m860_scc2_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if ((m860.scc2.sccm & 0x1) && (m860.scc2.scce & 0x1)) {
m860.scc2.scce = 0x1;
/* m860.scc2.sccm &= ~0x1;*/
while ((RxBd[SCC2_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SCC2_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SCC2_MINOR]->next) {
rxBufListTail[SCC2_MINOR] = rxBufListTail[SCC2_MINOR]->next;
rxBufListTail[SCC2_MINOR]->buf = RxBd[SCC2_MINOR]->buffer;
rxBufListTail[SCC2_MINOR]->len = RxBd[SCC2_MINOR]->length;
rxBufListTail[SCC2_MINOR]->pos = 0;
rxBufListTail[SCC2_MINOR]->next = 0;
RxBd[SCC2_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SCC2_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 29; /* Clear SCC2 interrupt-in-service bit */
}
rtems_isr
m860_scc3_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if ((m860.scc3.sccm & 0x1) && (m860.scc3.scce & 0x1)) {
m860.scc3.scce = 0x1;
/* m860.scc3.sccm &= ~0x1;*/
while ((RxBd[SCC3_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SCC3_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SCC3_MINOR]->next) {
rxBufListTail[SCC3_MINOR] = rxBufListTail[SCC3_MINOR]->next;
rxBufListTail[SCC3_MINOR]->buf = RxBd[SCC3_MINOR]->buffer;
rxBufListTail[SCC3_MINOR]->len = RxBd[SCC3_MINOR]->length;
rxBufListTail[SCC3_MINOR]->pos = 0;
rxBufListTail[SCC3_MINOR]->next = 0;
RxBd[SCC3_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SCC3_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 28; /* Clear SCC3 interrupt-in-service bit */
}
rtems_isr
m860_scc4_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if ((m860.scc4.sccm & 0x1) && (m860.scc4.scce & 0x1)) {
m860.scc4.scce = 0x1;
/* m860.scc4.sccm &= ~0x1;*/
while ((RxBd[SCC4_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SCC4_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SCC4_MINOR]->next) {
rxBufListTail[SCC4_MINOR] = rxBufListTail[SCC4_MINOR]->next;
rxBufListTail[SCC4_MINOR]->buf = RxBd[SCC4_MINOR]->buffer;
rxBufListTail[SCC4_MINOR]->len = RxBd[SCC4_MINOR]->length;
rxBufListTail[SCC4_MINOR]->pos = 0;
rxBufListTail[SCC4_MINOR]->next = 0;
RxBd[SCC4_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SCC4_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 27; /* Clear SCC4 interrupt-in-service bit */
}
rtems_isr
m860_smc1_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if (m860.smc1.smce & 0x1) {
m860.smc1.smce = 0x1;
/* m860.scc2.sccm &= ~0x1;*/
while ((RxBd[SMC1_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SMC1_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SMC1_MINOR]->next) {
rxBufListTail[SMC1_MINOR] = rxBufListTail[SMC1_MINOR]->next;
rxBufListTail[SMC1_MINOR]->buf = RxBd[SMC1_MINOR]->buffer;
rxBufListTail[SMC1_MINOR]->len = RxBd[SMC1_MINOR]->length;
rxBufListTail[SMC1_MINOR]->pos = 0;
rxBufListTail[SMC1_MINOR]->next = 0;
RxBd[SMC1_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SMC1_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */
}
rtems_isr
m860_smc2_console_interrupt_handler (rtems_vector_number v)
{
/*
* Buffer received?
*/
if (m860.smc2.smce & 0x1) {
m860.smc2.smce = 0x1;
while ((RxBd[SMC2_MINOR]->status & M860_BD_EMPTY) == 0) {
rxBufListTail[SMC2_MINOR]->next = malloc(sizeof(Buf_t));
if (rxBufListTail[SMC2_MINOR]->next) {
rxBufListTail[SMC2_MINOR] = rxBufListTail[SMC2_MINOR]->next;
rxBufListTail[SMC2_MINOR]->buf = RxBd[SMC2_MINOR]->buffer;
rxBufListTail[SMC2_MINOR]->len = RxBd[SMC2_MINOR]->length;
rxBufListTail[SMC2_MINOR]->pos = 0;
rxBufListTail[SMC2_MINOR]->next = 0;
RxBd[SMC2_MINOR]->buffer = malloc(RXBUFSIZE);
}
RxBd[SMC2_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP |
M860_BD_INTERRUPT;
}
}
/*
* Buffer transmitted?
*/
#if 0
if (m860.smc1.smce & 0x2) {
m860.smc1.smce = 0x2;
if ((smcTxBd->status & M360_BD_READY) == 0)
rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
}
#endif
m860.cisr = 1UL << 3; /* Clear SMC2 interrupt-in-service bit */
}
int
m860_buf_poll_read (int minor, char **buf)
{
int len;
if (RxBd[minor]->status & M860_BD_EMPTY)
return -1;
RxBd[minor]->buffer = malloc(RXBUFSIZE); /* I hope this succeeds ... */
len = RxBd[minor]->length;
RxBd[minor]->status = M860_BD_EMPTY | M860_BD_WRAP;
return len;
}
int
m860_buf_poll_write (int minor, char *buf, int len)
{
static char *last_buf[6];
while (TxBd[minor]->status & M860_BD_READY)
continue;
if (last_buf[minor])
free(last_buf[minor]);
last_buf[minor] = buf;
TxBd[minor]->buffer = buf;
TxBd[minor]->length = len;
TxBd[minor]->status = M860_BD_READY | M860_BD_WRAP;
return 0;
}
/*
* This is needed in case we use TERMIOS
*/
void m860_console_reserve_resources(rtems_configuration_table *configuration)
{
rtems_termios_reserve_resources (configuration, 1);
}
void m860_console_initialize(void)
{
int i;
for (i=0; i < NIFACES; i++) {
rxBufList[i] = malloc(sizeof(Buf_t));
rxBufListTail[i] = rxBufList[i];
rxBufList[i]->buf = 0;
rxBufList[i]->len = 0;
rxBufList[i]->pos = 0;
rxBufList[i]->next = 0;
}
}
rtems_device_driver m860_console_read(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_libio_rw_args_t *rw_args;
char *buffer;
int maximum;
int count;
Buf_t *tmp_buf;
rtems_unsigned32 level;
/*
* Set up interrupts
* FIXME: DANGER: WARNING:
* CICR and SIMASK must be set in any module that uses
* the CPM. Currently those are console-generic.c and
* network.c. If the registers are not set the same
* in both places, strange things may happen.
* If they are only set in one place, then an application
* that used the other module won't work correctly.
* Put this comment in each module that sets these 2 registers
*/
m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
m860.simask |= M860_SIMASK_LVM1;
rw_args = (rtems_libio_rw_args_t *) arg;
buffer = rw_args->buffer;
maximum = rw_args->count;
count = 0;
while (count == 0) {
if (rxBufList[minor]->len) {
while ((count < maximum) &&
(rxBufList[minor]->pos < rxBufList[minor]->len)) {
buffer[count++] = rxBufList[minor]->buf[rxBufList[minor]->pos++];
}
_CPU_ISR_Disable(level);
if (rxBufList[minor]->pos == rxBufList[minor]->len) {
if (rxBufList[minor]->next) {
tmp_buf=rxBufList[minor]->next;
free ((void *) rxBufList[minor]->buf);
free ((void *) rxBufList[minor]);
rxBufList[minor]=tmp_buf;
}
else {
free(rxBufList[minor]->buf);
rxBufList[minor]->buf=0;
rxBufList[minor]->len=0;
rxBufList[minor]->pos=0;
}
}
_CPU_ISR_Enable(level);
}
else
if(rxBufList[minor]->next && !rxBufList[minor]->len) {
tmp_buf = rxBufList[minor];
rxBufList[minor] = rxBufList[minor]->next;
free(tmp_buf);
}
/* sleep(1);*/
}
rw_args->bytes_moved = count;
return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
}
rtems_device_driver m860_console_write(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
int count;
int maximum;
rtems_libio_rw_args_t *rw_args;
char *in_buffer;
char *out_buffer;
int n;
/*
* Set up interrupts
* FIXME: DANGER: WARNING:
* CICR and SIMASK must be set in any module that uses
* the CPM. Currently those are console-generic.c and
* network.c. If the registers are not set the same
* in both places, strange things may happen.
* If they are only set in one place, then an application
* that used the other module won't work correctly.
* Put this comment in each module that sets these 2 registers
*/
#if 0
m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
m860.simask |= M860_SIMASK_LVM1;
#endif
rw_args = (rtems_libio_rw_args_t *) arg;
in_buffer = rw_args->buffer;
maximum = rw_args->count;
out_buffer = malloc(maximum*2); /* This is wasteful, but it won't */
/* be too small */
if (!out_buffer) {
rw_args->bytes_moved = 0;
return RTEMS_NO_MEMORY;
}
n=0;
for (count = 0; count < maximum; count++) {
if ( in_buffer[ count ] == '\n') {
out_buffer[count + n] = '\r';
n++;
}
out_buffer[count + n] = in_buffer[count];
}
m860_buf_poll_write(minor, out_buffer, maximum+n);
rw_args->bytes_moved = maximum;
return RTEMS_SUCCESSFUL;
}
/*
* How to use the console.
* In your BSP, have the following functions:
*
* rtems_device_driver console_initialize(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
* rtems_device_driver console_open(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
* rtems_device_driver console_close(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
* rtems_device_driver console_read(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
* rtems_device_driver console_write(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
* rtems_device_driver console_control(rtems_device_major_number major,
* rtems_device_minor_number minor,
* void *arg)
*
*/