/*
 *  This file contains the MVME162LX extended console IO package.
 *
 *  This file was created originally by 
 *  On-Line Applications Research Corporation (OAR)
 *  and modified by:
 *
 *  Katsutoshi Shibuya - BU-Denken Co.,Ltd. - Sapporo, JAPAN
 *
 *  featuring support of:
 *
 *     - Multi-SCC chip handling
 *     - Non-blocking I/O (O_NDELAY flag in libc)
 *     - Raw mode device (no CR/LF detection)
 *     - RTS/CTS flow control
 *
 *  REMARKS: This routine requires multiple interrupt vectors
 *           from SCC_VECTOR (normaly 0x40)
 *           to SCC_VECTOR+(number of SCC chips)
 *
 *  The original copyright follows;
 *
 *  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.
 * 
 *  Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
 *  EISCAT Scientific Association. M.Savitski
 *
 *  This material is a part of the MVME162 Board Support Package
 *  for the RTEMS executive. Its licensing policies are those of the
 *  RTEMS above.
 *
 *  $Id$
 */

#define M162_INIT

#include "consolex.h"
#include <bsp.h>
#include <rtems/libio.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define	NPORTS	4	/* Number of ports */
#define	DEVICEPREFIX	"tty"
#define	RAWDEVICEPREFIX	"rtty"
#define	CONSOLEPORT 0	/* port# of console:
			   undef this if you do not want /dev/console */
#define	READRETRY 1	/* Maximum retry count for read one char */
#define	WRITERETRY 8	/* Maximum retry count for write one char */

#define	PORTFROM 0	/* for debug */

static unsigned char	opencount[NPORTS];

/***********************************************************************
   Ring buffer for device
 ***********************************************************************/

#define QUEUE_LENGTH 128	/* Must be 2^n number */

typedef struct {
  char buffer[QUEUE_LENGTH];
  volatile int  head;
  volatile int  tail;
} ReceiverBuffer;

#define ReceiverBufferInitialize( _buffer ) \
  do { \
    (_buffer)->head = (_buffer)->tail = 0; \
  } while ( 0 ) 
  
#define ReceiverBufferIsEmpty( _buffer ) \
   ( (_buffer)->tail == (_buffer)->head )

#define ReceiverBufferIsNearEmpty( _buffer ) \
   ( (_buffer)->tail == (((_buffer)->head + 3) & (QUEUE_LENGTH-1)) )

#define ReceiverBufferIsFull( _buffer ) \
   ( (_buffer)->head == (((_buffer)->tail + 1) & (QUEUE_LENGTH-1)) )

#define ReceiverBufferIsNearFull( _buffer ) \
   ( (_buffer)->head == (((_buffer)->tail + 3) & (QUEUE_LENGTH-1)) )

#define ReceiverBufferAdd( _buffer, _ch ) \
  do { \
    rtems_unsigned32 isrlevel; \
    \
    rtems_interrupt_disable( isrlevel ); \
      (_buffer)->tail = ((_buffer)->tail+1) & (QUEUE_LENGTH-1); \
      (_buffer)->buffer[ (_buffer)->tail ] = (_ch); \
    rtems_interrupt_enable( isrlevel ); \
  } while ( 0 ) 

#define ReceiverBufferRemove( _buffer, _ch ) \
  do { \
    rtems_unsigned32 isrlevel; \
    \
    rtems_interrupt_disable( isrlevel ); \
      (_buffer)->head = ((_buffer)->head+1) & (QUEUE_LENGTH-1); \
      (_ch) = (_buffer)->buffer[ (_buffer)->head ]; \
    rtems_interrupt_enable( isrlevel ); \
  } while ( 0 ) 


/***********************************************************************
   DEVICE DEPENDED PART
 ***********************************************************************/


/* Time constant parameters
   CAUTION: These parameters are for MVME162LX-213 board.
 */

#define	TC38400	0x0006
#define	TC19200	0x000e
#define	TC9600	0x001e

/* Re-defining SCC register control macros
   to support Multi SCC chips */

