summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ppcn_60x/console/console.c
blob: 1c788bac0fc9c9466ec0a23192768c9d08713f79 (plain) (tree)







































































































































                                                                                





















































































































































































































                                                                               
/*
 *  This file contains the TTY driver for the PPCn_60x
 *
 *  This driver uses the termios pseudo driver.
 *
 *  COPYRIGHT (c) 1998 by Radstone Technology
 *
 *
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
 *
 * You are hereby granted permission to use, copy, modify, and distribute
 * this file, provided that this notice, plus the above copyright notice
 * and disclaimer, appears in all copies. Radstone Technology will provide
 * no support for this code.
 *
 *  COPYRIGHT (c) 1989-1997.
 *  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 <stdlib.h>
#include <assert.h>
#include <termios.h>

#include "console.h"

/*
 * Load configuration table
 */
#include "config.c"

#define NUM_CONSOLE_PORTS (sizeof(Console_Port_Tbl)/sizeof(console_tbl))

console_data	Console_Port_Data[NUM_CONSOLE_PORTS];
unsigned long	Console_Port_Count;
rtems_device_minor_number  Console_Port_Minor;
		
/* PAGE
 *
 *  console_open
 *
 *  open a port as a termios console.
 *
 */
rtems_device_driver console_open(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
	rtems_status_code status;
	rtems_libio_open_close_args_t *args = arg;
	rtems_libio_ioctl_args_t IoctlArgs;
	struct termios	Termios;
	rtems_termios_callbacks Callbacks;
	console_fns *c;

	/*
	 * Verify the port number is valid.
	 */
	if(minor>Console_Port_Count)
	{
		return RTEMS_INVALID_NUMBER;
	}

	/*
	 *  open the port as a termios console driver.
	 */
	c = Console_Port_Tbl[minor].pDeviceFns;
	Callbacks.firstOpen     = c->deviceFirstOpen;
	Callbacks.lastClose     = c->deviceLastClose;
	Callbacks.pollRead      = c->deviceRead;
	Callbacks.write         = c->deviceWrite;
	Callbacks.setAttributes = c->deviceSetAttributes;
	Callbacks.stopRemoteTx  = 
		Console_Port_Tbl[minor].pDeviceFlow->deviceStopRemoteTx;
	Callbacks.startRemoteTx = 
		Console_Port_Tbl[minor].pDeviceFlow->deviceStartRemoteTx;
	Callbacks.outputUsesInterrupts = c->deviceOutputUsesInterrupts;
	status = rtems_termios_open ( major, minor, arg, &Callbacks);
	Console_Port_Data[minor].termios_data = args->iop->data1;

	/*
	 * Patch in flow control routines
	 */
/* XXX */
#if 0 
	if((status==RTEMS_SUCCESSFUL) &&
	   (Console_Port_Tbl[minor].pDeviceFlow))
	{
		status=rtems_termios_flow_control(
			major, minor, arg,
			Console_Port_Tbl[minor].pDeviceFlow->
				deviceStartRemoteTx,
			Console_Port_Tbl[minor].pDeviceFlow->deviceStopRemoteTx,
			Console_Port_Tbl[minor].ulMargin,
			Console_Port_Tbl[minor].ulHysteresis);
	}
#endif

	if(minor!=Console_Port_Minor)
	{
		/*
		 * If this is not the console we do not want ECHO and
		 * so forth
		 */
		IoctlArgs.iop=args->iop;
		IoctlArgs.command=RTEMS_IO_GET_ATTRIBUTES;
		IoctlArgs.buffer=&Termios;
		rtems_termios_ioctl(&IoctlArgs);
		Termios.c_lflag=ICANON;
		IoctlArgs.command=RTEMS_IO_SET_ATTRIBUTES;
		rtems_termios_ioctl(&IoctlArgs);
	}

	if((args->iop->flags&LIBIO_FLAGS_READ) &&
	   Console_Port_Tbl[minor].pDeviceFlow &&
	   Console_Port_Tbl[minor].pDeviceFlow->deviceStartRemoteTx)
	{
		Console_Port_Tbl[minor].pDeviceFlow->deviceStartRemoteTx(minor);
	}

	return status;
}
 
rtems_device_driver console_close(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
	rtems_libio_open_close_args_t *args = arg;

	if((args->iop->flags&LIBIO_FLAGS_READ) &&
	   Console_Port_Tbl[minor].pDeviceFlow &&
	   Console_Port_Tbl[minor].pDeviceFlow->deviceStopRemoteTx)
	{
		Console_Port_Tbl[minor].pDeviceFlow->deviceStopRemoteTx(minor);
	}

	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);
}

