/*
* drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
* implementation.
* Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
*
* Based on atari_SCC.c which was
* Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
* Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
*/
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/serial.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/console.h>
#include <linux/init.h>
#include <asm/setup.h>
#include <asm/bootinfo.h>
#ifdef CONFIG_MVME147_SCC
#include <asm/mvme147hw.h>
#endif
#ifdef CONFIG_MVME162_SCC
#include <asm/mvme16xhw.h>
#endif
#ifdef CONFIG_BVME6000_SCC
#include <asm/bvme6000hw.h>
#endif
#include <linux/generic_serial.h>
#include "scc.h"
#define CHANNEL_A 0
#define CHANNEL_B 1
#define SCC_MINOR_BASE 64
/* Shadows for all SCC write registers */
static unsigned char scc_shadow[2][16];
/* Location to access for SCC register access delay */
static volatile unsigned char *scc_del = NULL;
/* To keep track of STATUS_REG state for detection of Ext/Status int source */
static unsigned char scc_last_status_reg[2];
/***************************** Prototypes *****************************/
/* Function prototypes */
static void scc_disable_tx_interrupts(void * ptr);
static void scc_enable_tx_interrupts(void * ptr);
static void scc_disable_rx_interrupts(void * ptr);
static void scc_enable_rx_interrupts(void * ptr);
static int scc_get_CD(void * ptr);
static void scc_shutdown_port(void * ptr);
static int scc_set_real_termios(void *ptr);
static void scc_hungup(void *ptr);
static void scc_close(void *ptr);
static int scc_chars_in_buffer(void * ptr);
static int scc_open(struct tty_struct * tty, struct file * filp);
static int scc_ioctl(struct tty_struct * tty, struct file * filp,
unsigned int cmd, unsigned long arg);
static void scc_throttle(struct tty_struct *tty);
static void scc_unthrottle(struct tty_struct *tty);
static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp);
static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp);
static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp);
static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp);
static void scc_setsignals(struct scc_port *port, int dtr, int rts);
static void scc_break_ctl(struct tty_struct *tty, int break_state);
static struct tty_driver *scc_driver;
struct scc_port scc_ports[2];
int scc_initialized = 0;
/*---------------------------------------------------------------------------
* Interface from generic_serial.c back here
*--------------------------------------------------------------------------*/
static struct real_driver scc_real_driver = {
scc_disable_tx_interrupts,
scc_enable_tx_interrupts,
scc_disable_rx_interrupts,
scc_enable_rx_interrupts,
scc_get_CD,
scc_shutdown_port,
scc_set_real_termios,
scc_chars_in_buffer,
scc_close,
scc_hungup,
NULL
};
static const struct tty_operations scc_ops = {
.open = scc_open,
.close = gs_close,
.write = gs_write,
.put_char = gs_put_char,
.flush_chars = gs_flush_chars,
.write_room = gs_write_room,
.chars_in_buffer = gs_chars_in_buffer,
.flush_buffer = gs_flush_buffer,
.ioctl = scc_ioctl,
.throttle = scc_throttle,
.unthrottle = scc_unthrottle,
.set_termios = gs_set_termios,
.stop = gs_stop,
.start = gs_start,
.hangup = gs_hangup,
.break_ctl = scc_break_ctl,
};
/*----------------------------------------------------------------------------
* vme_scc_init() and support functions
*---------------------------------------------------------------------------*/
static int scc_init_drivers(void)
{
int error;
scc_driver = alloc_tty_driver(2);
if (!scc_driver)
return -