#undef	scc
#if defined(mvme162lx)
static scc_regs	*scc[NPORTS] = {
    ((scc_regs * const) 0xFFF45004),
    ((scc_regs * const) 0xFFF45000),
    ((scc_regs * const) 0xFFF45804),
    ((scc_regs * const) 0xFFF45800)
};
#else
/* XXX fix me */
#warning "MVME162 BSP -- unknown address for SCC's"
static scc_regs	*scc[NPORTS] = {
    ((scc_regs * const) 0xFFF45004),
    ((scc_regs * const) 0xFFF45000),
    ((scc_regs * const) 0xFFF45804),
    ((scc_regs * const) 0xFFF45800)
};
#endif

#undef	ZWRITE0
#define ZWRITE0(port, v)  (scc[port]->csr = (unsigned char)(v))
#undef	ZREAD0
#define ZREAD0(port)  (scc[port]->csr)

#undef	ZREAD
#define ZREAD(port, n)  (ZWRITE0(port, n), (scc[port]->csr))
#undef	ZREADD
#define ZREADD(port)  (scc[port]->csr=0x08, scc[port]->csr )

#undef	ZWRITE
#define ZWRITE(port, n, v) (ZWRITE0(port, n), ZWRITE0(port, v))
#undef	ZWRITED
#define ZWRITED(port, v)  (scc[port]->csr = 0x08, \
                           scc[port]->csr = (unsigned char)(v))

static ReceiverBuffer	receiverBuffer[NPORTS];

/*
 *  Control flags (DTR/DCD/RTS/CTS)
 */

static unsigned char	wr4[NPORTS];
static unsigned char	wr5[NPORTS];
#define	SCCSetDTR(port) ZWRITE(port, 5, (wr5[port] |= 0x80))
#define	SCCResetDTR(port) ZWRITE(port, 5, (wr5[port] &= ~0x80))
#define	SCCSetRTS(port) ZWRITE(port, 5, (wr5[port] |= 0x02))
#define	SCCResetRTS(port) ZWRITE(port,5, (wr5[port] &= ~0x02))
#define	SCCGetDCD(port) (ZREAD0(port)&0x08)
#define	SCCGetCTS(port) (ZREAD0(port)&0x20)


/*
 *  Interrupt handler for receiver interrupts
 */

static rtems_isr	SCCReceiverISR(rtems_vector_number vector)
{
    register int    ipend, port;

    port = (vector-SCC_VECTOR)*2;
    ZWRITE0(port, 0x38);	/* reset highest IUS */

    ipend = ZREAD(port, 3);	/* read int pending from A side */

    if(ipend == 0x04)
	port++; /* channel B intr pending */
    else if(ipend == 0x20)
	;	/* channel A intr pending */
    else
	return;
    
    ReceiverBufferAdd(&receiverBuffer[port], ZREADD(port));
    
    if(ZREAD(port,1) & 0x70){ /* check error stat */
	ZWRITE0(port, 0x30);	/* reset error */
    }

    if(ReceiverBufferIsNearFull(&receiverBuffer[port]))
	SCCResetRTS(port);
}

/*
 * Initialize
 */

void	SCCInitialize()
{
    int     i;

    for(i = PORTFROM; i < NPORTS; i+=2)
	ZWRITE(i, 9,0xc0);	/* Reset SCC Chip */
    
    for(i = PORTFROM; i < NPORTS; i++){
	ReceiverBufferInitialize(&(receiverBuffer[i]));
	wr4[i] = 0x44;
	ZWRITE(i, 4, wr4[i]);	/* x16 clock, 1 stop, parity none */
	ZWRITE(i, 1, 0);	/* disable interrupts */
	ZWRITE(i, 2, SCC_VECTOR+(i/2));
	ZWRITE(i, 3, 0xc1);	/* receiver enable, 8bits */
	wr5[i] = 0x68;
	ZWRITE(i, 5, wr5[i]);	/* transmitter enable, 8bits, DTR&RTS off */
	ZWRITE(i,14, 0);	/* stop baudrate gen. */
	ZWRITE(i,11,0x50);	/* use baurate gen. */
	ZWRITE(i,15, 1);	/* Select WR7' */
	ZWRITE(i, 7, 0);	/* Disable all special interrupts */
	ZWRITE(i,10, 0);
	ZWRITE(i, 1, 0x10);     /* int on all Rx chars or special condition */
	set_vector(SCCReceiverISR, SCC_VECTOR+(i/2), 1); /* install ISR */
	ZWRITE(i, 9, 8);        /* master interrupt enable */
	ZWRITE(i,12,TC38400&0xff);	/* set 38400 baud */
	ZWRITE(i,13,TC38400>>8);
	ZWRITE(i,14, 3);	/* start baudrate gen. */
				/* CAUTION: If your SCC use XTAL on RTxC,
				   write 1 */
    }
    mcchip->vector_base = 0;
    mcchip->gen_control = 2;	/* MIEN */
    mcchip->SCC_int_ctl = 0x13;	/* SCC IEN, IPL3 */
}