/* PAGE
 *
 *  console_initialize
 *
 *  Routine called to initialize the console device driver.
 */
rtems_device_driver console_initialize(
  rtems_device_major_number  major,
  rtems_device_minor_number  minor,
  void                      *arg
)
{
	rtems_status_code          status;

	/*
	 * initialize the termio interface.
	 */
	rtems_termios_initialize();

	Console_Port_Count=NUM_CONSOLE_PORTS;

	for(minor=0;
	    minor<Console_Port_Count;
	    minor++)
	{
		/*
		 * First perform the configuration dependant probe, then the
		 * device dependant probe
		 */
		if((!Console_Port_Tbl[minor].deviceProbe ||
		    Console_Port_Tbl[minor].deviceProbe(minor)) &&
		   Console_Port_Tbl[minor].pDeviceFns->deviceProbe(minor))
		{
			/*
			 * Use this device for the console
			 */
			break;
		}
	}
	if(minor==Console_Port_Count)
	{
		/*
		 * Failed to find a working device
		 */
		rtems_fatal_error_occurred(RTEMS_IO_ERROR);
	}
	
	Console_Port_Minor=minor;

	/*
	 *  Register Device Names
	 */
	status = rtems_io_register_name("/dev/console",
					major,
					Console_Port_Minor );
	if (status != RTEMS_SUCCESSFUL)
	{
		rtems_fatal_error_occurred(status);
	}
	Console_Port_Tbl[minor].pDeviceFns->deviceInitialize(
		Console_Port_Minor);

	for(minor++;minor<Console_Port_Count;minor++)
	{
		/*
		 * First perform the configuration dependant probe, then the
		 * device dependant probe
		 */
		if((!Console_Port_Tbl[minor].deviceProbe ||
		    Console_Port_Tbl[minor].deviceProbe(minor)) &&
		   Console_Port_Tbl[minor].pDeviceFns->deviceProbe(minor))
		{
			status = rtems_io_register_name(
				Console_Port_Tbl[minor].sDeviceName,
				major,
				minor );
			if (status != RTEMS_SUCCESSFUL)
			{
				rtems_fatal_error_occurred(status);
			}

			/*
			 * Initialize the hardware device.
			 */
			Console_Port_Tbl[minor].pDeviceFns->deviceInitialize(
				minor);

		}
	}

	return RTEMS_SUCCESSFUL;
}

/* PAGE
 *
 *  DEBUG_puts
 *
 *  This should be safe in the event of an error.  It attempts to ensure
 *  that no TX empty interrupts occur while it is doing polled IO.  Then
 *  it restores the state of that external interrupt.
 *
 *  Input parameters:
 *    string  - pointer to debug output string
 *
 *  Output parameters:  NONE
 *
 *  Return values:      NONE
 */

void DEBUG_puts(
	char *string
)
{
	char *s;
	unsigned32	Irql;

	rtems_interrupt_disable(Irql);

	for ( s = string ; *s ; s++ ) 
	{
		Console_Port_Tbl[Console_Port_Minor].pDeviceFns->
			deviceWritePolled(Console_Port_Minor, *s);
	}

	rtems_interrupt_enable(Irql);
}

/* PAGE
 *
 *  DEBUG_puth
 *
 *  This should be safe in the event of an error.  It attempts to ensure
 *  that no TX empty interrupts occur while it is doing polled IO.  Then
 *  it restores the state of that external interrupt.
 *
 *  Input parameters:
 *    ulHexNum - value to display
 *
 *  Output parameters:  NONE
 *
 *  Return values:      NONE
 */
void
DEBUG_puth(
    unsigned32 ulHexNum
    )
{
	unsigned long i,d;
	unsigned32 Irql;

	rtems_interrupt_disable(Irql);
	
	Console_Port_Tbl[Console_Port_Minor].pDeviceFns->
		deviceWritePolled(Console_Port_Minor, '0');
	Console_Port_Tbl[Console_Port_Minor].pDeviceFns->
		deviceWritePolled(Console_Port_Minor, 'x');

	for(i=32;i;)
	{
		i-=4;
		d=(ulHexNum>>i)&0xf;
		Console_Port_Tbl[Console_Port_Minor].pDeviceFns->
			deviceWritePolled(Console_Port_Minor,
					  (d<=9) ? d+'0' : d+'a'-0xa);
	}

	rtems_interrupt_enable(Irql);
}