/*
 *   Non-blocking char input
 */

rtems_boolean	SCCGetOne(int port, char *ch)
{
    int	retry = READRETRY;
    while(ReceiverBufferIsEmpty(&receiverBuffer[port]))
	if(--retry <= 0)
	    return FALSE;

    ReceiverBufferRemove(&receiverBuffer[port],*ch);

    if(ReceiverBufferIsNearEmpty(&receiverBuffer[port]))
	SCCSetRTS(port);
    return TRUE;
}

/*
 *   Blocking char input
 */

char	SCCGetOneBlocked(int port)
{
    unsigned char tmp_char;
 
    while (!SCCGetOne(port, &tmp_char))
	rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
    return tmp_char;
}

/*
 *   Non-blocking char input
 *   No longer supports XON/XOFF flow control.
 */

rtems_boolean	SCCSendOne(int port, char ch)
{
    int	retry = WRITERETRY;

    if(!SCCGetCTS(port))
	return FALSE;
    while(!(ZREAD0(port) & TX_BUFFER_EMPTY))
	if(--retry <= 0)
	    return FALSE;
    ZWRITED(port, ch);
    return TRUE;
}


/*  
 *   Blocking char output
 *   No longer supports XON/XOFF flow control.
 */

void	SCCSendOneBlocked(int port, char ch)
{
    while(!SCCSendOne(port, ch))
	rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
}

/*
 * Set parameters for transmission
 */

unsigned32	SCCSetAttributes(int port, struct termios *t)
{
    unsigned char	wr3;
    
    ZWRITE(port,1,0);	/* Disable interrupt */
    ZWRITE(port,3,0);	/* Disable receiver */
    /* Baud */
    switch(t->c_cflag & CBAUD){
    case B38400:
	ZWRITE(port,12,TC38400&0xff);
	ZWRITE(port,13,TC38400>>8);
	break;
    case B19200:
	ZWRITE(port,12,TC19200&0xff);
	ZWRITE(port,13,TC19200>>8);
	break;
    case B9600:
	ZWRITE(port,12,TC9600&0xff);
	ZWRITE(port,13,TC9600>>8);
	break;
    }
    
    /* Code size */
    wr5[port] &= 0x8f;
    wr3 = 0;	/* receiver control */
    switch(t->c_cflag & CSIZE){
    case CS8:
	wr5[port] |= 0x60;
	wr3 |= 0xc0;
	break;
    case CS7:
	wr5[port] |= 0x20;
	wr3 |= 0x40;
	break;
    }

    /* Parity */
    wr4[port] &= 0xf0;
    if(t->c_cflag & PARENB)
	wr4[port] |= 0x01;
    if(!(t->c_cflag & PARODD))
	wr4[port] |= 0x02;
    /* ZWRITE(port,4,wr4[port]);*/

    /* Stop bits */
    /* wr4[port] = ZREAD(port,4) & 0xfc;*/
    if(t->c_cflag & CSTOPB)
	wr4[port] |= 0x0c;
    else
	wr4[port] |= 0x04;
    
    ZWRITE(port,4,wr4[port]);	/* TxRx parameters */
    ZWRITE(port,5,wr5[port]);	/* Transmission parameters */
    ZWRITE(port,3,wr3|0x01);	/* Enable receiver */
    ZWRITE(port,1,0x10);	/* Enable interrupt */

    return 0;
}

/*
 * Get parameters for transmission
 */

unsigned32	SCCGetAttributes(int port, struct termios *t)
{
    unsigned32	b;

    t->c_cflag = 0;
    
    /* Baud */
    b = ZREAD(port,13);
    b <<= 8;
    b |= ZREAD(port,12);
    switch(b){
    case TC38400:
	t->c_cflag |= B38400;
	break;
    case TC19200:
	t->c_cflag |= B19200;
	break;
    case TC9600:
	t->c_cflag |= B9600;
	break;
    }
    
    /* Code size */
    /* wr = ZREAD(port,5);*/
    t->c_cflag &= ~CSIZE;
    switch(wr5[port]&0x60){
    case 0x60:
	t->c_cflag |= CS8;
	break;
    case 0x20:
	t->c_cflag |= CS7;
	break;
    }

    /* Parity */
    /* wr = ZREAD(port,4);*/
    if(wr4[port] & 0x01)
	t->c_cflag |= PARENB;
    else
	t->c_cflag &= ~PARENB;
    if(wr4[port] & 0x02)
	t->c_cflag &= ~PARODD;
    else
	t->c_cflag |= PARODD;

    /* Stop bits */
    /* wr = ZREAD(port,4);*/
    if((wr4[port]&0xc0) == 0xc0)
	t->c_cflag |= CSTOPB;
    else
	t->c_cflag &= ~CSTOPB;

    return 0;
}

/***********************************************************************
   DEVICE INDEPENDED PART
 ***********************************************************************/

#define	LOCAL_ISTRIP	0x0001
#define	LOCAL_INLCR	0x0002
#define	LOCAL_IGNCR	0x0004
#define	LOCAL_ICRNL	0x0008
#define	LOCAL_IUCLC	0x0010
#define	LOCAL_OLCUC	0x0020
#define	LOCAL_ONLCR	0x0040
#define	LOCAL_OCRNL	0x0080
#define	LOCAL_ICANON	0x0100
#define	LOCAL_ECHO	0x0200

/*
 *  Device initialize entry point
 */

rtems_device_driver consolex_initialize(rtems_device_major_number  major,
					rtems_device_minor_number  minor,
					void *arg)
{
    rtems_status_code	status;
    char	devname[16];
    int		i;
    
    SCCInitialize();

#ifdef	CONSOLEPORT
    status = rtems_io_register_name("/dev/console",major,
				    (rtems_device_minor_number) CONSOLEPORT);
    if (status != RTEMS_SUCCESSFUL)
	rtems_fatal_error_occurred(status);
#endif
    
    for(i = PORTFROM; i < NPORTS; i++){
	/* Register cooked ttys */
	sprintf(devname,"/dev/%s%02d",DEVICEPREFIX,i);
	status = rtems_io_register_name(strdup(devname),major,
					(rtems_device_minor_number) i);
	if (status != RTEMS_SUCCESSFUL)
	    rtems_fatal_error_occurred(status);
	/* Register raw ttys */
	sprintf(devname,"/dev/%s%02d",RAWDEVICEPREFIX,i);
	status = rtems_io_register_name(strdup(devname),major,
					(rtems_device_minor_number) i+NPORTS);
	if (status != RTEMS_SUCCESSFUL)
	    rtems_fatal_error_occurred(status);
    }

    for(i = 0; i < NPORTS; i++){
	opencount[i] = 0;
    }
    
    return RTEMS_SUCCESSFUL;
}

/*
 *  Open entry point
 */

rtems_device_driver consolex_open(rtems_device_major_number major,
				  rtems_device_minor_number minor,
				  void *arg)
{
    rtems_libio_open_close_args_t *openargs = (rtems_libio_open_close_args_t *) arg;
    if(minor >= NPORTS)
	minor -= NPORTS;
    if(minor >= NPORTS)
	return RTEMS_INVALID_NUMBER;

    if(opencount[minor]++ == 0){
	/* first open */
	SCCSetDTR(minor);
	SCCSetRTS(minor);
    }
    openargs->iop->data0 = LOCAL_ICRNL|LOCAL_ONLCR|LOCAL_ICANON|LOCAL_ECHO;
    return RTEMS_SUCCESSFUL;
}

/*
 *  Close entry point
 */

rtems_device_driver consolex_close(rtems_device_major_number major,
				   rtems_device_minor_number minor,
				   void *arg)
{
    if(minor >= NPORTS)
	minor -= NPORTS;
    if(minor >= NPORTS)
	return RTEMS_INVALID_NUMBER;

    if(--(opencount[minor]) == 0){
	/* closed all */
	SCCResetRTS(minor);
	SCCResetDTR(minor);
    }
    return RTEMS_SUCCESSFUL;
}

/*
 * read bytes from the serial port.
 */

rtems_device_driver consolex_read_raw(rtems_device_major_number major,
				      rtems_device_minor_number minor,
				      void *arg)
{
    rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
    char *buffer;
    int count;

    if(minor >= NPORTS)
	return RTEMS_INVALID_NUMBER;

    buffer = rw_args->buffer;
    count = rw_args->count;

    if(rw_args->flags & LIBIO_FLAGS_NO_DELAY){
	/* Non blocking read */
	while(count){
	    if(!SCCGetOne(minor,buffer))
		break;
	    buffer++;
	    count--;
	}
    }else{
	/* Blocking read */
	while(count){
	    *buffer = SCCGetOneBlocked(minor);
	    buffer++;
	    count--;
	}
    }

    rw_args->bytes_moved = rw_args->count-count;
    return count ? RTEMS_UNSATISFIED : RTEMS_SUCCESSFUL;
}

rtems_device_driver consolex_read(rtems_device_major_number major,
				      rtems_device_minor_number minor,
				      void *arg)
{
    rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
    char *buffer;
    int count;
    unsigned32	mode;

    if(minor >= NPORTS)
	return consolex_read_raw(major,minor-NPORTS,arg);

    buffer = rw_args->buffer;
    count = rw_args->count;
    mode = rw_args->iop->data0;
    
    /* Cooked read */
    while(count){
	if(rw_args->flags & LIBIO_FLAGS_NO_DELAY){
	    /* Non blocking read */
	    if(!SCCGetOne(minor,buffer))
		break;
	}else{
	    /* Blocking read */
	    *buffer = SCCGetOneBlocked(minor);
	}
	if((mode&LOCAL_ICANON) && (*buffer == '\b')){
	    if(buffer > (char *)(rw_args->buffer)){
		buffer--;
		count++;
		if(mode&LOCAL_ECHO){
		    SCCSendOneBlocked(minor,'\b');
		    SCCSendOneBlocked(minor,' ');
		    SCCSendOneBlocked(minor,'\b');
		}
	    }
	    continue;
	}
	if((mode&LOCAL_IGNCR) && (*buffer == '\r'))
	    continue;
	if((mode&LOCAL_INLCR) && (*buffer == '\n'))
	    *buffer = '\r';
	if((mode&LOCAL_ICRNL) && (*buffer == '\r'))
	    *buffer = '\n';
	if((mode&LOCAL_IUCLC) && isupper((int)*buffer))
	    *buffer = tolower(*buffer);
	if(mode&LOCAL_ISTRIP)
	    *buffer &= 0x7f;
	if(mode&LOCAL_ECHO){
	    /* Caution: Echo back is blocking output */
	    SCCSendOneBlocked(minor,*buffer);
	}
	if((mode&LOCAL_ICANON) && (*buffer == '\n')){
	    buffer++;
	    count--;
	    if(count)
		*buffer = 0;
	    if((mode&LOCAL_ECHO)&&(mode&LOCAL_ONLCR))
		SCCSendOneBlocked(minor,'\r');
	    break;	/* finish reading */
	}
	buffer++;
	count--;
    }
    rw_args->bytes_moved = rw_args->count-count;
    return count ? RTEMS_UNSATISFIED : RTEMS_SUCCESSFUL;
}

/*
 * write bytes to the serial port.
 */

rtems_device_driver consolex_write_raw(rtems_device_major_number major,
				       rtems_device_minor_number minor,
				       void * arg)
{
    rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
    char *buffer;
    int count;

    if(minor >= NPORTS)
	return RTEMS_INVALID_NUMBER;

    buffer = rw_args->buffer;
    count = rw_args->count;

    if(rw_args->flags & LIBIO_FLAGS_NO_DELAY){
	/* Non blocking write */
	while(count){
	    if(!SCCSendOne(minor,*buffer))
		break;
	    buffer++;
	    count--;
	}
    }else{
	/* Blocking write */
	while(count){
	    SCCSendOneBlocked(minor,*buffer);
	    buffer++;
	    count--;
	}
    }
    
    rw_args->bytes_moved = rw_args->count-count;
    return count ? RTEMS_UNSATISFIED : RTEMS_SUCCESSFUL;
}

rtems_device_driver consolex_write(rtems_device_major_number major,
				   rtems_device_minor_number minor,
				   void * arg)
{
    rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
    char *buffer;
    int count;
    char	ch;
    unsigned32	mode;

    if(minor >= NPORTS)
	return consolex_write_raw(major,minor-NPORTS,arg);

    buffer = rw_args->buffer;
    count = rw_args->count;
    mode = rw_args->iop->data0;

    /* Cooked write */
    while(count){
	ch = *buffer;
	if((mode&LOCAL_ONLCR) && (ch == '\n')){	/* Output CRLF */
	    if(rw_args->flags & LIBIO_FLAGS_NO_DELAY){
		/* Non blocking write */
		if(!SCCSendOne(minor,'\r'))
		    break;
	    }else{
		SCCSendOneBlocked(minor,'\r');
	    }
	}
	if((mode&LOCAL_OCRNL) && (ch == '\r'))
	    ch = '\n';
	if((mode&OLCUC) && (islower((int)ch)))
	    ch = toupper(ch);
	if(rw_args->flags & LIBIO_FLAGS_NO_DELAY){
	    /* Non blocking write */
	    if(!SCCSendOne(minor,ch))
		break;
	}else{
	    SCCSendOneBlocked(minor,ch);
	}
	buffer++;
	count--;
    }
    
    rw_args->bytes_moved = rw_args->count-count;
    return count ? RTEMS_UNSATISFIED : RTEMS_SUCCESSFUL;
}

/*
 *  IO Control entry point
 */

rtems_device_driver consolex_control(rtems_device_major_number major,
				     rtems_device_minor_number minor,
				     void * arg)
{
    rtems_libio_ioctl_args_t	*ioarg = (rtems_libio_ioctl_args_t *)arg;
    struct termios	*tm = ioarg->buffer;
    unsigned32	*mode = &(ioarg->iop->data0);

    if(minor >= NPORTS)
	minor -= NPORTS;
    if(minor >= NPORTS)
	return RTEMS_INVALID_NUMBER;

    switch(ioarg->command){
    case RTEMS_IO_GET_ATTRIBUTES:
	tm->c_iflag = tm->c_oflag = tm->c_cflag = tm->c_lflag = 0;
	if(*mode & LOCAL_ISTRIP)
	    tm->c_iflag |= ISTRIP;
	if(*mode & LOCAL_INLCR)
	    tm->c_iflag |= INLCR;
	if(*mode & LOCAL_IGNCR)
	    tm->c_iflag |= IGNCR;
	if(*mode & LOCAL_ICRNL)
	    tm->c_iflag |= ICRNL;
	if(*mode & LOCAL_IUCLC)
	    tm->c_iflag |= IUCLC;
	if(*mode & LOCAL_OLCUC)
	    tm->c_oflag |= OLCUC;
	if(*mode & LOCAL_ONLCR)
	    tm->c_oflag |= ONLCR;
	if(*mode & LOCAL_OCRNL)
	    tm->c_oflag |= OCRNL;
	if(*mode & LOCAL_ICANON)
	    tm->c_lflag |= ICANON;
	if(*mode & LOCAL_ECHO)
	    tm->c_lflag |= ECHO;
	ioarg->ioctl_return = SCCGetAttributes(minor,tm);
	break;
    case RTEMS_IO_SET_ATTRIBUTES:
	*mode = 0;
	if(tm->c_iflag & ISTRIP)
	    *mode |= LOCAL_ISTRIP;
	if(tm->c_iflag & INLCR)
	    *mode |= LOCAL_INLCR;
	if(tm->c_iflag & IGNCR)
	    *mode |= LOCAL_IGNCR;
	if(tm->c_iflag & ICRNL)
	    *mode |= LOCAL_ICRNL;
	if(tm->c_iflag & IUCLC)
	    *mode |= LOCAL_IUCLC;
	if(tm->c_oflag & OLCUC)
	    *mode |= LOCAL_OLCUC;
	if(tm->c_oflag & ONLCR)
	    *mode |= LOCAL_ONLCR;
	if(tm->c_oflag & OCRNL)
	    *mode |= LOCAL_OCRNL;
	if(tm->c_lflag & ICANON)
	    *mode |= LOCAL_ICANON;
	if(tm->c_lflag & ECHO)
	    *mode |= LOCAL_ECHO;
	ioarg->ioctl_return = SCCSetAttributes(minor,tm);
	break;
    default:
	return RTEMS_NOT_DEFINED;
    }
    
    return RTEMS_SUCCESSFUL;
}
