summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--arch/mips/Makefile23
-rw-r--r--drivers/char/dz.c1595
-rw-r--r--drivers/char/dz.h242
-rw-r--r--drivers/net/bagetlance.c1363
-rw-r--r--drivers/net/declance.c1265
-rw-r--r--drivers/scsi/dec_esp.c299
-rw-r--r--drivers/scsi/dec_esp.h42
-rw-r--r--drivers/tc/Makefile21
-rw-r--r--drivers/tc/tc.c230
-rw-r--r--drivers/tc/zs.c2108
-rw-r--r--drivers/tc/zs.h405
-rw-r--r--include/asm-mips/baget/baget.h69
-rw-r--r--include/asm-mips/baget/vac.h208
-rw-r--r--include/asm-mips/baget/vic.h193
-rw-r--r--include/asm-mips/dec/interrupts.h79
-rw-r--r--include/asm-mips/dec/ioasic_addrs.h67
-rw-r--r--include/asm-mips/dec/ioasic_ints.h108
-rw-r--r--include/asm-mips/dec/kn01.h28
-rw-r--r--include/asm-mips/dec/kn02.h41
-rw-r--r--include/asm-mips/dec/kn02xa.h34
-rw-r--r--include/asm-mips/dec/kn03.h33
-rw-r--r--include/asm-mips/dec/machtype.h20
-rw-r--r--include/asm-mips/dec/tc.h43
-rw-r--r--include/asm-mips/dec/tcinfo.h47
-rw-r--r--include/asm-mips/dec/tcmodule.h35
26 files changed, 8601 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 7e8536ec5..7f3baf949 100644
--- a/Makefile
+++ b/Makefile
@@ -187,6 +187,10 @@ ifdef CONFIG_HAMRADIO
DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a
endif
+ifeq ($(CONFIG_TC),y)
+DRIVERS := $(DRIVERS) drivers/tc/tc.a
+endif
+
include arch/$(ARCH)/Makefile
.S.s:
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index b5a448d3f..5935a513e 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 1998/08/25 09:14:34 ralf Exp $
+# $Id: Makefile,v 1.13 1998/10/18 13:37:31 tsbogend Exp $
#
# 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
@@ -97,6 +97,17 @@ CORE_FILES += arch/mips/algor/algor.o
SUBDIRS += arch/mips/algor
#LOADADDR += 0x80000000
endif
+
+#
+# DECstation family
+#
+ifdef CONFIG_DECSTATION
+CORE_FILES += arch/mips/dec/dec.o
+SUBDIRS += arch/mips/dec arch/mips/dec/prom
+LIBS += arch/mips/dec/prom/rexlib.a
+LOADADDR += 0x80040000
+endif
+
#
# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
#
@@ -106,12 +117,14 @@ SUBDIRS += arch/mips/jazz arch/mips/arc
LIBS += arch/mips/arc/arclib.a
LOADADDR += 0x80080000
endif
+
ifdef CONFIG_SNI_RM200_PCI
CORE_FILES += arch/mips/sni/sni.o
SUBDIRS += arch/mips/sni arch/mips/arc
LIBS += arch/mips/arc/arclib.a
LOADADDR += 0x80080000
endif
+
ifdef CONFIG_SGI
LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a
SUBDIRS += arch/mips/sgi/kernel arch/mips/arc
@@ -125,6 +138,14 @@ HOSTCC = cc
endif
#
+# Baget/MIPS
+#
+ifdef CONFIG_BAGET_MIPS
+SUBDIRS += arch/mips/baget arch/mips/baget/prom
+LIBS += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a
+endif
+
+#
# Choosing incompatible machines durings configuration will result in
# error messages during linking. Select a default linkscript if
# none has been choosen above.
diff --git a/drivers/char/dz.c b/drivers/char/dz.c
new file mode 100644
index 000000000..347638591
--- /dev/null
+++ b/drivers/char/dz.c
@@ -0,0 +1,1595 @@
+/*
+ * dz.c: Serial port driver for DECStations equiped
+ * with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+ * Changed name of dz_init to rs_init to be consistent with tc code
+ * [13-NOV-98] triemer fixed code to receive characters
+ * after patches by harald to irq code.
+ * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
+ * field from "current" - somewhere between 2.1.121 and 2.1.131
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/param.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm-mips/wbflush.h>
+/* for definition of SERIAL */
+#include <asm/dec/interrupts.h>
+
+/* for definition of struct console */
+#ifdef CONFIG_SERIAL_CONSOLE
+#define CONSOLE_LINE (3)
+#include <linux/console.h>
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+
+#define DEBUG_DZ 1
+#ifdef DEBUG_DZ
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+#include <asm/bootinfo.h>
+
+extern int (*prom_printf) (char *,...);
+#endif
+
+
+
+#include "dz.h"
+
+#define DZ_INTR_DEBUG 1
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+extern struct wait_queue *keypress_wait;
+static struct dz_serial *lines[4];
+static unsigned char tmp_buffer[256];
+
+
+
+#ifdef DEBUG_DZ
+/*
+ * debugging code to send out chars via prom
+ */
+static void debug_console( const char *s,int count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ if (*s == 10)
+ prom_printf("%c", 13);
+ prom_printf("%c", *s++);
+ }
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+ *
+ * These routines are used to access the registers of the DZ
+ * chip, hiding relocation differences between implementation.
+ * ------------------------------------------------------------
+ */
+
+static inline unsigned short dz_in (struct dz_serial *info, unsigned offset)
+{
+ volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
+ return *addr;
+}
+
+static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned short value)
+{
+
+ volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
+ *addr = value;
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop () and rs_start ()
+ *
+ * These routines are called before setting or resetting
+ * tty->stopped. They enable or disable transmitter interrupts,
+ * as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void dz_stop (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned short mask, tmp;
+
+
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR); /* read the TX flag */
+
+ tmp &= ~mask; /* clear the TX flag */
+ dz_out (info, DZ_TCR, tmp);
+}
+
+static void dz_start (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned short mask, tmp;
+
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR); /* read the TX flag */
+
+ tmp |= mask; /* set the TX flag */
+ dz_out (info, DZ_TCR, tmp);
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * Here starts the interrupt handling routines. All of the
+ * following subroutines are declared as inline and are folded
+ * into dz_interrupt. They were separated out for readability's
+ * sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer dz.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * dz_sched_event ()
+ *
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ * ------------------------------------------------------------
+ */
+static inline void dz_sched_event (struct dz_serial *info, int event)
+{
+ info->event |= 1 << event;
+ queue_task (&info->tqueue, &tq_serial);
+ mark_bh (SERIAL_BH);
+}
+
+/*
+ * ------------------------------------------------------------
+ * receive_char ()
+ *
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+static inline void receive_chars (struct dz_serial *info_in)
+{
+
+ struct dz_serial *info;
+ struct tty_struct *tty = 0;
+ struct async_icount *icount;
+ int ignore = 0;
+ unsigned short status, tmp;
+ unsigned char ch;
+
+ /* this code is going to be a problem...
+ the call to tty_flip_buffer is going to need
+ to be rethought...
+ */
+ do
+ {
+ status = dz_in (info_in, DZ_RBUF);
+ info = lines[LINE(status)];
+
+ /* punt so we don't get duplicate characters */
+ if (!(status & DZ_DVAL))
+ goto ignore_char;
+
+
+ ch = UCHAR(status); /* grab the char */
+
+#ifdef 0
+ if (info->is_console) {
+ if (ch == 0) return; /* it's a break ... */
+
+ wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */
+ }
+#endif
+
+ tty = info->tty; /* now tty points to the proper dev */
+ icount = &info->icount;
+
+ if (!tty) break;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
+
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = 0;
+ icount->rx++;
+
+ /* keep track of the statistics */
+ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
+ if (status & DZ_PERR) /* parity error */
+ icount->parity++;
+ else if (status & DZ_FERR) /* frame error */
+ icount->frame++;
+ if (status & DZ_OERR) /* overrun error */
+ icount->overrun++;
+
+ /* check to see if we should ignore the character
+ and mask off conditions that should be ignored
+ */
+
+ if (status & info->ignore_status_mask) {
+ if (++ignore > 100 ) break;
+ goto ignore_char;
+ }
+
+ /* mask off the error conditions we want to ignore */
+ tmp = status & info->read_status_mask;
+
+ if (tmp & DZ_PERR)
+ {
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ debug_console("PERR\n",5);
+ }
+ else if (tmp & DZ_FERR)
+ {
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ debug_console("FERR\n",5);
+ }
+ if (tmp & DZ_OERR)
+ {
+ debug_console("OERR\n",5);
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ }
+ }
+ }
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ ignore_char:
+ } while (status & DZ_DVAL);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * transmit_char ()
+ *
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+static inline void transmit_chars (struct dz_serial *info)
+{
+ unsigned char tmp;
+
+
+
+ if (info->x_char) { /* XON/XOFF chars */
+ dz_out (info, DZ_TDR, info->x_char);
+ info->icount.tx++;
+ info->x_char = 0;
+ return;
+ }
+
+ /* if nothing to do or stopped or hardware stopped */
+ if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) {
+ dz_stop (info->tty);
+ return;
+ }
+
+ /* if something to do ... (rember the dz has no output fifo so we go one char at a time :-< */
+ tmp = (unsigned short)info->xmit_buf[info->xmit_tail++];
+ dz_out (info, DZ_TDR, tmp);
+ info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1);
+ info->icount.tx++;
+
+ if (--info->xmit_cnt < WAKEUP_CHARS)
+ dz_sched_event (info, DZ_EVENT_WRITE_WAKEUP);
+
+
+ /* Are we done */
+ if (info->xmit_cnt <= 0) dz_stop (info->tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * check_modem_status ()
+ *
+ * Only valid for the MODEM line duh !
+ * ------------------------------------------------------------
+ */
+static inline void check_modem_status (struct dz_serial *info)
+{
+ unsigned short status;
+
+ /* if not ne modem line just return */
+ if (info->line != DZ_MODEM) return;
+
+ status = dz_in (info, DZ_MSR);
+
+ /* it's easy, since DSR2 is the only bit in the register */
+ if (status) info->icount.dsr++;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_interrupt ()
+ *
+ * this is the main interrupt routine for the DZ chip.
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+static void dz_interrupt (int irq, void *dev, struct pt_regs *regs)
+{
+ struct dz_serial *info;
+ unsigned short status;
+
+ status = dz_in ((struct dz_serial *)dev, DZ_CSR); /* get the reason why we just got an irq */
+ info = lines[LINE(status)]; /* re-arrange info the proper port */
+
+ if (status & DZ_RDONE)
+ receive_chars (info); /* the receive function */
+
+ if (status & DZ_TRDY)
+ transmit_chars (info);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the DZ interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh (void)
+{
+ run_task_queue (&tq_serial);
+}
+
+static void do_softint (void *private_data)
+{
+ struct dz_serial *info = (struct dz_serial *)private_data;
+ struct tty_struct *tty = info->tty;
+
+ if (!tty) return;
+
+ if (test_and_clear_bit (DZ_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible (&tty->write_wait);
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * -------------------------------------------------------------------
+ */
+static void do_serial_hangup (void *private_data)
+{
+ struct dz_serial *info = (struct dz_serial *)private_data;
+ struct tty_struct *tty = info->tty;;
+
+ if (!tty) return;
+
+ tty_hangup (tty);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * startup ()
+ *
+ * various initialization tasks
+ * -------------------------------------------------------------------
+ */
+static int startup (struct dz_serial *info)
+{
+ unsigned long page, flags;
+ unsigned short tmp;
+
+ if (info->is_initialized) return 0;
+
+ save_flags (flags);
+ cli ();
+
+ if (!info->port) {
+ if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
+ restore_flags (flags);
+ return -ENODEV;
+ }
+
+ if (!info->xmit_buf) {
+ page = get_free_page (GFP_KERNEL);
+ if (!page) {
+ restore_flags (flags);
+ return -ENOMEM;
+ }
+ info->xmit_buf = (unsigned char *)page;
+ }
+
+ if (info->tty) clear_bit (TTY_IO_ERROR, &info->tty->flags);
+
+ /* enable the interrupt and the scanning */
+ tmp = dz_in (info, DZ_CSR);
+ tmp |= (DZ_RIE | DZ_TIE | DZ_MSE);
+ dz_out (info, DZ_CSR, tmp);
+
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /* set up the speed */
+ change_speed (info);
+
+ /* clear the line transmitter buffer
+ I can't figure out why I need to do this - but
+ its necessary - in order for the console portion
+ and the interrupt portion to live happily side by side.
+ */
+
+ /* clear the line transmitter buffer
+ I can't figure out why I need to do this - but
+ its necessary - in order for the console portion
+ and the interrupt portion to live happily side by side.
+ */
+
+ info->is_initialized = 1;
+
+ restore_flags (flags);
+ return 0;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * shutdown ()
+ *
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ * -------------------------------------------------------------------
+ */
+static void shutdown (struct dz_serial *info)
+{
+ unsigned long flags;
+ unsigned short tmp;
+
+ if (!info->is_initialized) return;
+
+ save_flags (flags);
+ cli ();
+
+ dz_stop (info->tty);
+
+
+
+ info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */
+ dz_out (info, DZ_LPR, info->cflags);
+
+ if (info->xmit_buf) { /* free Tx buffer */
+ free_page ((unsigned long)info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ tmp = dz_in (info, DZ_TCR);
+ if (tmp & DZ_MODEM_DTR) {
+ tmp &= ~DZ_MODEM_DTR;
+ dz_out (info, DZ_TCR, tmp);
+ }
+ }
+
+ if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
+
+ info->is_initialized = 0;
+ restore_flags (flags);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * change_speed ()
+ *
+ * set the baud rate.
+ * -------------------------------------------------------------------
+ */
+static void change_speed (struct dz_serial *info)
+{
+ unsigned long flags;
+ unsigned cflag;
+ int baud;
+
+ if (!info->tty || !info->tty->termios) return;
+
+ save_flags (flags);
+ cli ();
+
+ info->cflags = info->line;
+
+ cflag = info->tty->termios->c_cflag;
+
+ switch (cflag & CSIZE) {
+ case CS5: info->cflags |= DZ_CS5; break;
+ case CS6: info->cflags |= DZ_CS6; break;
+ case CS7: info->cflags |= DZ_CS7; break;
+ case CS8:
+ default: info->cflags |= DZ_CS8;
+ }
+
+ if (cflag & CSTOPB) info->cflags |= DZ_CSTOPB;
+ if (cflag & PARENB) info->cflags |= DZ_PARENB;
+ if (cflag & PARODD) info->cflags |= DZ_PARODD;
+
+ baud = tty_get_baud_rate (info->tty);
+ switch (baud) {
+ case 50 : info->cflags |= DZ_B50; break;
+ case 75 : info->cflags |= DZ_B75; break;
+ case 110 : info->cflags |= DZ_B110; break;
+ case 134 : info->cflags |= DZ_B134; break;
+ case 150 : info->cflags |= DZ_B150; break;
+ case 300 : info->cflags |= DZ_B300; break;
+ case 600 : info->cflags |= DZ_B600; break;
+ case 1200: info->cflags |= DZ_B1200; break;
+ case 1800: info->cflags |= DZ_B1800; break;
+ case 2000: info->cflags |= DZ_B2000; break;
+ case 2400: info->cflags |= DZ_B2400; break;
+ case 3600: info->cflags |= DZ_B3600; break;
+ case 4800: info->cflags |= DZ_B4800; break;
+ case 7200: info->cflags |= DZ_B7200; break;
+ case 9600:
+ default : info->cflags |= DZ_B9600;
+ }
+
+ info->cflags |= DZ_RXENAB;
+ dz_out (info, DZ_LPR, info->cflags);
+
+ /* setup accept flag */
+ info->read_status_mask = DZ_OERR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= (DZ_FERR | DZ_PERR);
+
+ /* characters to ignore */
+ info->ignore_status_mask = 0;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= (DZ_FERR | DZ_PERR);
+
+ restore_flags (flags);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_flush_char ()
+ *
+ * Flush the buffer.
+ * -------------------------------------------------------------------
+ */
+static void dz_flush_chars (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf)
+ return;
+
+ save_flags (flags);
+ cli ();
+
+ dz_start (info->tty);
+
+ restore_flags (flags);
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * dz_write ()
+ *
+ * main output routine.
+ * -------------------------------------------------------------------
+ */
+static int dz_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
+ int c, ret = 0;
+
+ if (!tty ) return ret;
+ if (!info->xmit_buf) return ret;
+ if (!tmp_buf) tmp_buf = tmp_buffer;
+
+
+
+ if (from_user) {
+
+ down (&tmp_buf_sem);
+ while (1) {
+ c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) break;
+
+ c -= copy_from_user (tmp_buf, buf, c);
+ if (!c) {
+ if (!ret) ret = -EFAULT;
+ break;
+ }
+
+ save_flags (flags);
+ cli ();
+
+ c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+
+ restore_flags(flags);
+
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+
+ up (&tmp_buf_sem);
+ } else {
+
+
+ while (1) {
+ save_flags (flags);
+ cli ();
+
+ c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags (flags);
+ break;
+ }
+ memcpy (info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+
+ restore_flags (flags);
+
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
+
+
+ if (info->xmit_cnt)
+ {
+ if (!tty->stopped)
+ {
+ if (!tty->hw_stopped)
+ {
+ dz_start (info->tty);
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_write_room ()
+ *
+ * compute the amount of space available for writing.
+ * -------------------------------------------------------------------
+ */
+static int dz_write_room (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ int ret;
+
+ ret = DZ_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0) ret = 0;
+ return ret;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_chars_in_buffer ()
+ *
+ * compute the amount of char left to be transmitted
+ * -------------------------------------------------------------------
+ */
+static int dz_chars_in_buffer (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ return info->xmit_cnt;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * dz_flush_buffer ()
+ *
+ * Empty the output buffer
+ * -------------------------------------------------------------------
+ */
+static void dz_flush_buffer (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ cli ();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ sti ();
+
+ wake_up_interruptible (&tty->write_wait);
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_throttle () and dz_unthrottle ()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled (or not).
+ * ------------------------------------------------------------
+ */
+static void dz_throttle (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ if (I_IXOFF(tty))
+ info->x_char = STOP_CHAR(tty);
+}
+
+static void dz_unthrottle (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ info->x_char = START_CHAR(tty);
+ }
+}
+
+static void dz_send_xchar (struct tty_struct *tty, char ch)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ info->x_char = ch;
+
+ if (ch) dz_start (info->tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl () and friends
+ * ------------------------------------------------------------
+ */
+static int get_serial_info (struct dz_serial *info, struct serial_struct *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset (&tmp, 0, sizeof(tmp));
+
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->port;
+ tmp.irq = SERIAL;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+
+ return copy_to_user (retinfo, &tmp, sizeof(*retinfo));
+}
+
+static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info)
+{
+ struct serial_struct new_serial;
+ struct dz_serial old_info;
+ int retval = 0;
+
+ if (!new_info)
+ return -EFAULT;
+
+ copy_from_user (&new_serial, new_info, sizeof(new_serial));
+ old_info = *info;
+
+ if (!suser())
+ return -EPERM;
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud_base = new_serial.baud_base;
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+
+ retval = startup (info);
+ return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info (struct dz_serial *info, unsigned int *value)
+{
+ unsigned short status = dz_in (info, DZ_LPR);
+
+ return put_user (status, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break (struct dz_serial *info, int duration)
+{
+ unsigned long flags;
+ unsigned short tmp, mask;
+
+ if (!info->port)
+ return;
+
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR);
+ tmp |= mask;
+
+ current->state = TASK_INTERRUPTIBLE;
+
+ save_flags (flags);
+ cli();
+
+ dz_out (info, DZ_TCR, tmp);
+
+ schedule_timeout(jiffies + duration);
+
+ tmp &= ~mask;
+ dz_out (info, DZ_TCR, tmp);
+
+ restore_flags (flags);
+}
+
+static int dz_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int error;
+ struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+ int retval;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change (tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent (tty, 0);
+ if (!arg)
+ send_break (info, HZ/4); /* 1/4 second */
+ return 0;
+
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change (tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent (tty, 0);
+ send_break (info, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+ error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long));
+ if (error)
+ return error;
+ put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
+ return 0;
+
+ case TIOCSSOFTCAR:
+ error = get_user (arg, (unsigned long *)arg);
+ if (error)
+ return error;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ return 0;
+
+ case TIOCGSERIAL:
+ error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info (info, (struct serial_struct *)arg);
+
+ case TIOCSSERIAL:
+ return set_serial_info (info, (struct serial_struct *) arg);
+
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return get_lsr_info (info, (unsigned int *)arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct dz_serial));
+ if (error)
+ return error;
+ copy_to_user((struct dz_serial *)arg, info, sizeof(struct dz_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static void dz_set_termios (struct tty_struct *tty,
+ struct termios *old_termios)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+
+ change_speed (info);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ dz_start (tty);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we turn off
+ * the transmit enable and receive enable flags.
+ * ------------------------------------------------------------
+ */
+static void dz_close (struct tty_struct *tty, struct file *filp)
+{
+ struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info) return;
+
+ save_flags (flags);
+ cli();
+
+ if (tty_hung_up_p (filp)) {
+ restore_flags (flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("dz_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+
+ if (--info->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+
+ if (info->count) {
+ restore_flags (flags);
+ return;
+ }
+ info->flags |= DZ_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & DZ_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & DZ_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+
+ if (info->closing_wait != DZ_CLOSING_WAIT_NONE)
+ tty_wait_until_sent (tty, info->closing_wait);
+
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts.
+ */
+
+ shutdown (info);
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer (tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+
+ if (tty->ldisc.num != ldiscs[N_TTY].num) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open)(tty);
+ }
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(jiffies + info->close_delay);
+ }
+ wake_up_interruptible (&info->open_wait);
+ }
+
+ info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING);
+ wake_up_interruptible (&info->close_wait);
+
+ restore_flags (flags);
+}
+
+/*
+ * dz_hangup () --- called by tty_hangup() when a hangup is signaled.
+ */
+static void dz_hangup (struct tty_struct *tty)
+{
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ dz_flush_buffer (tty);
+ shutdown (info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible (&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz_serial *info)
+{
+ struct wait_queue wait = { current, NULL };
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & DZ_CLOSING) {
+ interruptible_sleep_on (&info->close_wait);
+ return -EAGAIN;
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & DZ_NORMAL_ACTIVE)
+ return -EBUSY;
+
+ if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+ (info->flags & DZ_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+
+ if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+ (info->flags & DZ_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= DZ_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & DZ_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= DZ_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & DZ_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * dz_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue (&info->open_wait, &wait);
+
+ info->count--;
+ info->blocked_open++;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p (filp) || !(info->is_initialized)) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (!(info->flags & DZ_CALLOUT_ACTIVE) &&
+ !(info->flags & DZ_CLOSING) && do_clocal)
+ break;
+ if (signal_pending (current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue (&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+
+ if (retval)
+ return retval;
+ info->flags |= DZ_NORMAL_ACTIVE;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port. It also performs the
+ * serial-specific initialization for the tty structure.
+ */
+static int dz_open (struct tty_struct *tty, struct file *filp)
+{
+ struct dz_serial *info;
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+
+ /* The dz lines for the mouse/keyboard must be
+ * opened using their respective drivers.
+ */
+ if ((line < 0) || (line >= DZ_NB_PORT))
+ return -ENODEV;
+
+ if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
+ return -ENODEV;
+
+ info = lines[line];
+ info->count++;
+
+ tty->driver_data = info;
+ info->tty = tty;
+
+ /*
+ * Start up serial port
+ */
+ retval = startup (info);
+ if (retval)
+ return retval;
+
+
+
+ retval = block_til_ready (tty, filp, info);
+ if (retval)
+ return retval;
+
+ if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed (info);
+
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+ return 0;
+}
+
+static void show_serial_version (void)
+{
+ printk("%s%s\n", dz_name, dz_version);
+}
+
+
+__initfunc(int dz_init(void))
+{
+ int i, flags;
+ struct dz_serial *info;
+
+ /* Setup base handler, and timer table. */
+ init_bh (SERIAL_BH, do_serial_bh);
+
+ show_serial_version ();
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = DZ_NB_PORT;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+
+ serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = dz_open;
+ serial_driver.close = dz_close;
+ serial_driver.write = dz_write;
+ serial_driver.flush_chars = dz_flush_chars;
+ serial_driver.write_room = dz_write_room;
+ serial_driver.chars_in_buffer = dz_chars_in_buffer;
+ serial_driver.flush_buffer = dz_flush_buffer;
+ serial_driver.ioctl = dz_ioctl;
+ serial_driver.throttle = dz_throttle;
+ serial_driver.unthrottle = dz_unthrottle;
+ serial_driver.send_xchar = dz_send_xchar;
+ serial_driver.set_termios = dz_set_termios;
+ serial_driver.stop = dz_stop;
+ serial_driver.start = dz_start;
+ serial_driver.hangup = dz_hangup;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (tty_register_driver (&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver (&callout_driver))
+ panic("Couldn't register callout driver\n");
+ save_flags(flags); cli();
+
+ i = 0;
+ for (info = &multi[i]; i < DZ_NB_PORT; i++)
+ {
+ lines[i] = info;
+ info->magic = SERIAL_MAGIC;
+
+ if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
+ info->port = (unsigned long) KN01_DZ11_BASE;
+ else
+ info->port = (unsigned long) KN02_DZ11_BASE;
+
+ info->line = i;
+ info->tty = 0;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->callout_termios = callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+
+ /* If we are pointing to address zero then punt - not correctly
+ set up in setup.c to handle this. */
+ if (! info->port)
+ return 0;
+
+ printk("ttyS%02d at 0x%04x (irq = %d)\n", info->line, info->port, SERIAL);
+ }
+
+ /* reset the chip */
+#ifndef CONFIG_SERIAL_CONSOLE
+ dz_out(info, DZ_CSR, DZ_CLR);
+ while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR) ;
+ wbflush();
+
+ /* enable scanning */
+ dz_out(info, DZ_CSR, DZ_MSE);
+#endif
+
+ /* order matters here... the trick is that flags
+ is updated... in request_irq - to immediatedly obliterate
+ it is unwise. */
+ restore_flags(flags);
+
+
+ if (request_irq (SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0]))
+ panic ("Unable to register DZ interrupt\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+static void dz_console_put_char (unsigned char ch)
+{
+ long flags;
+ int loops = 1000;
+ unsigned short tmp = ch;
+ /* this code sends stuff out to serial device - spinning its
+ wheels and waiting. */
+
+ /* force the issue - point it at lines[3]*/
+ dz_console=&multi[CONSOLE_LINE];
+
+ save_flags(flags);
+ cli();
+
+
+ /* spin our wheels */
+ while (((dz_in(dz_console,DZ_TCR) & DZ_TRDY) != DZ_TRDY) && loops--)
+ ;
+
+ /* Actually transmit the character. */
+ dz_out (dz_console, DZ_TDR, tmp);
+
+ restore_flags(flags);
+}
+/*
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+ *
+ * dz_console_print is registered for printk.
+ * -------------------------------------------------------------------
+ */
+static void dz_console_print (struct console *cons,
+ const char *str,
+ unsigned int count)
+{
+#ifdef DEBUG_DZ
+ prom_printf((char *)str);
+#endif
+ while (count--)
+ {
+ if (*str == '\n')
+ dz_console_put_char ('\r');
+ dz_console_put_char (*str++);
+ }
+}
+
+static int dz_console_wait_key(struct console *co)
+{
+ return 0;
+}
+
+static kdev_t dz_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+__initfunc(static int dz_console_setup(struct console *co, char *options))
+{
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
+ unsigned short mask,tmp;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while(*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
+ }
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch(baud) {
+ case 1200:
+ cflag |= DZ_B1200;
+ break;
+ case 2400:
+ cflag |= DZ_B2400;
+ break;
+ case 4800:
+ cflag |= DZ_B4800;
+ break;
+ case 9600:
+ default:
+ cflag |= DZ_B9600;
+ break;
+ }
+ switch(bits) {
+ case 7:
+ cflag |= DZ_CS7;
+ break;
+ default:
+ case 8:
+ cflag |= DZ_CS8;
+ break;
+ }
+ switch(parity) {
+ case 'o': case 'O':
+ cflag |= DZ_PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= DZ_PARENB;
+ break;
+ }
+ co->cflag = cflag;
+
+ /* TOFIX: force to console line */
+ dz_console = &multi[CONSOLE_LINE];
+ dz_console->port = KN01_DZ11_BASE;
+ dz_console->line = CONSOLE_LINE;
+
+ dz_out(dz_console, DZ_CSR, DZ_CLR);
+ while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
+ ;
+
+ /* enable scanning */
+ dz_out(dz_console, DZ_CSR, DZ_MSE);
+
+ /* Set up flags... */
+ dz_console->cflags = 0;
+ dz_console->cflags |= DZ_B9600;
+ dz_console->cflags |= DZ_CS8;
+ dz_console->cflags |= DZ_PARENB;
+ dz_out (dz_console, DZ_LPR, dz_console->cflags);
+
+
+ mask = 1 << dz_console->line;
+ tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */
+ if (!(tmp & mask)) {
+ tmp |= mask; /* set the TX flag */
+ dz_out (dz_console, DZ_TCR, tmp);
+ }
+
+
+ /* TOFIX: force to console line */
+ dz_console = &multi[CONSOLE_LINE];
+ dz_console->port = KN01_DZ11_BASE;
+ dz_console->line = CONSOLE_LINE;
+
+ dz_out(dz_console, DZ_CSR, DZ_CLR);
+ while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
+ ;
+
+ /* enable scanning */
+ dz_out(dz_console, DZ_CSR, DZ_MSE);
+
+ /* Set up flags... */
+ dz_console->cflags = 0;
+ dz_console->cflags |= DZ_B9600;
+ dz_console->cflags |= DZ_CS8;
+ dz_console->cflags |= DZ_PARENB;
+ dz_out (dz_console, DZ_LPR, dz_console->cflags);
+
+
+ mask = 1 << dz_console->line;
+ tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */
+ if (!(tmp & mask)) {
+ tmp |= mask; /* set the TX flag */
+ dz_out (dz_console, DZ_TCR, tmp);
+ }
+
+
+ return 0;
+}
+
+static struct console dz_sercons = {
+ "ttyS",
+ dz_console_print,
+ NULL,
+ dz_console_device,
+ dz_console_wait_key,
+ NULL,
+ dz_console_setup,
+ CON_CONSDEV | CON_PRINTBUFFER,
+ CONSOLE_LINE,
+ 0,
+ NULL
+};
+
+__initfunc (long dz_serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&dz_sercons);
+
+ return kmem_start;
+}
+
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
diff --git a/drivers/char/dz.h b/drivers/char/dz.h
new file mode 100644
index 000000000..1b986d908
--- /dev/null
+++ b/drivers/char/dz.h
@@ -0,0 +1,242 @@
+/*
+ * dz.h: Serial port driver for DECStations equiped
+ * with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ */
+#ifndef DZ_SERIAL_H
+#define DZ_SERIAL_H
+
+/*
+ * Definitions for the Control and Status Received.
+ */
+#define DZ_TRDY 0x8000 /* Transmitter empty */
+#define DZ_TIE 0x4000 /* Transmitter Interrupt Enable */
+#define DZ_RDONE 0x0080 /* Receiver data ready */
+#define DZ_RIE 0x0040 /* Receive Interrupt Enable */
+#define DZ_MSE 0x0020 /* Master Scan Enable */
+#define DZ_CLR 0x0010 /* Master reset */
+#define DZ_MAINT 0x0008 /* Loop Back Mode */
+
+/*
+ * Definitions for the Received buffer.
+ */
+#define DZ_RBUF_MASK 0x00FF /* Data Mask in the Receive Buffer */
+#define DZ_LINE_MASK 0x0300 /* Line Mask in the Receive Buffer */
+#define DZ_DVAL 0x8000 /* Valid Data indicator */
+#define DZ_OERR 0x4000 /* Overrun error indicator */
+#define DZ_FERR 0x2000 /* Frame error indicator */
+#define DZ_PERR 0x1000 /* Parity error indicator */
+
+#define LINE(x) (x & DZ_LINE_MASK) >> 8 /* Get the line number from the input buffer */
+#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK)
+
+/*
+ * Definitions for the Transmit Register.
+ */
+#define DZ_LINE_KEYBOARD 0x0001
+#define DZ_LINE_MOUSE 0x0002
+#define DZ_LINE_MODEM 0x0004
+#define DZ_LINE_PRINTER 0x0008
+
+#define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */
+
+/*
+ * Definitions for the Modem Status Register.
+ */
+#define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */
+
+/*
+ * Definitions for the Transmit Data Register.
+ */
+#define DZ_BRK0 0x0100 /* Break assertion for line 0 */
+#define DZ_BRK1 0x0200 /* Break assertion for line 1 */
+#define DZ_BRK2 0x0400 /* Break assertion for line 2 */
+#define DZ_BRK3 0x0800 /* Break assertion for line 3 */
+
+/*
+ * Definitions for the Line Parameter Register.
+ */
+#define DZ_KEYBOARD 0x0000 /* line 0 = keyboard */
+#define DZ_MOUSE 0x0001 /* line 1 = mouse */
+#define DZ_MODEM 0x0002 /* line 2 = modem */
+#define DZ_PRINTER 0x0003 /* line 3 = printer */
+
+#define DZ_CSIZE 0x0018 /* Number of bits per byte (mask) */
+#define DZ_CS5 0x0000 /* 5 bits per byte */
+#define DZ_CS6 0x0008 /* 6 bits per byte */
+#define DZ_CS7 0x0010 /* 7 bits per byte */
+#define DZ_CS8 0x0018 /* 8 bits per byte */
+
+#define DZ_CSTOPB 0x0020 /* 2 stop bits instead of one */
+
+#define DZ_PARENB 0x0040 /* Parity enable */
+#define DZ_PARODD 0x0080 /* Odd parity instead of even */
+
+#define DZ_CBAUD 0x0E00 /* Baud Rate (mask) */
+#define DZ_B50 0x0000
+#define DZ_B75 0x0100
+#define DZ_B110 0x0200
+#define DZ_B134 0x0300
+#define DZ_B150 0x0400
+#define DZ_B300 0x0500
+#define DZ_B600 0x0600
+#define DZ_B1200 0x0700
+#define DZ_B1800 0x0800
+#define DZ_B2000 0x0900
+#define DZ_B2400 0x0A00
+#define DZ_B3600 0x0B00
+#define DZ_B4800 0x0C00
+#define DZ_B7200 0x0D00
+#define DZ_B9600 0x0E00
+
+#define DZ_CREAD 0x1000 /* Enable receiver */
+#define DZ_RXENAB 0x1000 /* enable receive char */
+/*
+ * Addresses for the DZ registers
+ */
+#define DZ_CSR 0x00 /* Control and Status Register */
+#define DZ_RBUF 0x08 /* Receive Buffer */
+#define DZ_LPR 0x08 /* Line Parameters Register */
+#define DZ_TCR 0x10 /* Transmitter Control Register */
+#define DZ_MSR 0x18 /* Modem Status Register */
+#define DZ_TDR 0x18 /* Transmit Data Register */
+
+
+#define DZ_NB_PORT 4
+
+#define DZ_XMIT_SIZE 4096 /* buffer size */
+#define WAKEUP_CHARS DZ_XMIT_SIZE/4
+
+#define DZ_EVENT_WRITE_WAKEUP 0
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+#define DZ_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define DZ_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define DZ_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define DZ_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define DZ_CLOSING 0x08000000 /* Serial port is closing */
+#define DZ_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define DZ_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+#define DZ_CLOSING_WAIT_INF 0
+#define DZ_CLOSING_WAIT_NONE 65535
+
+#define DZ_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+#define DZ_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define DZ_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+
+struct dz_serial {
+ unsigned port; /* base address for the port */
+ int type;
+ int flags;
+ int baud_base;
+ int blocked_open;
+ unsigned short close_delay;
+ unsigned short closing_wait;
+ unsigned short line; /* port/line number */
+ unsigned short cflags; /* line configuration flag */
+ unsigned short x_char; /* xon/xoff character */
+ unsigned short read_status_mask; /* mask for read condition */
+ unsigned short ignore_status_mask; /* mask for ignore condition */
+ unsigned long event; /* mask used in BH */
+ unsigned char *xmit_buf; /* Transmit buffer */
+ int xmit_head; /* Position of the head */
+ int xmit_tail; /* Position of the tail */
+ int xmit_cnt; /* Count of the chars in the buffer */
+ int count; /* indicates how many times it has been opened */
+ int magic;
+
+ struct async_icount icount; /* keep track of things ... */
+ struct tty_struct *tty; /* tty associated */
+ struct tq_struct tqueue; /* Queue for BH */
+ struct tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+
+ unsigned char is_console; /* flag indicating a serial console */
+ unsigned char is_initialized;
+};
+
+static struct dz_serial multi[DZ_NB_PORT]; /* Four serial lines in the DZ chip */
+static struct dz_serial *dz_console;
+static struct tty_driver serial_driver, callout_driver;
+
+static struct tty_struct *serial_table[DZ_NB_PORT];
+static struct termios *serial_termios[DZ_NB_PORT];
+static struct termios *serial_termios_locked[DZ_NB_PORT];
+
+static int serial_refcount;
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static char *dz_name = "DECstation DZ serial driver version ";
+static char *dz_version = "1.02";
+
+static inline unsigned short dz_in (struct dz_serial *, unsigned);
+static inline void dz_out (struct dz_serial *, unsigned, unsigned short);
+
+static inline void dz_sched_event (struct dz_serial *, int);
+static inline void receive_chars (struct dz_serial *);
+static inline void transmit_chars (struct dz_serial *);
+static inline void check_modem_status (struct dz_serial *);
+
+static void dz_stop (struct tty_struct *);
+static void dz_start (struct tty_struct *);
+static void dz_interrupt (int, void *, struct pt_regs *);
+static void do_serial_bh (void);
+static void do_softint (void *);
+static void do_serial_hangup (void *);
+static void change_speed (struct dz_serial *);
+static void dz_flush_chars (struct tty_struct *);
+static void dz_console_print (struct console *, const char *, unsigned int);
+static void dz_flush_buffer (struct tty_struct *);
+static void dz_throttle (struct tty_struct *);
+static void dz_unthrottle (struct tty_struct *);
+static void dz_send_xchar (struct tty_struct *, char);
+static void shutdown (struct dz_serial *);
+static void send_break (struct dz_serial *, int);
+static void dz_set_termios (struct tty_struct *, struct termios *);
+static void dz_close (struct tty_struct *, struct file *);
+static void dz_hangup (struct tty_struct *);
+static void show_serial_version (void);
+
+static int dz_write (struct tty_struct *, int, const unsigned char *, int);
+static int dz_write_room (struct tty_struct *);
+static int dz_chars_in_buffer (struct tty_struct *);
+static int startup (struct dz_serial *);
+static int get_serial_info (struct dz_serial *, struct serial_struct *);
+static int set_serial_info (struct dz_serial *, struct serial_struct *);
+static int get_lsr_info (struct dz_serial *, unsigned int *);
+static int dz_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long);
+static int block_til_ready (struct tty_struct *, struct file *, struct dz_serial *);
+static int dz_open (struct tty_struct *, struct file *);
+
+#ifdef MODULE
+int init_module (void)
+void cleanup_module (void)
+#endif
+
+#endif
+
+#endif /* DZ_SERIAL_H */
diff --git a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c
new file mode 100644
index 000000000..f08007e6d
--- /dev/null
+++ b/drivers/net/bagetlance.c
@@ -0,0 +1,1363 @@
+/* $Id$
+ * vmelance.c: Ethernet driver for VME Lance cards on Baget/MIPS
+ * This code stealed and adopted from linux/drivers/net/atarilance.c
+ * See that for author info
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+/*
+ * Driver code for Baget/Lance taken from atarilance.c, which also
+ * works well in case of Besta. Most significant changes made here
+ * related with 16BIT-only access to A24 space.
+ */
+
+static char *version = "bagetlance.c: v1.1 11/10/98\n";
+
+#include <linux/module.h>
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/baget/baget.h>
+
+#define BAGET_LANCE_IRQ BAGET_IRQ_MASK(0xdf)
+
+/*
+ * Define following if you don't need 16BIT-only access to Lance memory
+ * (Normally BAGET needs it)
+ */
+#undef NORMAL_MEM_ACCESS
+
+/* Debug level:
+ * 0 = silent, print only serious errors
+ * 1 = normal, print error messages
+ * 2 = debug, print debug infos
+ * 3 = debug, print even more debug infos (packet data)
+ */
+
+#define LANCE_DEBUG 1
+
+#ifdef LANCE_DEBUG
+static int lance_debug = LANCE_DEBUG;
+#else
+static int lance_debug = 1;
+#endif
+MODULE_PARM(lance_debug, "i");
+
+/* Print debug messages on probing? */
+#undef LANCE_DEBUG_PROBE
+
+#define DPRINTK(n,a) \
+ do { \
+ if (lance_debug >= n) \
+ printk a; \
+ } while( 0 )
+
+#ifdef LANCE_DEBUG_PROBE
+# define PROBE_PRINT(a) printk a
+#else
+# define PROBE_PRINT(a)
+#endif
+
+/* These define the number of Rx and Tx buffers as log2. (Only powers
+ * of two are valid)
+ * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
+ * is more time critical then sending and packets may have to remain in the
+ * board's memory when main memory is low.
+ */
+
+/* Baget Lance has 64K on-board memory, so it looks we can't increase
+ buffer quantity (40*1.5K is about 64K) */
+
+#define TX_LOG_RING_SIZE 3
+#define RX_LOG_RING_SIZE 5
+
+/* These are the derived values */
+
+#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE)
+#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5)
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE)
+#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5)
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+ volatile unsigned short base; /* Low word of base addr */
+#ifdef NORMAL_MEM_ACCESS
+ /* Following two fields are joined into one short to guarantee
+ 16BIT access to Baget lance registers */
+ volatile unsigned char flag;
+ unsigned char base_hi; /* High word of base addr (unused) */
+#else
+/* Following macros are used as replecements to 8BIT fields */
+#define GET_FLAG(h) (((h)->flag_base_hi >> 8) & 0xff)
+#define SET_FLAG(h,f) (h)->flag_base_hi = ((h)->flag_base_hi & 0xff) | \
+ (((unsigned)(f)) << 8)
+ volatile unsigned short flag_base_hi;
+#endif
+ volatile short buf_length; /* This length is 2s complement! */
+ volatile short msg_length; /* This length is "normal". */
+};
+
+
+struct lance_tx_head {
+ volatile unsigned short base; /* Low word of base addr */
+#ifdef NORMAL_MEM_ACCESS
+/* See comments above about 8BIT-access Baget A24-space problems */
+ volatile unsigned char flag;
+ unsigned char base_hi; /* High word of base addr (unused) */
+#else
+ volatile unsigned short flag_base_hi;
+#endif
+ volatile short length; /* Length is 2s complement! */
+ volatile short misc;
+};
+
+struct ringdesc {
+ volatile unsigned short adr_lo; /* Low 16 bits of address */
+#ifdef NORMAL_MEM_ACCESS
+/* See comments above about 8BIT-access Bage A24-space problems */
+ unsigned char len; /* Length bits */
+ unsigned char adr_hi; /* High 8 bits of address (unused) */
+#else
+ volatile unsigned short len_adr_hi;
+#endif
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+ unsigned short mode; /* Pre-set mode */
+ unsigned char hwaddr[6]; /* Physical ethernet address */
+ unsigned filter[2]; /* Multicast filter (unused). */
+ /* Receive and transmit ring base, along with length bits. */
+ struct ringdesc rx_ring;
+ struct ringdesc tx_ring;
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+ struct lance_init_block init;
+ struct lance_tx_head tx_head[TX_RING_SIZE];
+ struct lance_rx_head rx_head[RX_RING_SIZE];
+ char packet_area[0]; /* packet data follow after the
+ * init block and the ring
+ * descriptors and are located
+ * at runtime */
+};
+
+/* RieblCard specifics:
+ * The original TOS driver for these cards reserves the area from offset
+ * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
+ * Ethernet address there, and the magic for verifying the data's validity.
+ * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
+ * is reserved for the interrupt vector number.
+ */
+#define RIEBL_RSVD_START 0xee70
+#define RIEBL_RSVD_END 0xeec0
+#define RIEBL_MAGIC 0x09051990
+#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a))
+#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e))
+#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe))
+
+/* This is a default address for the old RieblCards without a battery
+ * that have no ethernet address at boot time. 00:00:36:04 is the
+ * prefix for Riebl cards, the 00:00 at the end is arbitrary.
+ */
+
+static unsigned char OldRieblDefHwaddr[6] = {
+ 0x00, 0x00, 0x36, 0x04, 0x00, 0x00
+};
+
+/* I/O registers of the Lance chip */
+
+struct lance_ioreg {
+/* base+0x0 */ volatile unsigned short data;
+/* base+0x2 */ volatile unsigned short addr;
+ unsigned char _dummy1[3];
+/* base+0x7 */ volatile unsigned char ivec;
+ unsigned char _dummy2[5];
+/* base+0xd */ volatile unsigned char eeprom;
+ unsigned char _dummy3;
+/* base+0xf */ volatile unsigned char mem;
+};
+
+/* Types of boards this driver supports */
+
+enum lance_type {
+ OLD_RIEBL, /* old Riebl card without battery */
+ NEW_RIEBL, /* new Riebl card with battery */
+ PAM_CARD /* PAM card with EEPROM */
+};
+
+static char *lance_names[] = {
+ "Riebl-Card (without battery)",
+ "Riebl-Card (with battery)",
+ "PAM intern card"
+};
+
+/* The driver's private device structure */
+
+struct lance_private {
+ enum lance_type cardtype;
+ struct lance_ioreg *iobase;
+ struct lance_memory *mem;
+ int cur_rx, cur_tx; /* The next free ring entry */
+ int dirty_tx; /* Ring entries to be freed. */
+ /* copy function */
+ void *(*memcpy_f)( void *, const void *, size_t );
+ struct net_device_stats stats;
+/* These two must be ints for set_bit() */
+ int tx_full;
+ int lock;
+};
+
+/* I/O register access macros */
+
+#define MEM lp->mem
+#define DREG IO->data
+#define AREG IO->addr
+#define REGA(a) ( AREG = (a), DREG )
+
+/* Definitions for packet buffer access: */
+#define PKT_BUF_SZ 1544
+/* Get the address of a packet buffer corresponding to a given buffer head */
+#define PKTBUF_ADDR(head) (((unsigned char *)(MEM)) + (head)->base)
+
+/* Possible memory/IO addresses for probing */
+
+struct lance_addr {
+ unsigned long memaddr;
+ unsigned long ioaddr;
+ int slow_flag;
+} lance_addr_list[] = {
+ { BAGET_LANCE_MEM_BASE, BAGET_LANCE_IO_BASE, 1 } /* Baget Lance */
+};
+
+#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+
+
+#define LANCE_HI_BASE (0xff & (BAGET_LANCE_MEM_BASE >> 16))
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define TMD1_ENP 0x01 /* end of packet */
+#define TMD1_STP 0x02 /* start of packet */
+#define TMD1_DEF 0x04 /* deferred */
+#define TMD1_ONE 0x08 /* one retry needed */
+#define TMD1_MORE 0x10 /* more than one retry needed */
+#define TMD1_ERR 0x40 /* error summary */
+#define TMD1_OWN 0x80 /* ownership (set: chip owns) */
+
+#define TMD1_OWN_CHIP TMD1_OWN
+#define TMD1_OWN_HOST 0
+
+/* tx_head misc field */
+#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */
+#define TMD3_RTRY 0x0400 /* failed after 16 retries */
+#define TMD3_LCAR 0x0800 /* carrier lost */
+#define TMD3_LCOL 0x1000 /* late collision */
+#define TMD3_UFLO 0x4000 /* underflow (late memory) */
+#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */
+
+/* rx_head flags */
+#define RMD1_ENP 0x01 /* end of packet */
+#define RMD1_STP 0x02 /* start of packet */
+#define RMD1_BUFF 0x04 /* buffer error */
+#define RMD1_CRC 0x08 /* CRC error */
+#define RMD1_OFLO 0x10 /* overflow */
+#define RMD1_FRAM 0x20 /* framing error */
+#define RMD1_ERR 0x40 /* error summary */
+#define RMD1_OWN 0x80 /* ownership (set: ship owns) */
+
+#define RMD1_OWN_CHIP RMD1_OWN
+#define RMD1_OWN_HOST 0
+
+/* register names */
+#define CSR0 0 /* mode/status */
+#define CSR1 1 /* init block addr (low) */
+#define CSR2 2 /* init block addr (high) */
+#define CSR3 3 /* misc */
+#define CSR8 8 /* address filter */
+#define CSR15 15 /* promiscuous mode */
+
+/* CSR0 */
+/* (R=readable, W=writeable, S=set on write, C=clear on write) */
+#define CSR0_INIT 0x0001 /* initialize (RS) */
+#define CSR0_STRT 0x0002 /* start (RS) */
+#define CSR0_STOP 0x0004 /* stop (RS) */
+#define CSR0_TDMD 0x0008 /* transmit demand (RS) */
+#define CSR0_TXON 0x0010 /* transmitter on (R) */
+#define CSR0_RXON 0x0020 /* receiver on (R) */
+#define CSR0_INEA 0x0040 /* interrupt enable (RW) */
+#define CSR0_INTR 0x0080 /* interrupt active (R) */
+#define CSR0_IDON 0x0100 /* initialization done (RC) */
+#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */
+#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */
+#define CSR0_MERR 0x0800 /* memory error (RC) */
+#define CSR0_MISS 0x1000 /* missed frame (RC) */
+#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */
+#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */
+#define CSR0_ERR 0x8000 /* error (RC) */
+
+/* CSR3 */
+#define CSR3_BCON 0x0001 /* byte control */
+#define CSR3_ACON 0 // fixme: 0x0002 /* ALE control */
+#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */
+
+
+
+/***************************** Prototypes *****************************/
+
+static int addr_accessible( volatile void *regp, int wordflag, int
+ writeflag );
+static unsigned long lance_probe1( struct device *dev, struct lance_addr
+ *init_rec );
+static int lance_open( struct device *dev );
+static void lance_init_ring( struct device *dev );
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev );
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
+static int lance_rx( struct device *dev );
+static int lance_close( struct device *dev );
+static struct net_device_stats *lance_get_stats( struct device *dev );
+static void set_multicast_list( struct device *dev );
+static int lance_set_mac_address( struct device *dev, void *addr );
+
+/************************* End of Prototypes **************************/
+
+/* Network traffic statistic (bytes) */
+
+int lance_stat = 0;
+
+static void update_lance_stat (int len) {
+ lance_stat += len;
+}
+
+/*
+ This function is used to access Baget/Lance memory to avoid
+ 8/32BIT access to VAC A24 space
+ ALL memcpy calls was chenged to this function to avoid dbe problems
+ Don't confuse with function name -- it stays from original code
+*/
+
+void *slow_memcpy( void *dst, const void *src, size_t len )
+
+{
+ unsigned long to = (unsigned long)dst;
+ unsigned long from = (unsigned long)src;
+ unsigned long to_end = to +len;
+
+ /* Unaligned flags */
+
+ int odd_from = from & 1;
+ int odd_to = to & 1;
+ int odd_to_end = to_end & 1;
+
+ /* Align for 16BIT-access first */
+
+ register unsigned short *from_a = (unsigned short*) (from & ~1);
+ register unsigned short *to_a = (unsigned short*) (to & ~1);
+ register unsigned short *to_end_a = (unsigned short*) (to_end & ~1);
+
+ /* Caching values -- not in loop invariant */
+
+ register unsigned short from_v;
+ register unsigned short to_v;
+
+ /* Invariant is: from_a and to_a are pointers before or exactly to
+ currently copying byte */
+
+ if (odd_to) {
+ /* First byte unaligned case */
+ from_v = *from_a;
+ to_v = *to_a;
+
+ to_v &= ~0xff;
+ to_v |= 0xff & (from_v >> (odd_from ? 0 : 8));
+ *to_a++ = to_v;
+
+ if (odd_from) from_a++;
+ }
+ if (odd_from == odd_to) {
+ /* Same parity */
+ while (to_a + 7 < to_end_a) {
+ unsigned long dummy1, dummy2;
+ unsigned long reg1, reg2, reg3, reg4;
+
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ "lh\t%2,0(%1)\n\t"
+ "nop\n\t"
+ "lh\t%3,2(%1)\n\t"
+ "sh\t%2,0(%0)\n\t"
+ "lh\t%4,4(%1)\n\t"
+ "sh\t%3,2(%0)\n\t"
+ "lh\t%5,6(%1)\n\t"
+ "sh\t%4,4(%0)\n\t"
+ "lh\t%2,8(%1)\n\t"
+ "sh\t%5,6(%0)\n\t"
+ "lh\t%3,10(%1)\n\t"
+ "sh\t%2,8(%0)\n\t"
+ "lh\t%4,12(%1)\n\t"
+ "sh\t%3,10(%0)\n\t"
+ "lh\t%5,14(%1)\n\t"
+ "sh\t%4,12(%0)\n\t"
+ "nop\n\t"
+ "sh\t%5,14(%0)\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=r" (dummy1), "=r" (dummy2),
+ "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+ :"0" (to_a), "1" (from_a)
+ :"memory");
+
+ to_a += 8;
+ from_a += 8;
+
+ }
+ while (to_a < to_end_a) {
+ *to_a++ = *from_a++;
+ }
+ } else {
+ /* Different parity */
+ from_v = *from_a;
+ while (to_a < to_end_a) {
+ unsigned short from_v_next;
+ from_v_next = *++from_a;
+ *to_a++ = ((from_v & 0xff)<<8) | ((from_v_next>>8) & 0xff);
+ from_v = from_v_next;
+ }
+
+ }
+ if (odd_to_end) {
+ /* Last byte unaligned case */
+ to_v = *to_a;
+ from_v = *from_a;
+
+ to_v &= ~0xff00;
+ if (odd_from == odd_to) {
+ to_v |= from_v & 0xff00;
+ } else {
+ to_v |= (from_v<<8) & 0xff00;
+ }
+
+ *to_a = to_v;
+ }
+
+ update_lance_stat( len );
+
+ return( dst );
+}
+
+
+__initfunc(int bagetlance_probe( struct device *dev ))
+
+{ int i;
+ static int found = 0;
+
+ if (found)
+ /* Assume there's only one board possible... That seems true, since
+ * the Riebl/PAM board's address cannot be changed. */
+ return( ENODEV );
+
+ for( i = 0; i < N_LANCE_ADDR; ++i ) {
+ if (lance_probe1( dev, &lance_addr_list[i] )) {
+ found = 1;
+ return( 0 );
+ }
+ }
+
+ return( ENODEV );
+}
+
+
+
+/* Derived from hwreg_present() in vme/config.c: */
+
+__initfunc(static int addr_accessible( volatile void *regp,
+ int wordflag,
+ int writeflag ))
+{
+ /* We have a fine function to do it */
+ extern int try_read(unsigned long, int);
+ return try_read((unsigned long)regp, sizeof(short)) != -1;
+}
+
+
+
+/* Original atari driver uses it */
+#define IRQ_TYPE_PRIO SA_INTERRUPT
+#define IRQ_SOURCE_TO_VECTOR(x) (x)
+
+__initfunc(static unsigned long lance_probe1( struct device *dev,
+ struct lance_addr *init_rec ))
+
+{ volatile unsigned short *memaddr =
+ (volatile unsigned short *)init_rec->memaddr;
+ volatile unsigned short *ioaddr =
+ (volatile unsigned short *)init_rec->ioaddr;
+ struct lance_private *lp;
+ struct lance_ioreg *IO;
+ int i;
+ static int did_version = 0;
+ unsigned short save1, save2;
+
+ PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
+ (long)memaddr, (long)ioaddr ));
+
+ /* Test whether memory readable and writable */
+ PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
+ if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
+
+ if ((unsigned long)memaddr >= KSEG2) {
+ extern int kseg2_alloc_io (unsigned long addr, unsigned long size);
+ if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) {
+ printk("bagetlance: unable map lance memory\n");
+ goto probe_fail;
+ }
+ }
+
+ /* Written values should come back... */
+ PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
+ save1 = *memaddr;
+ *memaddr = 0x0001;
+ if (*memaddr != 0x0001) goto probe_fail;
+ PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
+ *memaddr = 0x0000;
+ if (*memaddr != 0x0000) goto probe_fail;
+ *memaddr = save1;
+
+ /* First port should be readable and writable */
+ PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
+ if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
+
+ /* and written values should be readable */
+ PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
+ save2 = ioaddr[1];
+ ioaddr[1] = 0x0001;
+ if (ioaddr[1] != 0x0001) goto probe_fail;
+
+ /* The CSR0_INIT bit should not be readable */
+ PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
+ save1 = ioaddr[0];
+ ioaddr[1] = CSR0;
+ ioaddr[0] = CSR0_INIT | CSR0_STOP;
+ if (ioaddr[0] != CSR0_STOP) {
+ ioaddr[0] = save1;
+ ioaddr[1] = save2;
+ goto probe_fail;
+ }
+ PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
+ ioaddr[0] = CSR0_STOP;
+ if (ioaddr[0] != CSR0_STOP) {
+ ioaddr[0] = save1;
+ ioaddr[1] = save2;
+ goto probe_fail;
+ }
+
+ /* Now ok... */
+ PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
+ goto probe_ok;
+
+ probe_fail:
+ return( 0 );
+
+ probe_ok:
+ init_etherdev( dev, sizeof(struct lance_private) );
+ if (!dev->priv)
+ dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
+ lp = (struct lance_private *)dev->priv;
+ MEM = (struct lance_memory *)memaddr;
+ IO = lp->iobase = (struct lance_ioreg *)ioaddr;
+ dev->base_addr = (unsigned long)ioaddr; /* informational only */
+ lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
+
+ REGA( CSR0 ) = CSR0_STOP;
+
+ /* Now test for type: If the eeprom I/O port is readable, it is a
+ * PAM card */
+ if (addr_accessible( &(IO->eeprom), 0, 0 )) {
+ /* Switch back to Ram */
+ i = IO->mem;
+ lp->cardtype = PAM_CARD;
+ }
+#ifdef NORMAL_MEM_ACCESS
+ else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
+#else
+ else if (({
+ unsigned short *a = (unsigned short*)RIEBL_MAGIC_ADDR;
+ (((int)a[0]) << 16) + ((int)a[1]) == RIEBL_MAGIC;
+ })) {
+#endif
+ lp->cardtype = NEW_RIEBL;
+ }
+ else
+ lp->cardtype = OLD_RIEBL;
+
+ if (lp->cardtype == PAM_CARD ||
+ memaddr == (unsigned short *)0xffe00000) {
+ /* PAMs card and Riebl on ST use level 5 autovector */
+ request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO,
+ "PAM/Riebl-ST Ethernet", dev);
+ dev->irq = (unsigned short)BAGET_LANCE_IRQ;
+ }
+ else {
+ /* For VME-RieblCards, request a free VME int;
+ * (This must be unsigned long, since dev->irq is short and the
+ * IRQ_MACHSPEC bit would be cut off...)
+ */
+ unsigned long irq = BAGET_LANCE_IRQ;
+ if (!irq) {
+ printk( "Lance: request for VME interrupt failed\n" );
+ return( 0 );
+ }
+ request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
+ "Riebl-VME Ethernet", dev);
+ dev->irq = irq;
+ }
+
+ printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
+ dev->name, lance_names[lp->cardtype],
+ (unsigned long)ioaddr,
+ (unsigned long)memaddr,
+ dev->irq,
+ init_rec->slow_flag ? " (slow memcpy)" : "" );
+
+ /* Get the ethernet address */
+ switch( lp->cardtype ) {
+ case OLD_RIEBL:
+ /* No ethernet address! (Set some default address) */
+ slow_memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
+ break;
+ case NEW_RIEBL:
+ lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
+ break;
+ case PAM_CARD:
+ i = IO->eeprom;
+ for( i = 0; i < 6; ++i )
+ dev->dev_addr[i] =
+ ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
+ ((((unsigned short *)MEM)[i*2+1] & 0x0f));
+ i = IO->mem;
+ break;
+ }
+ for( i = 0; i < 6; ++i )
+ printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+ if (lp->cardtype == OLD_RIEBL) {
+ printk( "%s: Warning: This is a default ethernet address!\n",
+ dev->name );
+ printk( " Use \"ifconfig hw ether ...\" to set the address.\n" );
+ }
+
+ MEM->init.mode = 0x0000; /* Disable Rx and Tx. */
+
+ {
+ unsigned char hwaddr[6];
+ for( i = 0; i < 6; i++ )
+ hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+ slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
+ }
+
+ MEM->init.filter[0] = 0x00000000;
+ MEM->init.filter[1] = 0x00000000;
+ MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
+
+#ifdef NORMAL_MEM_ACCESS
+ MEM->init.rx_ring.adr_hi = LANCE_HI_BASE;
+ MEM->init.rx_ring.len = RX_RING_LEN_BITS;
+#else
+ MEM->init.rx_ring.len_adr_hi =
+ ((unsigned)RX_RING_LEN_BITS << 8) | LANCE_HI_BASE;
+#endif
+
+
+ MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
+
+#ifdef NORMAL_MEM_ACCESS
+ MEM->init.tx_ring.adr_hi = LANCE_HI_BASE;
+ MEM->init.tx_ring.len = TX_RING_LEN_BITS;
+#else
+ MEM->init.tx_ring.len_adr_hi =
+ ((unsigned)TX_RING_LEN_BITS<<8) | LANCE_HI_BASE;
+#endif
+
+ if (lp->cardtype == PAM_CARD)
+ IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
+ else
+ *RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
+
+ if (did_version++ == 0)
+ DPRINTK( 1, ( version ));
+
+ /* The LANCE-specific entries in the device structure. */
+ dev->open = &lance_open;
+ dev->hard_start_xmit = &lance_start_xmit;
+ dev->stop = &lance_close;
+ dev->get_stats = &lance_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->set_mac_address = &lance_set_mac_address;
+ dev->start = 0;
+
+ memset( &lp->stats, 0, sizeof(lp->stats) );
+
+ return( 1 );
+}
+
+
+static int lance_open( struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_ioreg *IO = lp->iobase;
+ int i;
+
+ DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
+
+ lance_init_ring(dev);
+ /* Re-initialize the LANCE, and start it when done. */
+
+ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+ REGA( CSR2 ) = 0;
+ REGA( CSR1 ) = 0;
+ REGA( CSR0 ) = CSR0_INIT;
+ /* From now on, AREG is kept to point to CSR0 */
+
+ i = 1000000;
+ while (--i > 0)
+ if (DREG & CSR0_IDON)
+ break;
+ if (i < 0 || (DREG & CSR0_ERR)) {
+ DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
+ dev->name, i, DREG ));
+ DREG = CSR0_STOP;
+ return( -EIO );
+ }
+ DREG = CSR0_IDON;
+ DREG = CSR0_STRT;
+ DREG = CSR0_INEA;
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
+ MOD_INC_USE_COUNT;
+
+ return( 0 );
+}
+
+
+/* Initialize the LANCE Rx and Tx rings. */
+
+static void lance_init_ring( struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int i;
+ unsigned offset;
+
+ lp->lock = 0;
+ lp->tx_full = 0;
+ lp->cur_rx = lp->cur_tx = 0;
+ lp->dirty_tx = 0;
+
+ offset = offsetof( struct lance_memory, packet_area );
+
+/* If the packet buffer at offset 'o' would conflict with the reserved area
+ * of RieblCards, advance it */
+#define CHECK_OFFSET(o) \
+ do { \
+ if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) { \
+ if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
+ : (o) < RIEBL_RSVD_END) \
+ (o) = RIEBL_RSVD_END; \
+ } \
+ } while(0)
+
+ for( i = 0; i < TX_RING_SIZE; i++ ) {
+ CHECK_OFFSET(offset);
+ MEM->tx_head[i].base = offset;
+#ifdef NORMAL_MEM_ACCESS
+ MEM->tx_head[i].flag = TMD1_OWN_HOST;
+ MEM->tx_head[i].base_hi = LANCE_HI_BASE;
+#else
+ MEM->tx_head[i].flag_base_hi =
+ (TMD1_OWN_HOST<<8) | LANCE_HI_BASE;
+#endif
+ MEM->tx_head[i].length = 0;
+ MEM->tx_head[i].misc = 0;
+ offset += PKT_BUF_SZ;
+ }
+
+ for( i = 0; i < RX_RING_SIZE; i++ ) {
+ CHECK_OFFSET(offset);
+ MEM->rx_head[i].base = offset;
+#ifdef NORMAL_MEM_ACCESS
+ MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+ MEM->rx_head[i].base_hi = LANCE_HI_BASE;
+#else
+ MEM->rx_head[i].flag_base_hi =
+ (TMD1_OWN_CHIP<<8) | LANCE_HI_BASE;
+#endif
+ MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
+ MEM->rx_head[i].msg_length = 0;
+ offset += PKT_BUF_SZ;
+ }
+}
+
+
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_ioreg *IO = lp->iobase;
+ int entry, len;
+ struct lance_tx_head *head;
+ unsigned long flags;
+
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 20)
+ return( 1 );
+ AREG = CSR0;
+ DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, DREG ));
+ DREG = CSR0_STOP;
+ /*
+ * Always set BSWP after a STOP as STOP puts it back into
+ * little endian mode.
+ */
+ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+ lp->stats.tx_errors++;
+#ifndef final_version
+ { int i;
+ DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
+ lp->dirty_tx, lp->cur_tx,
+ lp->tx_full ? " (full)" : "",
+ lp->cur_rx ));
+ for( i = 0 ; i < RX_RING_SIZE; i++ )
+ DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
+ i, MEM->rx_head[i].base,
+ -MEM->rx_head[i].buf_length,
+ MEM->rx_head[i].msg_length ));
+ for( i = 0 ; i < TX_RING_SIZE; i++ )
+ DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
+ i, MEM->tx_head[i].base,
+ -MEM->tx_head[i].length,
+ MEM->tx_head[i].misc ));
+ }
+#endif
+ lance_init_ring(dev);
+ REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
+
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+
+ return( 0 );
+ }
+
+ DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+ dev->name, DREG ));
+
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
+ DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
+ return 1;
+ }
+
+ if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
+ DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
+ /* don't clear dev->tbusy flag. */
+ return 1;
+ }
+
+ /* Fill in a Tx ring entry */
+ if (lance_debug >= 3) {
+ u_char *p;
+ int i;
+ printk( "%s: TX pkt type 0x%04x from ", dev->name,
+ ((u_short *)skb->data)[6]);
+ for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ printk(" to ");
+ for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ printk(" data at 0x%08x len %d\n", (int)skb->data,
+ (int)skb->len );
+ }
+
+ /* We're not prepared for the int until the last flags are set/reset. And
+ * the int may happen already after setting the OWN_CHIP... */
+ save_flags(flags);
+ cli();
+
+ /* Mask to ring buffer boundary. */
+ entry = lp->cur_tx & TX_RING_MOD_MASK;
+ head = &(MEM->tx_head[entry]);
+
+ /* Caution: the write order is important here, set the "ownership" bits
+ * last.
+ */
+
+ /* The old LANCE chips doesn't automatically pad buffers to min. size. */
+ len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+ /* PAM-Card has a bug: Can only send packets with even number of bytes! */
+ if (lp->cardtype == PAM_CARD && (len & 1))
+ ++len;
+
+ head->length = -len;
+ head->misc = 0;
+ lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+#ifdef NORMAL_MEM_ACCESS
+ head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+#else
+ SET_FLAG(head,(TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP));
+#endif
+ dev_kfree_skb( skb );
+ lp->cur_tx++;
+ lp->stats.tx_bytes += skb->len;
+ while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
+ lp->cur_tx -= TX_RING_SIZE;
+ lp->dirty_tx -= TX_RING_SIZE;
+ }
+
+ /* Trigger an immediate send poll. */
+ DREG = CSR0_INEA | CSR0_TDMD;
+ dev->trans_start = jiffies;
+
+ lp->lock = 0;
+#ifdef NORMAL_MEM_ACCESS
+ if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
+#else
+ if ((GET_FLAG(&MEM->tx_head[(entry+1) & TX_RING_MOD_MASK]) & TMD1_OWN) ==
+#endif
+ TMD1_OWN_HOST)
+ dev->tbusy = 0;
+ else
+ lp->tx_full = 1;
+ restore_flags(flags);
+
+ return 0;
+}
+
+/* The LANCE interrupt handler. */
+
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
+{
+ struct device *dev = dev_id;
+ struct lance_private *lp;
+ struct lance_ioreg *IO;
+ int csr0, boguscnt = 10;
+
+ if (dev == NULL) {
+ DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
+ return;
+ }
+
+ lp = (struct lance_private *)dev->priv;
+ IO = lp->iobase;
+ AREG = CSR0;
+
+ if (dev->interrupt) {
+ DPRINTK( 1, ( "Re-entering CAUSE=%08x STATUS=%08x\n",
+ read_32bit_cp0_register(CP0_CAUSE),
+ read_32bit_cp0_register(CP0_STATUS) ));
+ panic("lance: interrupt handler reentered !");
+ }
+
+ dev->interrupt = 1;
+
+ while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
+ --boguscnt >= 0) {
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
+ CSR0_TDMD | CSR0_INEA);
+
+ DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n",
+ dev->name, csr0, DREG ));
+
+ if (csr0 & CSR0_RINT) /* Rx interrupt */
+ lance_rx( dev );
+
+ if (csr0 & CSR0_TINT) { /* Tx-done interrupt */
+ int dirty_tx = lp->dirty_tx;
+
+ while( dirty_tx < lp->cur_tx) {
+ int entry = dirty_tx & TX_RING_MOD_MASK;
+#ifdef NORMAL_MEM_ACCESS
+ int status = MEM->tx_head[entry].flag;
+#else
+ int status = GET_FLAG(&MEM->tx_head[entry]);
+#endif
+ if (status & TMD1_OWN_CHIP)
+ break; /* It still hasn't been Txed */
+
+#ifdef NORMAL_MEM_ACCESS
+ MEM->tx_head[entry].flag = 0;
+#else
+ SET_FLAG(&MEM->tx_head[entry],0);
+#endif
+
+ if (status & TMD1_ERR) {
+ /* There was an major error, log it. */
+ int err_status = MEM->tx_head[entry].misc;
+ lp->stats.tx_errors++;
+ if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+ if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+ if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ if (err_status & TMD3_UFLO) {
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ lp->stats.tx_fifo_errors++;
+ /* Remove this verbosity later! */
+ DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
+ dev->name, csr0 ));
+ /* Restart the chip. */
+ DREG = CSR0_STRT;
+ }
+ } else {
+ if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
+ lp->stats.collisions++;
+ lp->stats.tx_packets++;
+ }
+ dirty_tx++;
+ }
+
+#ifndef final_version
+ if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+ DPRINTK( 0, ( "out-of-sync dirty pointer,"
+ " %d vs. %d, full=%d.\n",
+ dirty_tx, lp->cur_tx, lp->tx_full ));
+ dirty_tx += TX_RING_SIZE;
+ }
+#endif
+
+ if (lp->tx_full && dev->tbusy
+ && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ dev->tbusy = 0;
+ mark_bh( NET_BH );
+ }
+
+ lp->dirty_tx = dirty_tx;
+ }
+
+ /* Log misc errors. */
+ if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & CSR0_MERR) {
+ DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
+ "status %04x.\n", dev->name, csr0 ));
+ /* Restart the chip. */
+ DREG = CSR0_STRT;
+ }
+ }
+
+ /* Clear any other interrupt, and set interrupt enable. */
+ DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
+ CSR0_IDON | CSR0_INEA;
+
+ DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
+ dev->name, DREG ));
+ dev->interrupt = 0;
+ return;
+}
+
+
+static int lance_rx( struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ int entry = lp->cur_rx & RX_RING_MOD_MASK;
+ int i;
+
+#ifdef NORMAL_MEM_ACCESS
+ DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
+ MEM->rx_head[entry].flag ));
+#else
+ DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
+ GET_FLAG(&MEM->rx_head[entry]) ));
+#endif
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+#ifdef NORMAL_MEM_ACCESS
+ while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
+#else
+ while( (GET_FLAG(&MEM->rx_head[entry]) & RMD1_OWN) == RMD1_OWN_HOST ) {
+#endif
+ struct lance_rx_head *head = &(MEM->rx_head[entry]);
+#ifdef NORMAL_MEM_ACCESS
+ int status = head->flag;
+#else
+ int status = GET_FLAG(head);
+#endif
+
+ if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */
+ /* There is a tricky error noted by John Murphy,
+ <murf@perftech.com> to Russ Nelson: Even with full-sized
+ buffers it's possible for a jabber packet to use two
+ buffers, with only the last correctly noting the error. */
+ if (status & RMD1_ENP) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet.*/
+ if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
+ if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
+ if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
+ if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+#ifdef NORMAL_MEM_ACCESS
+ head->flag &= (RMD1_ENP|RMD1_STP);
+#else
+ SET_FLAG(head,GET_FLAG(head) & (RMD1_ENP|RMD1_STP));
+#endif
+ } else {
+ /* Malloc up new buffer, compatible with net-3. */
+ short pkt_len = head->msg_length & 0xfff;
+ struct sk_buff *skb;
+
+ if (pkt_len < 60) {
+ printk( "%s: Runt packet!\n", dev->name );
+ lp->stats.rx_errors++;
+ }
+ else {
+ skb = dev_alloc_skb( pkt_len+2 );
+ if (skb == NULL) {
+ DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
+ dev->name ));
+ for( i = 0; i < RX_RING_SIZE; i++ )
+#ifdef NORMAL_MEM_ACCESS
+ if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
+#else
+ if (GET_FLAG(&MEM->rx_head[(entry+i) & \
+ RX_RING_MOD_MASK]) &
+#endif
+ RMD1_OWN_CHIP)
+ break;
+
+ if (i > RX_RING_SIZE - 2) {
+ lp->stats.rx_dropped++;
+#ifdef NORMAL_MEM_ACCESS
+ head->flag |= RMD1_OWN_CHIP;
+#else
+ SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
+#endif
+ lp->cur_rx++;
+ }
+ break;
+ }
+
+ if (lance_debug >= 3) {
+ u_char *data = PKTBUF_ADDR(head), *p;
+ printk( "%s: RX pkt type 0x%04x from ", dev->name,
+ ((u_short *)data)[6]);
+ for( p = &data[6], i = 0; i < 6; i++ )
+ printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ printk(" to ");
+ for( p = data, i = 0; i < 6; i++ )
+ printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+ "len %d\n",
+ data[15], data[16], data[17], data[18],
+ data[19], data[20], data[21], data[22],
+ pkt_len );
+ }
+
+ skb->dev = dev;
+ skb_reserve( skb, 2 ); /* 16 byte align */
+ skb_put( skb, pkt_len ); /* Make room */
+ lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
+ }
+ }
+
+#ifdef NORMAL_MEM_ACCESS
+ head->flag |= RMD1_OWN_CHIP;
+#else
+ SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
+#endif
+ entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+ }
+ lp->cur_rx &= RX_RING_MOD_MASK;
+
+ /* From lance.c (Donald Becker): */
+ /* We should check that at least two ring entries are free. If not,
+ we should free one and mark stats->rx_dropped++. */
+
+ return 0;
+}
+
+
+static int lance_close( struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_ioreg *IO = lp->iobase;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ AREG = CSR0;
+
+ DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, DREG ));
+
+ /* We stop the LANCE here -- it occasionally polls
+ memory if we don't. */
+ DREG = CSR0_STOP;
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static struct net_device_stats *lance_get_stats( struct device *dev )
+
+{
+ struct lance_private *lp = (struct lance_private *)dev->priv;
+ return &lp->stats;
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+
+static void set_multicast_list( struct device *dev )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_ioreg *IO = lp->iobase;
+
+ if (!dev->start)
+ /* Only possible if board is already started */
+ return;
+
+ /* We take the simple way out and always enable promiscuous mode. */
+ DREG = CSR0_STOP; /* Temporarily stop the lance. */
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Log any net taps. */
+ DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+ REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+ } else {
+ short multicast_table[4];
+ int num_addrs = dev->mc_count;
+ int i;
+ /* We don't use the multicast table, but rely on upper-layer
+ * filtering. */
+ memset( multicast_table, (num_addrs == 0) ? 0 : -1,
+ sizeof(multicast_table) );
+ for( i = 0; i < 4; i++ )
+ REGA( CSR8+i ) = multicast_table[i];
+ REGA( CSR15 ) = 0; /* Unset promiscuous mode */
+ }
+
+ /*
+ * Always set BSWP after a STOP as STOP puts it back into
+ * little endian mode.
+ */
+ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+
+ /* Resume normal operation and reset AREG to CSR0 */
+ REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
+}
+
+
+/* This is needed for old RieblCards and possible for new RieblCards */
+
+static int lance_set_mac_address( struct device *dev, void *addr )
+
+{ struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct sockaddr *saddr = addr;
+ int i;
+
+ if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
+ return( -EOPNOTSUPP );
+
+ if (dev->start) {
+ /* Only possible while card isn't started */
+ DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
+ dev->name ));
+ return( -EIO );
+ }
+
+ slow_memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+ {
+ unsigned char hwaddr[6];
+ for( i = 0; i < 6; i++ )
+ hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+ slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
+ }
+
+ lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
+ /* set also the magic for future sessions */
+#ifdef NORMAL_MEM_ACCESS
+ *RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
+#else
+ {
+ unsigned long magic = RIEBL_MAGIC;
+ slow_memcpy(RIEBL_MAGIC_ADDR, &magic, sizeof(*RIEBL_MAGIC_ADDR));
+ }
+#endif
+ return( 0 );
+}
+
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct device bagetlance_dev =
+{
+ devicename, /* filled in by register_netdev() */
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, bagetlance_probe,
+};
+
+int init_module(void)
+
+{ int err;
+
+ if ((err = register_netdev( &bagetlance_dev ))) {
+ if (err == -EIO) {
+ printk( "No Vme Lance board found. Module not loaded.\n");
+ }
+ return( err );
+ }
+ return( 0 );
+}
+
+void cleanup_module(void)
+
+{
+ unregister_netdev( &bagetlance_dev );
+}
+
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
new file mode 100644
index 000000000..b5c5b4f42
--- /dev/null
+++ b/drivers/net/declance.c
@@ -0,0 +1,1265 @@
+/*
+ * Lance ethernet driver for the MIPS processor based
+ * DECstation family
+ *
+ *
+ * adopted from sunlance.c by Richard van den Berg
+ *
+ * additional sources:
+ * - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
+ * Revision 1.2
+ *
+ * History:
+ *
+ * v0.001: The kernel accepts the code and it shows the hardware address.
+ *
+ * v0.002: Removed most sparc stuff, left only some module and dma stuff.
+ *
+ * v0.003: Enhanced base address calculation from proposals by
+ * Harald Koerfgen and Thomas Riemer.
+ *
+ * v0.004: lance-regs is pointing at the right addresses, added prom
+ * check. First start of address mapping and DMA.
+ *
+ * v0.005: started to play around with LANCE-DMA. This driver will not work
+ * for non IOASIC lances. HK
+ *
+ * v0.006: added pointer arrays to lance_private and setup routine for them
+ * in dec_lance_init. HK
+ *
+ * v0.007: Big shit. The LANCE seems to use a different DMA mechanism to access
+ * the init block. This looks like one (short) word at a time, but the smallest
+ * amount the IOASIC can transfer is a (long) word. So we have a 2-2 padding here.
+ * Changed lance_init_block accordingly. The 16-16 padding for the buffers
+ * seems to be correct. HK
+ *
+ * v0.008 - mods to make PMAX_LANCE work. 01/09/1999 triemer
+ */
+
+#undef DEBUG_DRIVER
+
+static char *version =
+"declance.c: v0.008 by Linux Mips DECstation task force\n";
+
+static char *lancestr = "LANCE";
+
+/*
+ * card types
+ */
+#define ASIC_LANCE 1
+#define PMAD_LANCE 2
+#define PMAX_LANCE 3
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_ints.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/kn01.h>
+#include <asm/wbflush.h>
+#include <asm/addrspace.h>
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/utsname.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/etherdevice.h>
+
+#ifndef CONFIG_TC
+unsigned long system_base = 0;
+unsigned long dmaptr;
+#endif
+static int type;
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+#define LE_CSR0 0
+#define LE_CSR1 1
+#define LE_CSR2 2
+#define LE_CSR3 3
+
+#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
+
+#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
+#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
+#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
+#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
+#define LE_C0_MERR 0x0800 /* ME: Memory error */
+#define LE_C0_RINT 0x0400 /* Received interrupt */
+#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
+#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
+#define LE_C0_INTR 0x0080 /* Interrupt or error */
+#define LE_C0_INEA 0x0040 /* Interrupt enable */
+#define LE_C0_RXON 0x0020 /* Receiver on */
+#define LE_C0_TXON 0x0010 /* Transmitter on */
+#define LE_C0_TDMD 0x0008 /* Transmitter demand */
+#define LE_C0_STOP 0x0004 /* Stop the card */
+#define LE_C0_STRT 0x0002 /* Start the card */
+#define LE_C0_INIT 0x0001 /* Init the card */
+
+#define LE_C3_BSWP 0x4 /* SWAP */
+#define LE_C3_ACON 0x2 /* ALE Control */
+#define LE_C3_BCON 0x1 /* Byte control */
+
+/* Receive message descriptor 1 */
+#define LE_R1_OWN 0x80 /* Who owns the entry */
+#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
+#define LE_R1_FRA 0x20 /* FRA: Frame error */
+#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
+#define LE_R1_CRC 0x08 /* CRC error */
+#define LE_R1_BUF 0x04 /* BUF: Buffer error */
+#define LE_R1_SOP 0x02 /* Start of packet */
+#define LE_R1_EOP 0x01 /* End of packet */
+#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+#define LE_T1_OWN 0x80 /* Lance owns the packet */
+#define LE_T1_ERR 0x40 /* Error summary */
+#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
+#define LE_T1_EONE 0x08 /* Error: one retry needed */
+#define LE_T1_EDEF 0x04 /* Error: deferred */
+#define LE_T1_SOP 0x02 /* Start of packet */
+#define LE_T1_EOP 0x01 /* End of packet */
+#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
+
+#define LE_T3_BUF 0x8000 /* Buffer error */
+#define LE_T3_UFL 0x4000 /* Error underflow */
+#define LE_T3_LCOL 0x1000 /* Error late collision */
+#define LE_T3_CLOS 0x0800 /* Error carrier loss */
+#define LE_T3_RTY 0x0400 /* Error retry */
+#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
+
+/* Define: 2^4 Tx buffers and 2^4 Rx buffers */
+
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 4
+#define LANCE_LOG_RX_BUFFERS 4
+#endif
+
+#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
+
+#define PKT_BUF_SZ 1536
+#define RX_BUFF_SIZE PKT_BUF_SZ
+#define TX_BUFF_SIZE PKT_BUF_SZ
+
+#undef TEST_HITS
+#define DEBUG_DRIVER 1
+
+#define ZERO 0
+
+/* The DS2000/3000 have a linear 64 KB buffer.
+
+ * The PMAD-AA has 128 kb buffer on-board.
+ *
+ * The IOASIC LANCE devices use a shared memory region. This region as seen
+ * from the CPU is (max) 128 KB long and has to be on an 128 KB boundary.
+ * The LANCE sees this as a 64 KB long continuous memory region.
+ *
+ * The LANCE's DMA address is used as an index in this buffer and DMA takes
+ * place in bursts of eight 16-Bit words which are packed into four 32-Bit words
+ * by the IOASIC. This leads to a strange padding: 16 bytes of valid data followed
+ * by a 16 byte gap :-(.
+ */
+
+struct lance_rx_desc {
+ unsigned short rmd0; /* low address of packet */
+ short gap0;
+ unsigned char rmd1_hadr; /* high address of packet */
+ unsigned char rmd1_bits; /* descriptor bits */
+ short gap1;
+ short length; /* This length is 2s complement (negative)!
+ * Buffer length
+ */
+ short gap2;
+ unsigned short mblength; /* This is the actual number of bytes received */
+ short gap3;
+};
+
+struct lance_tx_desc {
+ unsigned short tmd0; /* low address of packet */
+ short gap0;
+ unsigned char tmd1_hadr; /* high address of packet */
+ unsigned char tmd1_bits; /* descriptor bits */
+ short gap1;
+ short length; /* Length is 2s complement (negative)! */
+ short gap2;
+ unsigned short misc;
+ short gap3;
+};
+
+
+/* First part of the LANCE initialization block, described in databook. */
+struct lance_init_block {
+ unsigned short mode; /* Pre-set mode (reg. 15) */
+ short gap0;
+
+ unsigned char phys_addr[12]; /* Physical ethernet address
+ * only 0, 1, 4, 5, 8, 9 are valid
+ * 2, 3, 6, 7, 10, 11 are gaps
+ */
+ unsigned short filter[8]; /* Multicast filter.
+ * only 0, 2, 4, 6 are valid
+ * 1, 3, 5, 7 are gaps
+ */
+
+ /* Receive and transmit ring base, along with extra bits. */
+ unsigned short rx_ptr; /* receive descriptor addr */
+ short gap1;
+ unsigned short rx_len; /* receive len and high addr */
+ short gap2;
+ unsigned short tx_ptr; /* transmit descriptor addr */
+ short gap3;
+ unsigned short tx_len; /* transmit len and high addr */
+ short gap4;
+ char gap5[16];
+
+ /* The buffer descriptors */
+ struct lance_rx_desc brx_ring[RX_RING_SIZE];
+ struct lance_tx_desc btx_ring[TX_RING_SIZE];
+};
+
+#define BUF_OFFSET_CPU sizeof(struct lance_init_block)
+#define BUF_OFFSET_LNC (sizeof(struct lance_init_block)>>1)
+
+#define libdesc_offset(rt, elem) \
+((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem])))))
+
+/*
+ * This works *only* for the ring descriptors
+ */
+#define LANCE_ADDR(x) (PHYSADDR(x) >> 1)
+
+struct lance_private {
+ char *name;
+ volatile struct lance_regs *ll;
+ volatile struct lance_init_block *init_block;
+ volatile unsigned long *dma_ptr_reg;
+
+ int rx_new, tx_new;
+ int rx_old, tx_old;
+
+ struct net_device_stats stats;
+
+ unsigned short busmaster_regval;
+
+ struct device *dev; /* Backpointer */
+ struct lance_private *next_module;
+
+ /* Pointers to the ring buffers as seen from the CPU */
+ char *rx_buf_ptr_cpu[RX_RING_SIZE];
+ char *tx_buf_ptr_cpu[TX_RING_SIZE];
+
+ /* Pointers to the ring buffers as seen from the LANCE */
+ char *rx_buf_ptr_lnc[RX_RING_SIZE];
+ char *tx_buf_ptr_lnc[TX_RING_SIZE];
+};
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+ lp->tx_old+TX_RING_MOD_MASK-lp->tx_new:\
+ lp->tx_old - lp->tx_new-1)
+
+/* The lance control ports are at an absolute address, machine and tc-slot
+ * dependant.
+ * DECstations do only 32-bit access and the LANCE uses 16 bit addresses,
+ * so we have to give the structure an extra member making rap pointing
+ * at the right address
+ */
+struct lance_regs {
+ volatile unsigned short rdp; /* register data port */
+ unsigned short pad;
+ volatile unsigned short rap; /* register address port */
+};
+
+int dec_lance_debug = 2;
+
+/*
+ #ifdef MODULE
+ static struct lance_private *root_lance_dev = NULL;
+ #endif
+ */
+
+static inline void writereg(volatile unsigned short *regptr, short value)
+{
+ *regptr = value;
+ wbflush();
+}
+
+/* Load the CSR registers */
+static void load_csrs(struct lance_private *lp)
+{
+ volatile struct lance_regs *ll = lp->ll;
+ int leptr;
+
+ /* The address space as seen from the LANCE
+ * begins at address 0. HK
+ */
+ leptr = 0;
+
+ writereg(&ll->rap, LE_CSR1);
+ writereg(&ll->rdp, (leptr & 0xFFFF));
+ writereg(&ll->rap, LE_CSR2);
+ writereg(&ll->rdp, leptr >> 16);
+ writereg(&ll->rap, LE_CSR3);
+ writereg(&ll->rdp, lp->busmaster_regval);
+
+ /* Point back to csr0 */
+ writereg(&ll->rap, LE_CSR0);
+}
+
+/*
+ * Our specialized copy routines
+ *
+ */
+void cp_to_buf(void *to, const void *from, __kernel_size_t len)
+{
+ unsigned short *tp, *fp, clen;
+ unsigned char *rtp, *rfp;
+
+ if (type == PMAX_LANCE) {
+ clen = len >> 1;
+ tp = (unsigned short *) to;
+ fp = (unsigned short *) from;
+
+ while (clen--) {
+ *tp++ = *fp++;
+ tp++;
+ }
+
+ clen = len & 1;
+ rtp = (unsigned char *) tp;
+ rfp = (unsigned char *) fp;
+ while (clen--) {
+ *rtp++ = *rfp++;
+ }
+ } else {
+ /*
+ * copy 16 Byte chunks
+ */
+ clen = len >> 4;
+ tp = (unsigned short *) to;
+ fp = (unsigned short *) from;
+ while (clen--) {
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ tp += 8;
+ }
+
+ /*
+ * do the rest, if any.
+ */
+ clen = len & 15;
+ rtp = (unsigned char *) tp;
+ rfp = (unsigned char *) fp;
+ while (clen--) {
+ *rtp++ = *rfp++;
+ }
+ }
+
+ wbflush();
+}
+
+void cp_from_buf(void *to, unsigned char *from, int len)
+{
+ unsigned short *tp, *fp, clen;
+ unsigned char *rtp, *rfp;
+
+ if (type == PMAX_LANCE) {
+ clen = len >> 1;
+ tp = (unsigned short *) to;
+ fp = (unsigned short *) from;
+ while (clen--) {
+ *tp++ = *fp++;
+ fp++;
+ }
+
+ clen = len & 1;
+
+ rtp = (unsigned char *) tp;
+ rfp = (unsigned char *) fp;
+
+ while (clen--) {
+ *rtp++ = *rfp++;
+ }
+ } else {
+
+ /*
+ * copy 16 Byte chunks
+ */
+ clen = len >> 4;
+ tp = (unsigned short *) to;
+ fp = (unsigned short *) from;
+ while (clen--) {
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ *tp++ = *fp++;
+ fp += 8;
+ }
+
+ /*
+ * do the rest, if any.
+ */
+ clen = len & 15;
+ rtp = (unsigned char *) tp;
+ rfp = (unsigned char *) fp;
+ while (clen--) {
+ *rtp++ = *rfp++;
+ }
+
+
+ }
+
+}
+
+/* Setup the Lance Rx and Tx rings */
+/* Sets dev->tbusy */
+static void lance_init_ring(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib;
+ int leptr;
+ int i;
+
+ ib = (struct lance_init_block *) (dev->mem_start);
+
+ /* Lock out other processes while setting up hardware */
+ dev->tbusy = 1;
+ lp->rx_new = lp->tx_new = 0;
+ lp->rx_old = lp->tx_old = 0;
+
+ ib->mode = 0;
+
+ /* Copy the ethernet address to the lance init block.
+ * XXX bit 0 of the physical address registers has to be zero
+ */
+ ib->phys_addr[0] = dev->dev_addr[0];
+ ib->phys_addr[1] = dev->dev_addr[1];
+ ib->phys_addr[4] = dev->dev_addr[2];
+ ib->phys_addr[5] = dev->dev_addr[3];
+ ib->phys_addr[8] = dev->dev_addr[4];
+ ib->phys_addr[9] = dev->dev_addr[5];
+ /* Setup the initialization block */
+
+ /* Setup rx descriptor pointer */
+ leptr = LANCE_ADDR(libdesc_offset(brx_ring, 0));
+ ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
+ ib->rx_ptr = leptr;
+ if (ZERO)
+ printk("RX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(brx_ring, 0));
+
+ /* Setup tx descriptor pointer */
+ leptr = LANCE_ADDR(libdesc_offset(btx_ring, 0));
+ ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
+ ib->tx_ptr = leptr;
+ if (ZERO)
+ printk("TX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(btx_ring, 0));
+
+ /* Clear the multicast filter */
+ ib->filter[0] = 0;
+ ib->filter[2] = 0;
+ ib->filter[4] = 0;
+ ib->filter[6] = 0;
+ if (ZERO)
+ printk("TX rings:\n");
+
+ /* Setup the Tx ring entries */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ leptr = (int) lp->tx_buf_ptr_lnc[i];
+ ib->btx_ring[i].tmd0 = leptr;
+ ib->btx_ring[i].tmd1_hadr = leptr >> 16;
+ ib->btx_ring[i].tmd1_bits = 0;
+ ib->btx_ring[i].length = 0xf000; /* The ones required by tmd2 */
+ ib->btx_ring[i].misc = 0;
+ if (i < 3 && ZERO)
+ printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->tx_buf_ptr_cpu[i]);
+ }
+
+ /* Setup the Rx ring entries */
+ if (ZERO)
+ printk("RX rings:\n");
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ leptr = (int) lp->rx_buf_ptr_lnc[i];
+ ib->brx_ring[i].rmd0 = leptr;
+ ib->brx_ring[i].rmd1_hadr = leptr >> 16;
+ ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
+ ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000;
+ ib->brx_ring[i].mblength = 0;
+ if (i < 3 && ZERO)
+ printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]);
+ }
+ wbflush();
+}
+
+static int init_restart_lance(struct lance_private *lp)
+{
+ volatile struct lance_regs *ll = lp->ll;
+ int i;
+
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_INIT);
+
+ /* Wait for the lance to complete initialization */
+ for (i = 0; (i < 100) && !(ll->rdp & LE_C0_IDON); i++) {
+ udelay(10);
+ }
+ if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
+ printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+ return -1;
+ }
+ if ((ll->rdp & LE_C0_ERR)) {
+ printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+ return -1;
+ }
+ writereg(&ll->rdp, LE_C0_IDON);
+ writereg(&ll->rdp, LE_C0_STRT);
+ writereg(&ll->rdp, LE_C0_INEA);
+
+ return 0;
+}
+
+static int lance_rx(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib;
+ volatile struct lance_rx_desc *rd = 0;
+ unsigned char bits;
+ int len = 0;
+ struct sk_buff *skb = 0;
+ ib = (struct lance_init_block *) (dev->mem_start);
+
+#ifdef TEST_HITS
+ int i;
+
+ printk("[");
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (i == lp->rx_new)
+ printk("%s",
+ ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+ else
+ printk("%s",
+ ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
+ }
+ printk("]");
+#endif
+
+ for (rd = &ib->brx_ring[lp->rx_new];
+ !((bits = rd->rmd1_bits) & LE_R1_OWN);
+ rd = &ib->brx_ring[lp->rx_new]) {
+
+ /* We got an incomplete frame? */
+ if ((bits & LE_R1_POK) != LE_R1_POK) {
+ lp->stats.rx_over_errors++;
+ lp->stats.rx_errors++;
+ } else if (bits & LE_R1_ERR) {
+ /* Count only the end frame as a rx error,
+ * not the beginning
+ */
+ if (bits & LE_R1_BUF)
+ lp->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC)
+ lp->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL)
+ lp->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA)
+ lp->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP)
+ lp->stats.rx_errors++;
+ } else {
+ len = (rd->mblength & 0xfff) - 4;
+ skb = dev_alloc_skb(len + 2);
+
+ if (skb == 0) {
+ printk("%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ rd->mblength = 0;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
+ return 0;
+ }
+ lp->stats.rx_bytes += len;
+
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align */
+ skb_put(skb, len); /* make room */
+ cp_from_buf(skb->data,
+ (char *) lp->rx_buf_ptr_cpu[lp->rx_new],
+ len);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ }
+
+ /* Return the packet to the pool */
+ rd->mblength = 0;
+ rd->length = -RX_BUFF_SIZE | 0xf000;
+ rd->rmd1_bits = LE_R1_OWN;
+ lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
+ }
+ return 0;
+}
+
+static int lance_tx(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib;
+ volatile struct lance_regs *ll = lp->ll;
+ volatile struct lance_tx_desc *td;
+ int i, j;
+ int status;
+ ib = (struct lance_init_block *) (dev->mem_start);
+ j = lp->tx_old;
+
+ for (i = j; i != lp->tx_new; i = j) {
+ td = &ib->btx_ring[i];
+ /* If we hit a packet not owned by us, stop */
+ if (td->tmd1_bits & LE_T1_OWN)
+ break;
+
+ if (td->tmd1_bits & LE_T1_ERR) {
+ status = td->misc;
+
+ lp->stats.tx_errors++;
+ if (status & LE_T3_RTY)
+ lp->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL)
+ lp->stats.tx_window_errors++;
+
+ if (status & LE_T3_CLOS) {
+ lp->stats.tx_carrier_errors++;
+ printk("%s: Carrier Lost", dev->name);
+ /* Stop the lance */
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+ lance_init_ring(dev);
+ load_csrs(lp);
+ init_restart_lance(lp);
+ return 0;
+ }
+ /* Buffer errors and underflows turn off the
+ * transmitter, restart the adapter.
+ */
+ if (status & (LE_T3_BUF | LE_T3_UFL)) {
+ lp->stats.tx_fifo_errors++;
+
+ printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+ dev->name);
+ /* Stop the lance */
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+ lance_init_ring(dev);
+ load_csrs(lp);
+ init_restart_lance(lp);
+ return 0;
+ }
+ } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+ /*
+ * So we don't count the packet more than once.
+ */
+ td->tmd1_bits &= ~(LE_T1_POK);
+
+ /* One collision before packet was sent. */
+ if (td->tmd1_bits & LE_T1_EONE)
+ lp->stats.collisions++;
+
+ /* More than one collision, be optimistic. */
+ if (td->tmd1_bits & LE_T1_EMORE)
+ lp->stats.collisions += 2;
+
+ lp->stats.tx_packets++;
+ }
+ j = (j + 1) & TX_RING_MOD_MASK;
+ }
+ lp->tx_old = j;
+ return 0;
+}
+
+static void lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *) dev_id;
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+ int csr0;
+
+ if (dev->interrupt)
+ printk("%s: again\n", dev->name);
+
+ dev->interrupt = 1;
+
+ writereg(&ll->rap, LE_CSR0);
+ csr0 = ll->rdp;
+
+ /* Acknowledge all the interrupt sources ASAP */
+ writereg(&ll->rdp, csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT));
+
+ if ((csr0 & LE_C0_ERR)) {
+ /* Clear the error condition */
+ writereg(&ll->rdp, LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
+ LE_C0_CERR | LE_C0_MERR);
+ }
+ if (csr0 & LE_C0_RINT)
+ lance_rx(dev);
+
+ if (csr0 & LE_C0_TINT)
+ lance_tx(dev);
+
+ if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ if (csr0 & LE_C0_BABL)
+ lp->stats.tx_errors++;
+
+ if (csr0 & LE_C0_MISS)
+ lp->stats.rx_errors++;
+
+ if (csr0 & LE_C0_MERR) {
+ volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR);
+
+ printk("%s: Memory error, status %04x", dev->name, csr0);
+
+ if (int_stat & LANCE_DMA_MEMRDERR) {
+ printk("%s: DMA error\n", dev->name);
+ int_stat |= LANCE_DMA_MEMRDERR;
+ /*
+ * re-enable LANCE DMA
+ */
+ *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
+ wbflush();
+ }
+ writereg(&ll->rdp, LE_C0_STOP);
+
+ lance_init_ring(dev);
+ load_csrs(lp);
+ init_restart_lance(lp);
+ dev->tbusy = 0;
+ }
+ writereg(&ll->rdp, LE_C0_INEA);
+ writereg(&ll->rdp, LE_C0_INEA);
+ dev->interrupt = 0;
+}
+
+struct device *last_dev = 0;
+
+static int lance_open(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+ int status = 0;
+
+ last_dev = dev;
+
+ /* Associate IRQ with lance_interrupt */
+ if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
+ printk("Lance: Can't get irq %d\n", dev->irq);
+ return -EAGAIN;
+ }
+ /* Stop the Lance */
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+
+ lance_init_ring(dev);
+ load_csrs(lp);
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ status = init_restart_lance(lp);
+
+ /*
+ * if (!status)
+ * MOD_INC_USE_COUNT;
+ */
+
+ return status;
+}
+
+static int lance_close(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ /* Stop the card */
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+
+ free_irq(dev->irq, (void *) dev);
+ /*
+ MOD_DEC_USE_COUNT;
+ */
+ return 0;
+}
+
+static inline int lance_reset(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+ int status;
+
+ /* Stop the lance */
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+
+ lance_init_ring(dev);
+ load_csrs(lp);
+ dev->trans_start = jiffies;
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ status = init_restart_lance(lp);
+#ifdef DEBUG_DRIVER
+ printk("Lance restart=%d\n", status);
+#endif
+ return status;
+}
+
+static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_regs *ll = lp->ll;
+ volatile struct lance_init_block *ib;
+ unsigned long flags;
+ int entry, skblen, len;
+ int status = 0;
+ static int outs;
+ ib = (struct lance_init_block *) (dev->mem_start);
+
+ /* Transmitter timeout, serious problems */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+
+ if (tickssofar < 100) {
+ status = -1;
+ } else {
+ printk("%s: transmit timed out, status %04x, reset\n",
+ dev->name, ll->rdp);
+ lance_reset(dev);
+ }
+ return status;
+ }
+ /* Block a timer-based transmit from overlapping. */
+ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+ printk("Transmitter access conflict.\n");
+ return -1;
+ }
+ skblen = skb->len;
+ save_and_cli(flags);
+ if (!TX_BUFFS_AVAIL) {
+ restore_flags(flags);
+ return -1;
+ }
+ len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+
+ lp->stats.tx_bytes += len;
+
+ entry = lp->tx_new & TX_RING_MOD_MASK;
+ ib->btx_ring[entry].length = (-len);
+ ib->btx_ring[entry].misc = 0;
+
+ cp_to_buf((char *) lp->tx_buf_ptr_cpu[entry], skb->data, skblen);
+
+ /* Clear the slack of the packet, do I need this? */
+ /* For a firewall its a good idea - AC */
+/*
+ if (len != skblen)
+ memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1);
+ */
+
+ /* Now, give the packet to the lance */
+ ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);
+ lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK;
+
+ outs++;
+ /* Kick the lance: transmit now */
+ writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD);
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+
+ if (TX_BUFFS_AVAIL)
+ dev->tbusy = 0;
+
+ restore_flags(flags);
+ return status;
+}
+
+static struct net_device_stats *lance_get_stats(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+
+ return &lp->stats;
+}
+
+static void lance_load_multicast(struct device *dev)
+{
+ volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start);
+ volatile u16 *mcast_table = (u16 *) & ib->filter;
+ struct dev_mc_list *dmi = dev->mc_list;
+ char *addrs;
+ int i, j, bit, byte;
+ u32 crc, poly = CRC_POLYNOMIAL_BE;
+
+ /* set all multicast bits */
+ if (dev->flags & IFF_ALLMULTI) {
+ ib->filter[0] = 0xffff;
+ ib->filter[2] = 0xffff;
+ ib->filter[4] = 0xffff;
+ ib->filter[6] = 0xffff;
+ return;
+ }
+ /* clear the multicast filter */
+ ib->filter[0] = 0;
+ ib->filter[2] = 0;
+ ib->filter[4] = 0;
+ ib->filter[6] = 0;
+
+ /* Add addresses */
+ for (i = 0; i < dev->mc_count; i++) {
+ addrs = dmi->dmi_addr;
+ dmi = dmi->next;
+
+ /* multicast address? */
+ if (!(*addrs & 1))
+ continue;
+
+ crc = 0xffffffff;
+ for (byte = 0; byte < 6; byte++)
+ for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+
+ if (test) {
+ crc = crc ^ poly;
+ }
+ }
+
+ crc = crc >> 26;
+ mcast_table[crc >> 3] |= 1 << (crc & 0xf);
+ }
+ return;
+}
+
+static void lance_set_multicast(struct device *dev)
+{
+ struct lance_private *lp = (struct lance_private *) dev->priv;
+ volatile struct lance_init_block *ib;
+ volatile struct lance_regs *ll = lp->ll;
+
+ ib = (struct lance_init_block *) (dev->mem_start);
+
+ while (dev->tbusy)
+ schedule();
+ set_bit(0, (void *) &dev->tbusy);
+ while (lp->tx_old != lp->tx_new)
+ schedule();
+
+ writereg(&ll->rap, LE_CSR0);
+ writereg(&ll->rdp, LE_C0_STOP);
+
+ lance_init_ring(dev);
+
+ if (dev->flags & IFF_PROMISC) {
+ ib->mode |= LE_MO_PROM;
+ } else {
+ ib->mode &= ~LE_MO_PROM;
+ lance_load_multicast(dev);
+ }
+ load_csrs(lp);
+ init_restart_lance(lp);
+ dev->tbusy = 0;
+}
+
+__initfunc(static int dec_lance_init(struct device *dev, const int type))
+{
+ static unsigned version_printed = 0;
+ struct lance_private *lp;
+ volatile struct lance_regs *ll;
+ int i;
+ unsigned long esar_base;
+ unsigned char *esar;
+
+#ifndef CONFIG_TC
+ system_base = KN01_LANCE_BASE;
+#else
+ int slot;
+#endif
+
+ if (dec_lance_debug && version_printed++ == 0)
+ printk(version);
+
+ if (dev == NULL) {
+ dev = init_etherdev(0, sizeof(struct lance_private) + 8);
+ } else {
+ dev->priv = kmalloc(sizeof(struct lance_private) + 8,
+ GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct lance_private) + 8);
+
+ }
+
+ /* Make certain the data structures used by the LANCE are aligned. */
+ dev->priv = (void *) (((unsigned long) dev->priv + 7) & ~7);
+ lp = (struct lance_private *) dev->priv;
+
+ switch (type) {
+#ifdef CONFIG_TC
+ case ASIC_LANCE:
+ dev->base_addr = system_base + LANCE;
+
+ /* buffer space for the on-board LANCE shared memory */
+ /*
+ * FIXME: ugly hack!
+ */
+ dev->mem_start = KSEG1ADDR(0x0020000);
+ dev->mem_end = dev->mem_start + 0x00020000;
+ dev->irq = ETHER;
+ esar_base = system_base + ESAR;
+
+ /*
+ * setup the pointer arrays, this sucks [tm] :-(
+ */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
+ + 2 * i * RX_BUFF_SIZE);
+ lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+ + i * RX_BUFF_SIZE);
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
+ + 2 * RX_RING_SIZE * RX_BUFF_SIZE
+ + 2 * i * TX_BUFF_SIZE);
+ lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+ + RX_RING_SIZE * RX_BUFF_SIZE
+ + i * TX_BUFF_SIZE);
+ }
+
+ /*
+ * setup and enable IOASIC LANCE DMA
+ */
+ lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P);
+ *(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3;
+ *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
+ wbflush();
+
+ break;
+ case PMAD_LANCE:
+ slot = search_tc_card("PMAD-AA");
+ claim_tc_card(slot);
+
+ dev->mem_start = get_tc_base_addr(slot);
+ dev->base_addr = dev->mem_start + 0x100000;
+ dev->irq = get_tc_irq_nr(slot);
+ esar_base = dev->mem_start + 0x1c0002;
+ break;
+#endif
+ case PMAX_LANCE:
+ dev->irq = ETHER;
+ dev->base_addr = KN01_LANCE_BASE;
+ dev->mem_start = KN01_LANCE_BASE + 0x01000000;
+ esar_base = KN01_RTC_BASE + 1;
+ /*
+ * setup the pointer arrays, this sucks [tm] :-(
+ */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ lp->rx_buf_ptr_cpu[i] =
+ (char *) (dev->mem_start + BUF_OFFSET_CPU
+ + 2 * i * RX_BUFF_SIZE);
+
+ lp->rx_buf_ptr_lnc[i] =
+ (char *) (BUF_OFFSET_LNC
+ + i * RX_BUFF_SIZE);
+
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ lp->tx_buf_ptr_cpu[i] =
+ (char *) (dev->mem_start + BUF_OFFSET_CPU
+ + 2 * RX_RING_SIZE * RX_BUFF_SIZE
+ + 2 * i * TX_BUFF_SIZE);
+ lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+ + RX_RING_SIZE * RX_BUFF_SIZE
+ + i * TX_BUFF_SIZE);
+
+ }
+ break;
+ default:
+ printk("declance_init called with unknown type\n");
+ return -ENODEV;
+ break;
+ }
+
+ ll = (struct lance_regs *) dev->base_addr;
+ esar = (unsigned char *) esar_base;
+
+ /* prom checks */
+ /* First, check for test pattern */
+ if (esar[0x60] != 0xff && esar[0x64] != 0x00 &&
+ esar[0x68] != 0x55 && esar[0x6c] != 0xaa) {
+ printk("Ethernet station address prom not found!\n");
+ return -ENODEV;
+ }
+ /* Check the prom contents */
+ for (i = 0; i < 8; i++) {
+ if (esar[i * 4] != esar[0x3c - i * 4] &&
+ esar[i * 4] != esar[0x40 + i * 4] &&
+ esar[0x3c - i * 4] != esar[0x40 + i * 4]) {
+ printk("Something is wrong with the ethernet "
+ "station address prom!\n");
+ return -ENODEV;
+ }
+ }
+
+ /* Copy the ethernet address to the device structure, later to the
+ * lance initialization block so the lance gets it every time it's
+ * (re)initialized.
+ */
+ switch (type) {
+ case ASIC_LANCE:
+ printk("%s: IOASIC onboard LANCE, addr = ", dev->name);
+ break;
+ case PMAD_LANCE:
+ printk("%s: PMAD-AA, addr = ", dev->name);
+ break;
+ case PMAX_LANCE:
+ printk("%s: PMAX onboard LANCE, addr = ", dev->name);
+ break;
+ }
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = esar[i * 4];
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':');
+ }
+
+ printk(" irq = %d\n", dev->irq);
+
+ /* Fill the dev fields */
+
+ dev->open = lance_open;
+ dev->stop = lance_close;
+ dev->hard_start_xmit = lance_start_xmit;
+ dev->get_stats = lance_get_stats;
+ dev->set_multicast_list = lance_set_multicast;
+ dev->dma = 0;
+
+ /* lp->ll is the location of the registers for lance card */
+ lp->ll = ll;
+
+ lp->name = lancestr;
+
+ /* busmaster_regval (CSR3) should be zero according to the PMAD-AA
+ * specification.
+ */
+ lp->busmaster_regval = 0;
+ lp->dev = dev;
+
+ ether_setup(dev);
+/*
+ #ifdef MODULE
+ dev->ifindex = dev_new_index();
+ lp->next_module = root_lance_dev;
+ root_lance_dev = lp;
+ #endif
+ */
+ return 0;
+}
+
+
+/* Find all the lance cards on the system and initialize them */
+__initfunc(int dec_lance_probe(struct device *dev))
+{
+ static int called = 0;
+
+#ifdef CONFIG_TC
+ int slot = -1;
+
+ if (TURBOCHANNEL) {
+ if (IOASIC && !called) {
+ called = 1;
+ type = ASIC_LANCE;
+ } else {
+ if ((slot = search_tc_card("PMAD-AA")) >= 0) {
+ type = PMAD_LANCE;
+ } else {
+ return -ENODEV;
+ }
+ }
+ } else {
+ if (!called) {
+ called = 1;
+ type = PMAX_LANCE;
+ } else {
+ return -ENODEV;
+ }
+ }
+#else
+ if (!called && !TURBOCHANNEL) {
+ called = 1;
+ type = PMAX_LANCE;
+ } else {
+ return -ENODEV;
+ }
+#endif
+
+ return dec_lance_init(dev, type);
+}
+
+/*
+ #ifdef MODULE
+
+ int
+ init_module(void)
+ {
+ root_lance_dev = NULL;
+ return dec_lance_probe(NULL);
+ }
+
+ void
+ cleanup_module(void)
+ {
+ struct lance_private *lp;
+
+ while (root_lance_dev) {
+ lp = root_lance_dev->next_module;
+
+ unregister_netdev(root_lance_dev->dev);
+ kfree(root_lance_dev->dev);
+ root_lance_dev = lp;
+ }
+ }
+
+ #endif -* MODULE */
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
new file mode 100644
index 000000000..b1da29c72
--- /dev/null
+++ b/drivers/scsi/dec_esp.c
@@ -0,0 +1,299 @@
+/*
+ * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations
+ *
+ * TURBOchannel changes by Harald Koerfgen
+ *
+ * based on jazz_esp.c:
+ * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * jazz_esp is based on David S. Miller's ESP driver and cyber_esp
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "NCR53C9x.h"
+#include "dec_esp.h"
+
+#include <asm/irq.h>
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+#include <asm/dma.h>
+
+#include <asm/pgtable.h>
+
+#include <asm/dec/tc.h>
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int dma_irq_p(struct NCR_ESP *esp);
+static int dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_advance_sg (Scsi_Cmnd *sp);
+static void dma_led_off(struct NCR_ESP *);
+static void dma_led_on(struct NCR_ESP *);
+
+
+volatile unsigned char cmd_buffer[16];
+ /* This is where all commands are put
+ * before they are trasfered to the ESP chip
+ * via PIO.
+ */
+
+/***************************************************************** Detection */
+int dec_esp_detect(Scsi_Host_Template *tpnt)
+{
+ struct NCR_ESP *esp;
+ struct ConfigDev *esp_dev;
+ int slot;
+
+ if ((slot = search_tc_card("PMAZ-AA")) >= 0) {
+ claim_tc_card(slot);
+ esp_dev = 0;
+ esp = esp_allocate(tpnt, (void *) esp_dev);
+
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
+
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
+ esp->dma_drain = 0;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ /* virtual DMA functions */
+ esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+ esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
+ esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
+ esp->dma_advance_sg = &dma_advance_sg;
+
+
+ /* SCSI chip speed */
+ esp->cfreq = get_tc_speed();
+
+ /*
+ * we don't give the address of DMA channel, but the number
+ * of DMA channel, so we can use the jazz DMA functions
+ *
+ */
+ esp->dregs = JAZZ_SCSI_DMA;
+
+ /* ESP register base */
+ esp->eregs = (struct ESP_regs *)get_tc_base_addr(slot);
+
+ /* Set the command buffer */
+ esp->esp_command = (volatile unsigned char *)cmd_buffer;
+
+ /* get virtual dma address for command buffer */
+ esp->esp_command_dvma = (volatile unsigned char *)cmd_buffer; /* vdma_alloc(PHYSADDR(cmd_buffer), sizeof (cmd_buffer)); */
+
+ esp->irq = get_tc_irq_nr(slot);
+ request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI",
+ NULL);
+
+ /*
+ * FIXME, look if the scsi id is availabe from NVRAM
+ */
+ esp->scsi_id = 7;
+
+ /* Check for differential SCSI-bus */
+ /* What is this stuff? */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
+ printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use);
+ esps_running = esps_in_use;
+ return esps_in_use;
+ }
+ return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+ return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+ /*
+ * maximum DMA size is 1MB
+ */
+ unsigned long sz = sp->SCp.this_residual;
+ if(sz > 0x100000)
+ sz = 0x100000;
+ return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+
+ ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n",
+ esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs)));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+/*
+ dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length);
+ vdma_disable ((int)esp->dregs);
+ vdma_set_mode ((int)esp->dregs, DMA_MODE_READ);
+ vdma_set_addr ((int)esp->dregs, vaddress);
+ vdma_set_count ((int)esp->dregs, length);
+ vdma_enable ((int)esp->dregs);
+*/
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+/*
+ dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length);
+ vdma_disable ((int)esp->dregs);
+ vdma_set_mode ((int)esp->dregs, DMA_MODE_WRITE);
+ vdma_set_addr ((int)esp->dregs, vaddress);
+ vdma_set_count ((int)esp->dregs, length);
+ vdma_enable ((int)esp->dregs);
+*/
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+ disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+ enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+ return (esp->eregs->esp_status & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+/*
+ int enable = vdma_get_enable((int)esp->dregs);
+
+ return (enable & R4030_CHNL_ENABLE);
+*/
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+ /*
+ * On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+ * so when (write) is true, it actually means READ!
+ */
+/*
+ if(write){
+ dma_init_read(esp, addr, count);
+ } else {
+ dma_init_write(esp, addr, count);
+ }
+*/
+}
+
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+/*
+ sp->SCp.have_data_in = vdma_alloc(PHYSADDR(sp->SCp.buffer), sp->SCp.this_residual);
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in);
+*/
+}
+
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+/*
+ int sz = sp->SCp.buffers_residual;
+ struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer;
+
+ while (sz >= 0) {
+ sg[sz].dvma_addr = vdma_alloc(PHYSADDR(sg[sz].addr), sg[sz].len);
+ sz--;
+ }
+ sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+*/
+}
+
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+/*
+ vdma_free(sp->SCp.have_data_in);
+*/
+}
+
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+/*
+ int sz = sp->use_sg - 1;
+ struct mmu_sglist *sg = (struct mmu_sglist *)sp->buffer;
+
+ while(sz >= 0) {
+ vdma_free(sg[sz].dvma_addr);
+ sz--;
+ }
+*/
+}
+
+static void dma_advance_sg (Scsi_Cmnd *sp)
+{
+/*
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+*/
+}
+
+#define JAZZ_HDC_LED 0xe000d100 /* FIXME, find correct address */
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+#if 0
+ *(unsigned char *)JAZZ_HDC_LED = 0;
+#endif
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+#if 0
+ *(unsigned char *)JAZZ_HDC_LED = 1;
+#endif
+}
diff --git a/drivers/scsi/dec_esp.h b/drivers/scsi/dec_esp.h
new file mode 100644
index 000000000..738b90356
--- /dev/null
+++ b/drivers/scsi/dec_esp.h
@@ -0,0 +1,42 @@
+/* dec_esp.h: Defines and structures for the JAZZ SCSI driver.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ *
+ * based on jazz_esp.h:
+ * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#ifndef DEC_ESP_H
+#define DEC_ESP_H
+
+#define EREGS_PAD(n) unchar n[3];
+
+#include "NCR53C9x.h"
+
+
+extern int dec_esp_detect(struct SHT *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_command(Scsi_Cmnd *);
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *, unsigned int);
+extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout);
+
+#define SCSI_DEC_ESP { \
+ proc_dir: &proc_scsi_esp, \
+ proc_info: &esp_proc_info, \
+ name: "PMAZ-AA", \
+ detect: dec_esp_detect, \
+ info: esp_info, \
+ command: esp_command, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING, }
+
+#endif /* JAZZ_DEC_H */
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
new file mode 100644
index 000000000..b1f4c4644
--- /dev/null
+++ b/drivers/tc/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS :=
+
+L_TARGET := tc.a
+L_OBJS := tc.o
+
+ifdef CONFIG_ZS
+L_OBJS += zs.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
new file mode 100644
index 000000000..36183ff9c
--- /dev/null
+++ b/drivers/tc/tc.c
@@ -0,0 +1,230 @@
+/* $Id: $
+ * tc-init: We assume the TURBOchannel to be up and running so
+ * just probe for Modules and fill in the global data structure
+ * tc_bus.
+ *
+ * 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.
+ *
+ * Copyright (c) Harald Koerfgen, 1998
+ *
+ */
+
+#include <linux/string.h>
+#include <asm/init.h>
+#include <asm/addrspace.h>
+#include <asm/errno.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tcinfo.h>
+#include <asm/dec/tcmodule.h>
+#include <asm/dec/interrupts.h>
+
+#include <asm/ptrace.h>
+#include <linux/kernel.h>
+
+#define TC_DEBUG
+
+slot_info tc_bus[MAX_SLOT];
+static int max_tcslot = 0;
+static tcinfo *info = (tcinfo *)0;
+
+unsigned long system_base = 0;
+
+extern void (*dbe_board_handler)(struct pt_regs *regs);
+extern unsigned long *(*rex_slot_address)(int);
+extern void *(*rex_gettcinfo)(void);
+
+/*
+ * Interface to the world. Read comment in include/asm-mips/tc.h.
+ */
+
+int search_tc_card(char *name)
+{
+ int slot;
+ slot_info *sip;
+
+ for (slot = 0; slot <= max_tcslot; slot++) {
+ sip = &tc_bus[slot];
+ if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
+ return slot;
+ }
+ }
+
+ return -ENODEV;
+}
+
+void claim_tc_card(int slot)
+{
+ if (tc_bus[slot].flags & IN_USE) {
+ printk("claim_tc_card: attempting to claim a card already in use\n");
+ return;
+ }
+ tc_bus[slot].flags &= ~FREE;
+ tc_bus[slot].flags |= IN_USE;
+}
+
+void release_tc_card(int slot)
+{
+ if (tc_bus[slot].flags & FREE) {
+ printk("release_tc_card: attempting to release a card already free\n");
+ return;
+ }
+ tc_bus[slot].flags &= ~IN_USE;
+ tc_bus[slot].flags |= FREE;
+}
+
+unsigned long get_tc_base_addr(int slot)
+{
+ return tc_bus[slot].base_addr;
+}
+
+unsigned long get_tc_irq_nr(int slot)
+{
+ return tc_bus[slot].interrupt;
+}
+
+unsigned long get_tc_speed(void)
+{
+ return 100000 * (10000 / (unsigned long)info->clk_period);
+}
+
+/*
+ * Probing for TURBOchannel modules
+ */
+__initfunc(static void my_dbe_handler(struct pt_regs *regs))
+{
+ regs->cp0_epc += 4;
+}
+
+__initfunc(static void tc_probe(unsigned long startaddr, unsigned long size, int max_slot))
+{
+ int i, slot;
+ long offset;
+ unsigned char *module;
+ void (*old_be_handler)(struct pt_regs *regs);
+
+ /* Install our exception handler temporarily */
+
+ old_be_handler = dbe_board_handler;
+ dbe_board_handler = my_dbe_handler;
+ for (slot = 0; slot <= max_slot; slot++) {
+ module = (char *)(startaddr + slot * size);
+ offset = -1;
+ if (module[OLDCARD + PATTERN0] == 0x55 && module[OLDCARD + PATTERN1] == 0x00
+ && module[OLDCARD + PATTERN2] == 0xaa && module[OLDCARD + PATTERN3] == 0xff)
+ offset = OLDCARD;
+ if (module[PATTERN0] == 0x55 && module[PATTERN1] == 0x00
+ && module[PATTERN2] == 0xaa && module[PATTERN3] == 0xff)
+ offset = 0;
+
+ if (offset != -1) {
+ tc_bus[slot].base_addr = (unsigned long)module;
+ for(i = 0; i < 8; i++) {
+ tc_bus[slot].firmware[i] = module[FIRM_VER + offset + 4 * i];
+ tc_bus[slot].vendor[i] = module[VENDOR + offset + 4 * i];
+ tc_bus[slot].name[i] = module[MODULE + offset + 4 * i];
+ }
+ tc_bus[slot].firmware[8] = 0;
+ tc_bus[slot].vendor[8] = 0;
+ tc_bus[slot].name[8] = 0;
+ /*
+ * Looks unneccesary, but we may change
+ * TC? in the future
+ */
+ switch (slot) {
+ case 0:
+ tc_bus[slot].interrupt = TC0;
+ case 1:
+ tc_bus[slot].interrupt = TC1;
+ case 2:
+ tc_bus[slot].interrupt = TC2;
+ /*
+ * Yuck! DS5000/200 onboard devices
+ */
+ case 5:
+ tc_bus[slot].interrupt = SCSI_INT;
+ case 6:
+ tc_bus[slot].interrupt = ETHER;
+ default:
+ tc_bus[slot].interrupt = -1;
+ }
+ }
+ }
+
+ dbe_board_handler = old_be_handler;
+}
+
+/*
+ * the main entry
+ */
+__initfunc(void tc_init(void))
+{
+ int tc_clock;
+ int i;
+ unsigned long slot0addr;
+ unsigned long slot_size;
+
+ if (!TURBOCHANNEL)
+ return;
+
+ for (i = 0; i < MAX_SLOT; i++) {
+ tc_bus[i].base_addr = 0;
+ tc_bus[i].name[0] = 0;
+ tc_bus[i].vendor[0] = 0;
+ tc_bus[i].firmware[0] = 0;
+ tc_bus[i].interrupt = -1;
+ tc_bus[i].flags = FREE;
+ }
+
+ info = (tcinfo *) rex_gettcinfo();
+ slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0));
+
+ switch (mips_machtype) {
+ case MACH_DS5000_200:
+ max_tcslot = 6;
+ break;
+ case MACH_DS5000_1XX:
+ case MACH_DS5000_2X0:
+ max_tcslot = 2;
+ break;
+ case MACH_DS5000_XX:
+ default:
+ max_tcslot = 1;
+ break;
+ }
+
+ tc_clock = 10000 / info->clk_period;
+
+ if (TURBOCHANNEL && info->slot_size && slot0addr) {
+ printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
+ tc_clock / 10, tc_clock % 10);
+ printk("(%sparity)\n", info->parity ? "" : "no ");
+
+ slot_size = info->slot_size << 20;
+
+ tc_probe(slot0addr, slot_size, max_tcslot);
+
+ /*
+ * All TURBOchannel DECstations have the onboard devices
+ * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+ * would be.
+ */
+ if(mips_machtype == MACH_DS5000_XX)
+ i = 2;
+ else
+ i = 1;
+
+ system_base = slot0addr + slot_size * (max_tcslot + i);
+
+#ifdef TC_DEBUG
+ for (i = 0; i <= max_tcslot; i++)
+ if (tc_bus[i].base_addr) {
+ printk(" slot %d: ", i);
+ printk("%s %s %s\n", tc_bus[i].vendor,
+ tc_bus[i].name, tc_bus[i].firmware);
+ }
+#endif
+ }
+
+}
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
new file mode 100644
index 000000000..3dbb837a2
--- /dev/null
+++ b/drivers/tc/zs.c
@@ -0,0 +1,2108 @@
+/*
+ * decserial.c: Serial port driver for IOASIC DECsatations.
+ *
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * DECstation changes
+ * Copyright (C) 1998 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Keyboard and mouse are not supported right now. If you want to change this,
+ * you might want to have a look at drivers/sbus/char/sunserial.c to see
+ * how this might be done. HK
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/wbflush.h>
+#include <asm/dec/interrupts.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/ioasic_addrs.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+#include "zs.h"
+
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL 2 /* Max number of ZS chips supported */
+#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
+
+#define RECOVERY_DELAY udelay(2)
+
+struct dec_zschannel zs_channels[NUM_CHANNELS];
+
+struct dec_serial zs_soft[NUM_CHANNELS];
+int zs_channels_found;
+struct dec_serial *zs_chain; /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
+
+#ifdef CONFIG_KGDB
+struct dec_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+ 9, 0x80, /* reset A side (CHRA) */
+ 13, 0, /* set baud rate divisor */
+ 12, 1,
+ 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
+ 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
+ 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+ 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
+ 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+#endif
+
+static unsigned char zs_init_regs[16] __initdata = {
+ 0, /* write 0 */
+ 0, /* write 1 */
+ 0xf0, /* write 2 */
+ (Rx8), /* write 3 */
+ (X16CLK | SB1), /* write 4 */
+ (Tx8), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (VIS), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ (BRSRC | BRENABL), /* write 14 */
+ 0 /* write 15 */
+};
+
+#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
+
+DECLARE_TASK_QUEUE(tq_zs_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
+ * Debugging.
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_PARANOIA_CHECK
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+static void change_speed(struct dec_serial *info);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct dec_serial *info,
+ dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for serial struct (%d, %d) in %s\n";
+ static const char *badinfo =
+ "Warning: null mac_serial for (%d, %d) in %s\n";
+
+ if (!info) {
+ printk(badinfo, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+ if (info->magic != SERIAL_MAGIC) {
+ printk(badmagic, MAJOR(device), MINOR(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 0, 0 };
+
+/*
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct dec_zschannel *channel,
+ unsigned char reg)
+{
+ unsigned char retval;
+
+ if (reg != 0) {
+ *channel->control = reg & 0xf;
+ wbflush(); RECOVERY_DELAY;
+ }
+ retval = *channel->control;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsreg(struct dec_zschannel *channel,
+ unsigned char reg, unsigned char value)
+{
+ if (reg != 0) {
+ *channel->control = reg & 0xf;
+ wbflush(); RECOVERY_DELAY;
+ }
+ *channel->control = value;
+ wbflush(); RECOVERY_DELAY;
+ return;
+}
+
+static inline unsigned char read_zsdata(struct dec_zschannel *channel)
+{
+ unsigned char retval;
+
+ retval = *channel->data;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsdata(struct dec_zschannel *channel,
+ unsigned char value)
+{
+ *channel->data = value;
+ wbflush(); RECOVERY_DELAY;
+ return;
+}
+
+static inline void load_zsregs(struct dec_zschannel *channel,
+ unsigned char *regs)
+{
+/* ZS_CLEARERR(channel);
+ ZS_CLEARFIFO(channel); */
+ /* Load 'em up */
+ write_zsreg(channel, R4, regs[R4]);
+ write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R2, regs[R2]);
+ write_zsreg(channel, R10, regs[R10]);
+ write_zsreg(channel, R11, regs[R11]);
+ write_zsreg(channel, R12, regs[R12]);
+ write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14]);
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R3, regs[R3]);
+ write_zsreg(channel, R5, regs[R5]);
+ return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct dec_serial *ss, int set)
+{
+ if (ss->zs_channel != ss->zs_chan_a) {
+ if (set)
+ ss->zs_chan_a->curregs[5] |= (RTS | DTR);
+ else
+ ss->zs_chan_a->curregs[5] &= ~(RTS | DTR);
+ write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]);
+ }
+ return;
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct dec_serial *ss)
+{
+ struct dec_zschannel *channel = ss->zs_channel;
+ int brg;
+
+ /* The baud rate is split up between two 8-bit registers in
+ * what is termed 'BRG time constant' format in my docs for
+ * the chip, it is a function of the clk rate the chip is
+ * receiving which happens to be constant.
+ */
+ brg = (read_zsreg(channel, 13) << 8);
+ brg |= read_zsreg(channel, 12);
+ return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct dec_zschannel *zsc)
+{
+ write_zsreg(zsc, 0, ERR_RES);
+ write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct dec_serial *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_zs_serial);
+ mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct dec_serial *info,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat, flag;
+
+ while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+ stat = read_zsreg(info->zs_channel, R1);
+ ch = read_zsdata(info->zs_channel);
+
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ if (ch == 0x03 || ch == '$')
+ breakpoint();
+ if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ return;
+ }
+#endif
+ if (!tty)
+ continue;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ static int flip_buf_ovf;
+ ++flip_buf_ovf;
+ continue;
+ }
+ tty->flip.count++;
+ {
+ static int flip_max_cnt;
+ if (flip_max_cnt < tty->flip.count)
+ flip_max_cnt = tty->flip.count;
+ }
+ if (stat & Rx_OVR) {
+ flag = TTY_OVERRUN;
+ } else if (stat & FRM_ERR) {
+ flag = TTY_FRAME;
+ } else if (stat & PAR_ERR) {
+ flag = TTY_PARITY;
+ } else
+ flag = 0;
+ if (flag)
+ /* reset the error indication */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ }
+ tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct dec_serial *info)
+{
+ if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+ return;
+ info->tx_active = 0;
+
+ if (info->x_char) {
+ /* Send next char */
+ write_zsdata(info->zs_channel, info->x_char);
+ info->x_char = 0;
+ info->tx_active = 1;
+ return;
+ }
+
+ if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+ write_zsreg(info->zs_channel, 0, RES_Tx_P);
+ return;
+ }
+ /* Send char */
+ write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ info->tx_active = 1;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static _INLINE_ void status_handle(struct dec_serial *info)
+{
+ unsigned char status;
+
+ /* Get status from Read Register 0 */
+ status = read_zsreg(info->zs_channel, 0);
+
+ /* FIXEM: Check for DCD transitions */
+ if (((status ^ info->read_reg_zero) & DCD) != 0
+ && info->tty && !C_CLOCAL(info->tty)) {
+ if (status & DCD) {
+ wake_up_interruptible(&info->open_wait);
+ } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+
+ /* Check for CTS transitions */
+ if (info->tty && C_CRTSCTS(info->tty)) {
+ /*
+ * For some reason, on the Power Macintosh,
+ * it seems that the CTS bit is 1 when CTS is
+ * *negated* and 0 when it is asserted.
+ * The DCD bit doesn't seem to be inverted
+ * like this.
+ */
+ if ((status & CTS) != 0) {
+ if (info->tx_stopped) {
+ info->tx_stopped = 0;
+ if (!info->tx_active)
+ transmit_chars(info);
+ }
+ } else {
+ info->tx_stopped = 1;
+ }
+ }
+
+ /* Clear status condition... */
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ info->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct dec_serial *info = (struct dec_serial *) dev_id;
+ unsigned char zs_intreg;
+ int shift;
+
+ /* NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+ if (info->zs_chan_a == info->zs_channel)
+ shift = 3; /* Channel A */
+ else
+ shift = 0; /* Channel B */
+
+ for (;;) {
+ zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+ if ((zs_intreg & CHAN_IRQMASK) == 0)
+ break;
+
+ if (zs_intreg & CHBRxIP) {
+ receive_chars(info, regs);
+ }
+ if (zs_intreg & CHBTxIP) {
+ transmit_chars(info);
+ }
+ if (zs_intreg & CHBEXT) {
+ status_handle(info);
+ }
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+#if 1
+ save_flags(flags); cli();
+ if (info->zs_channel->curregs[5] & TxENAB) {
+ info->zs_channel->curregs[5] &= ~TxENAB;
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ }
+ restore_flags(flags);
+#endif
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_start"))
+ return;
+
+ save_flags(flags); cli();
+#if 1
+ if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
+ info->zs_channel->curregs[5] |= TxENAB;
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ }
+#else
+ if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
+ transmit_chars(info);
+ }
+#endif
+ restore_flags(flags);
+}
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_zs_serial);
+}
+
+static void do_softint(void *private_)
+{
+ struct dec_serial *info = (struct dec_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+static void rs_timer(void)
+{
+}
+
+static int startup(struct dec_serial * info)
+{
+ unsigned long flags;
+
+ if (info->flags & ZILOG_INITIALIZED)
+ return 0;
+
+ if (!info->xmit_buf) {
+ info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+ if (!info->xmit_buf)
+ return -ENOMEM;
+ }
+
+ save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
+ info->zs_channel->curregs[5] |= (TxENAB | Tx8);
+ info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
+ info->zs_channel->curregs[9] |= (VIS | MIE);
+ write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
+ write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);
+ write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * Set the speed of the serial port
+ */
+ change_speed(info);
+
+ /* Save the current value of RR0 */
+ info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+ info->flags |= ZILOG_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct dec_serial * info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ZILOG_INITIALIZED))
+ return;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d (irq %d)....", info->line,
+ info->irq);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = 0;
+ }
+
+ info->zs_channel->curregs[1] = 0;
+ write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */
+
+ info->zs_channel->curregs[3] &= ~RxENABLE;
+ write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+
+ info->zs_channel->curregs[5] &= ~TxENAB;
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ if (!info->tty || C_HUPCL(info->tty)) {
+ info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ }
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ZILOG_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct dec_serial *info)
+{
+ unsigned short port;
+ unsigned cflag;
+ int i;
+ int brg;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+ if (!(port = info->port))
+ return;
+ i = cflag & CBAUD;
+
+ save_flags(flags); cli();
+ info->zs_baud = baud_table[i];
+ info->clk_divisor = 16;
+
+ switch (info->zs_baud) {
+ default:
+ info->zs_channel->curregs[4] = X16CLK;
+ brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+ info->zs_channel->curregs[12] = (brg & 255);
+ info->zs_channel->curregs[13] = ((brg >> 8) & 255);
+ }
+
+ /* byte size and parity */
+ info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
+ info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->zs_channel->curregs[3] |= Rx5;
+ info->zs_channel->curregs[5] |= Tx5;
+ break;
+ case CS6:
+ info->zs_channel->curregs[3] |= Rx6;
+ info->zs_channel->curregs[5] |= Tx6;
+ break;
+ case CS7:
+ info->zs_channel->curregs[3] |= Rx7;
+ info->zs_channel->curregs[5] |= Tx7;
+ break;
+ case CS8:
+ default: /* defaults to 8 bits */
+ info->zs_channel->curregs[3] |= Rx8;
+ info->zs_channel->curregs[5] |= Tx8;
+ break;
+ }
+
+ info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+ if (cflag & CSTOPB) {
+ info->zs_channel->curregs[4] |= SB2;
+ } else {
+ info->zs_channel->curregs[4] |= SB1;
+ }
+ if (cflag & PARENB) {
+ info->zs_channel->curregs[4] |= PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->zs_channel->curregs[4] |= PAR_EVEN;
+ }
+
+ if (!(cflag & CLOCAL)) {
+ if (!(info->zs_channel->curregs[15] & DCDIE))
+ info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+ info->zs_channel->curregs[15] |= DCDIE;
+ } else
+ info->zs_channel->curregs[15] &= ~DCDIE;
+ if (cflag & CRTSCTS) {
+ info->zs_channel->curregs[15] |= CTSIE;
+ if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+ info->tx_stopped = 1;
+ } else {
+ info->zs_channel->curregs[15] &= ~CTSIE;
+ info->tx_stopped = 0;
+ }
+
+ /* Load up the new values */
+ load_zsregs(info->zs_channel, info->zs_channel->curregs);
+
+ restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ transmit_chars(info);
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ copy_from_user(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+
+ if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+ && !info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ int ret;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+ return 0;
+ return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+ return;
+ cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ sti();
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ save_flags(flags); cli();
+ info->x_char = STOP_CHAR(tty);
+ if (!info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ }
+
+ if (C_CRTSCTS(tty)) {
+ /*
+ * Here we want to turn off the RTS line. On Macintoshes,
+ * we only get the DTR line, which goes to both DTR and
+ * RTS on the modem. RTS doesn't go out to the serial
+ * port socket. So you should make sure your modem is
+ * set to ignore DTR if you're using CRTSCTS.
+ */
+ save_flags(flags); cli();
+ info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ restore_flags(flags);
+ }
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ save_flags(flags); cli();
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ info->x_char = START_CHAR(tty);
+ if (!info->tx_active)
+ transmit_chars(info);
+ }
+ restore_flags(flags);
+ }
+
+ if (C_CRTSCTS(tty)) {
+ /* Assert RTS and DTR lines */
+ save_flags(flags); cli();
+ info->zs_chan_a->curregs[5] |= DTR | RTS;
+ write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ restore_flags(flags);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct dec_serial * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->port;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct dec_serial * info,
+ struct serial_struct * new_info)
+{
+ struct serial_struct new_serial;
+ struct dec_serial old_info;
+ int retval = 0;
+
+ if (!new_info)
+ return -EFAULT;
+ copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ old_info = *info;
+
+ if (!suser()) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.type != info->type) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ZILOG_USR_MASK) !=
+ (info->flags & ~ZILOG_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+ (new_serial.flags & ZILOG_USR_MASK));
+ info->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud_base = new_serial.baud_base;
+ info->flags = ((info->flags & ~ZILOG_FLAGS) |
+ (new_serial.flags & ZILOG_FLAGS));
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+ retval = startup(info);
+ return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct dec_serial * info, unsigned int *value)
+{
+ unsigned char status;
+
+ cli();
+ status = read_zsreg(info->zs_channel, 0);
+ sti();
+ put_user(status,value);
+ return 0;
+}
+
+static int get_modem_info(struct dec_serial *info, unsigned int *value)
+{
+ unsigned char control, status;
+ unsigned int result;
+
+ cli();
+ control = info->zs_chan_a->curregs[5];
+ status = read_zsreg(info->zs_channel, 0);
+ sti();
+ result = ((control & RTS) ? TIOCM_RTS: 0)
+ | ((control & DTR) ? TIOCM_DTR: 0)
+ | ((status & DCD) ? TIOCM_CAR: 0)
+ | ((status & CTS) ? 0: TIOCM_CTS);
+ put_user(result,value);
+ return 0;
+}
+
+static int set_modem_info(struct dec_serial *info, unsigned int cmd,
+ unsigned int *value)
+{
+ int error;
+ unsigned int arg, bits;
+
+ error = verify_area(VERIFY_READ, value, sizeof(int));
+ if (error)
+ return error;
+ get_user(arg, value);
+ bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
+ cli();
+ switch (cmd) {
+ case TIOCMBIS:
+ info->zs_chan_a->curregs[5] |= bits;
+ break;
+ case TIOCMBIC:
+ info->zs_chan_a->curregs[5] &= ~bits;
+ break;
+ case TIOCMSET:
+ info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
+ break;
+ default:
+ sti();
+ return -EINVAL;
+ }
+ write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+ sti();
+ return 0;
+}
+
+/*
+ * rs_break - turn transmit break condition on/off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+ struct dec_serial *info = (struct dec_serial *) tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_break"))
+ return;
+ if (!info->port)
+ return;
+
+ save_flags(flags); cli();
+ if (break_state == -1)
+ info->zs_channel->curregs[5] |= SND_BRK;
+ else
+ info->zs_channel->curregs[5] &= ~SND_BRK;
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ restore_flags(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int error;
+ struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel)
+ return -ENODEV;
+#endif
+ if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TIOCMGET:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
+ case TIOCGSERIAL:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct dec_serial));
+ if (error)
+ return error;
+ copy_from_user((struct dec_serial *) arg,
+ info, sizeof(struct dec_serial));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+ int was_stopped;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+ was_stopped = info->tx_stopped;
+
+ change_speed(info);
+
+ if (was_stopped && !info->tx_stopped)
+ rs_start(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed.
+ * Wait for the last remaining data to be sent.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+ return;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ZILOG_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receiver and receive interrupts.
+ */
+ info->zs_channel->curregs[3] &= ~RxENABLE;
+ write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+ info->zs_channel->curregs[1] = 0; /* disable any rx ints */
+ write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
+ ZS_CLEARFIFO(info->zs_channel);
+ if (info->flags & ZILOG_INITIALIZED) {
+ /*
+ * Before we drop DTR, make sure the SCC transmitter
+ * has completely drained.
+ */
+ rs_wait_until_sent(tty, info->timeout);
+ }
+
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+ ZILOG_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct dec_serial *info = (struct dec_serial *) tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+
+ if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+ return;
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ */
+ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout)
+ char_time = MIN(char_time, timeout);
+ while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->counter = 0; /* make us low-priority */
+ schedule_timeout(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && ((orig_jiffies + timeout) < jiffies))
+ break;
+ }
+ current->state = TASK_RUNNING;
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+ struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+ return;
+
+ rs_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct dec_serial *info)
+{
+ struct wait_queue wait = { current, NULL };
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ZILOG_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ZILOG_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ZILOG_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (info->flags & ZILOG_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ZILOG_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ZILOG_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ cli();
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ sti();
+ info->blocked_open++;
+ while (1) {
+ cli();
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD))
+ zs_rtsdtr(info, 1);
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ZILOG_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+ !(info->flags & ZILOG_CLOSING) &&
+ (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ZILOG_NORMAL_ACTIVE;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct dec_serial *info;
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (line >= zs_channels_found))
+ return -ENODEV;
+ info = zs_soft + line;
+
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel)
+ return -ENODEV;
+#endif
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
+ return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->count);
+#endif
+
+ info->count++;
+ tty->driver_data = info;
+ info->tty = tty;
+
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ZILOG_CLOSING)) {
+ if (info->flags & ZILOG_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ZILOG_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval)
+ return retval;
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+ }
+#ifdef CONFIG_SERIAL_CONSOLE
+ if (sercons.cflag && sercons.index == line) {
+ tty->termios->c_cflag = sercons.cflag;
+ sercons.cflag = 0;
+ change_speed(info);
+ }
+#endif
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d successful...", info->line);
+#endif
+/* tty->low_latency = 1; */
+ return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+__initfunc(static void show_serial_version(void))
+{
+ printk("DECstation Z8530 serial driver version 0.03\n");
+}
+
+/* Initialize Z8530s zs_channels
+ */
+
+__initfunc(static void probe_sccs(void))
+{
+ struct dec_serial **pp;
+ int i, n, n_chips = 0, n_channels, chip, channel;
+ unsigned long flags;
+
+ /*
+ * did we get here by accident?
+ */
+ if(!IOASIC) {
+ printk("Not on JUNKIO machine, skipping probe_sccs\n");
+ return;
+ }
+
+ /*
+ * When serial console is activated, tc_init has not been called yet
+ * and system_base is undefined. Unfortunately we have to hardcode
+ * system_base for this case :-(. HK
+ */
+ switch(mips_machtype) {
+ case MACH_DS5000_2X0:
+ system_base = 0xbf800000;
+ n_chips = 2;
+ break;
+ case MACH_DS5000_1XX:
+ system_base = 0xbc000000;
+ n_chips = 2;
+ break;
+ case MACH_DS5000_XX:
+ system_base = 0xbc000000;
+ n_chips = 1;
+ break;
+ }
+
+ pp = &zs_chain;
+
+ n_channels = 0;
+
+ for (chip = 0; chip < n_chips; chip++) {
+ for (channel = 0; channel <= 1; channel++) {
+ /*
+ * The sccs reside on the high byte of the 16 bit IOBUS
+ */
+ zs_channels[n_channels].control = (volatile unsigned char *)
+ system_base + (0 == chip ? SCC0 : SCC1) + (0 == channel ? 1 : 9);
+ zs_channels[n_channels].data = zs_channels[n_channels].control + 4;
+ zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
+ zs_soft[n_channels].irq = SERIAL;
+
+ if (0 == channel)
+ zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1];
+ else
+ zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels];
+
+ *pp = &zs_soft[n_channels];
+ pp = &zs_soft[n_channels].zs_next;
+ n_channels++;
+ }
+ }
+
+ *pp = 0;
+ zs_channels_found = n_channels;
+
+ for (n = 0; n < zs_channels_found; n++) {
+ for (i = 0; i < 16; i++) {
+ zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
+ }
+ }
+
+/* save_and_cli(flags);
+ for (n = 0; n < zs_channels_found; n++) {
+ if (((int)zs_channels[n].control & 0xf) == 1) {
+ write_zsreg(zs_soft[channel].zs_chan_a, R9, FHWRES);
+ udelay(10000);
+ write_zsreg(zs_soft[channel].zs_chan_a, R9, 0);
+ }
+ load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
+ }
+ restore_flags(flags); */
+}
+
+/* zs_init inits the driver */
+__initfunc(int zs_init(void))
+{
+ int channel, i;
+ unsigned long flags;
+ struct dec_serial *info;
+
+ if(!IOASIC)
+ return -ENODEV;
+
+ /* Setup base handler, and timer table. */
+ init_bh(SERIAL_BH, do_serial_bh);
+ timer_table[RS_TIMER].fn = rs_timer;
+ timer_table[RS_TIMER].expires = 0;
+
+ /* Find out how many Z8530 SCCs we have */
+ if (zs_chain == 0)
+ probe_sccs();
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+ /* Not all of this is exactly right for us. */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = zs_channels_found;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+ serial_driver.break_ctl = rs_break;
+ serial_driver.wait_until_sent = rs_wait_until_sent;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ save_flags(flags); cli();
+
+ for (channel = 0; channel < zs_channels_found; ++channel) {
+#ifdef CONFIG_KGDB
+ if (zs_soft[channel].kgdb_channel) {
+ continue;
+ }
+#endif
+ zs_soft[channel].clk_divisor = 16;
+ zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+
+ if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ,
+ "SCC", &zs_soft[channel]))
+ printk(KERN_ERR "decserial: can't get irq %d\n",
+ SERIAL);
+
+ /* If console serial line, then enable interrupts. */
+/* if (zs_soft[channel].is_cons) {
+ write_zsreg(zs_soft[channel].zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+ write_zsreg(zs_soft[channel].zs_channel, R9,
+ (VIS | MIE));
+ }
+*/
+ }
+
+ for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+ {
+#ifdef CONFIG_KGDB
+ if (info->kgdb_channel) {
+ continue;
+ }
+#endif
+ info->magic = SERIAL_MAGIC;
+ info->port = (int) info->zs_channel->control;
+ info->line = i;
+ info->tty = 0;
+ info->custom_divisor = 16;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios =callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->open_wait = 0;
+ info->close_wait = 0;
+ printk("tty%02d at 0x%08x (irq = %d)", info->line,
+ info->port, info->irq);
+ printk(" is a Z85C30 SCC\n");
+ }
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* PowerMac: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+ return -1;
+}
+
+void unregister_serial(int line)
+{
+ return;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+
+/* This is for console output */
+static void
+zs_console_putchar(struct dec_serial *info, char ch)
+{
+ int loops = 10000;
+ unsigned long flags;
+
+ if(!info->zs_channel)
+ return;
+
+ save_flags(flags); cli();
+
+ while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops)
+ RECOVERY_DELAY;
+ *(info->zs_channel->data) = ch;
+ wbflush(); RECOVERY_DELAY;
+
+ restore_flags(flags);
+}
+
+static void serial_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+ struct dec_serial *info;
+ int i;
+ unsigned char nine;
+
+ info = zs_soft + co->index;
+
+#if 0
+ /*
+ * disable master interrupt if necessary
+ */
+ nine = info->zs_channel->curregs[9];
+ if(nine & MIE)
+ write_zsreg(info->zs_channel, R9, nine & ~MIE);
+#endif
+ /*
+ * do it
+ */
+ for (i = 0; i < count; i++, s++) {
+ if(*s == '\n')
+ zs_console_putchar(info, '\r');
+ zs_console_putchar(info, *s);
+ }
+ /*
+ * restore master interrupt enable
+ */
+#if 0
+ write_zsreg(info->zs_channel, R9, nine);
+#endif
+}
+
+/*
+ * Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+ return 0;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ * Setup initial baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first rs_open()
+ * - initialize the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+ struct dec_serial *info;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
+ unsigned long flags;
+
+ if(!IOASIC)
+ return -ENODEV;
+
+ info = zs_soft + co->index;
+
+ if (zs_chain == 0)
+ probe_sccs();
+
+ info->is_cons = 1;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while(*s >= '0' && *s <= '9')
+ s++;
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
+ }
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch(baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ case 9600:
+ default:
+ cflag |= B9600;
+ break;
+ }
+ switch(bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
+ }
+ switch(parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
+ }
+ co->cflag = cflag;
+#if 1
+ save_and_cli(flags);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing
+ */
+ info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
+ info->zs_channel->curregs[5] |= (TxENAB | Tx8);
+ info->zs_channel->curregs[9] |= (VIS);
+ write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+ write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+ write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Set the speed of the serial port
+ */
+ change_speed(info);
+
+ /* Save the current value of RR0 */
+ info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+ zs_soft[co->index].clk_divisor = 16;
+ zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
+
+ restore_flags(flags);
+#endif
+ return 0;
+}
+
+static struct console sercons = {
+ "ttyS",
+ serial_console_write,
+ NULL,
+ serial_console_device,
+ serial_console_wait_key,
+ NULL,
+ serial_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc (long zs_serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&sercons);
+ return kmem_start;
+}
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
+#ifdef CONFIG_KGDB
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct dec_zschannel *chan = zs_kgdbchan;
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ RECOVERY_DELAY;
+ write_zsdata(chan, kgdb_char);
+}
+char getDebugChar(void)
+{
+ struct dec_zschannel *chan = zs_kgdbchan;
+ while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ eieio(); /*barrier();*/
+ return read_zsdata(chan);
+}
+void kgdb_interruptible(int yes)
+{
+ struct dec_zschannel *chan = zs_kgdbchan;
+ int one, nine;
+ nine = read_zsreg(chan, 9);
+ if (yes == 1) {
+ one = EXT_INT_ENAB|INT_ALL_Rx;
+ nine |= MIE;
+ printk("turning serial ints on\n");
+ } else {
+ one = RxINT_DISAB;
+ nine &= ~MIE;
+ printk("turning serial ints off\n");
+ }
+ write_zsreg(chan, 1, one);
+ write_zsreg(chan, 9, nine);
+}
+/* This sets up the serial port we're using, and turns on
+ * interrupts for that channel, so kgdb is usable once we're done.
+ */
+static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
+{
+ int brg;
+ int i, x;
+ volatile char *sccc = ms->control;
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
+ for (i = 20000; i != 0; --i) {
+ x = *sccc; eieio();
+ }
+ for (i = 0; i < sizeof(scc_inittab); ++i) {
+ write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
+ i++;
+ }
+}
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+__initfunc(void zs_kgdb_hook(int tty_num))
+{
+ /* Find out how many Z8530 SCCs we have */
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
+ zs_kgdbchan = zs_soft[tty_num].zs_channel;
+ zs_soft[tty_num].change_needed = 0;
+ zs_soft[tty_num].clk_divisor = 16;
+ zs_soft[tty_num].zs_baud = 38400;
+ zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
+ zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+ /* Turn on transmitter/receiver at 8-bits/char */
+ kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
+ printk("KGDB: on channel %d initialized\n", tty_num);
+ set_debug_traps(); /* init stub */
+}
+#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
new file mode 100644
index 000000000..d45ce05ed
--- /dev/null
+++ b/drivers/tc/zs.h
@@ -0,0 +1,405 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _DECSERIAL_H
+#define _DECSERIAL_H
+
+#define NUM_ZSREGS 16
+
+struct serial_struct {
+ int type;
+ int line;
+ int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char reserved_char[2];
+ int hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ int reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE 65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct dec_zschannel {
+ volatile unsigned char *control;
+ volatile unsigned char *data;
+
+ /* Current write register values */
+ unsigned char curregs[NUM_ZSREGS];
+};
+
+struct dec_serial {
+ struct dec_serial *zs_next; /* For IRQ servicing chain */
+ struct dec_zschannel *zs_channel; /* Channel registers */
+ struct dec_zschannel *zs_chan_a; /* A side registers */
+ unsigned char read_reg_zero;
+
+ char soft_carrier; /* Use soft carrier on this channel */
+ char break_abort; /* Is serial console in, so process brk/abrt */
+ char kgdb_channel; /* Kgdb is running on this channel */
+ char is_cons; /* Is this our console. */
+ unsigned char tx_active; /* character is being xmitted */
+ unsigned char tx_stopped; /* output is suspended */
+
+ /* We need to know the current clock divisor
+ * to read the bps rate the chip has currently
+ * loaded.
+ */
+ unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
+ int zs_baud;
+
+ char change_needed;
+
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int flags; /* defined in tty.h */
+ int type; /* UART type */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+#define XCLK_MASK 0xC0
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define SOFTACK 0x20 /* Software Interrupt Acknowledge */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ } while(0)
+
+#endif /* !(_DECSERIAL_H) */
diff --git a/include/asm-mips/baget/baget.h b/include/asm-mips/baget/baget.h
new file mode 100644
index 000000000..774493965
--- /dev/null
+++ b/include/asm-mips/baget/baget.h
@@ -0,0 +1,69 @@
+/* $Id$
+ * baget.h: Definitions specific to Baget/MIPS machines.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_BAGET_H
+#define _MIPS_BAGET_H
+
+#include "vic.h"
+#include "vac.h"
+
+#define VIC_BASE 0xBFFC0000
+#define VAC_BASE 0xBFFD0000
+
+
+/* Baget interrupt registers and their sizes */
+
+struct baget_int_reg {
+ unsigned long address;
+ int size; /* in bytes */
+};
+#define BAGET_INT_NONE {0,0}
+
+#define BAGET_INT0_ACK {0xbffa0003,1}
+#define BAGET_INT1_ACK {0xbffa0008,4}
+#define BAGET_INT5_ACK {0xbff00000,1}
+
+#define BAGET_WRERR_ACK ((volatile char*)0xbff00000)
+
+
+/* Baget address spaces */
+
+#define BAGET_A24M_BASE 0xFC000000 /* VME-master A24 base address */
+#define BAGET_A24S_BASE 0x00000000 /* VME-slave A24 base address */
+#define BAGET_A24S_MASK 0x00c00000 /* VME-slave A24 address mask */
+#define BAGET_GSW_BASE 0xf000 /* global switches address base */
+#define BAGET_MSW_BASE(P) (0xe000+(P)*0x100) /* module switches address base */
+
+#define BAGET_LED_BASE ((volatile short *)(0xbffd0000 + 0x00001800))
+
+#define BAGET_PIL_NR 8
+#define BAGET_IRQ_NR NR_IRQS /* 64 */
+#define BAGET_IRQ_MASK(x) ((NR_IRQS-1) & (x))
+
+#define BAGET_FPU_IRQ 0x26
+#define BAGET_VIC_TIMER_IRQ 0x32
+#define BAGET_VAC_TIMER_IRQ 0x37
+#define BAGET_BSM_IRQ 0x3C
+
+#define BAGET_LANCE_MEM_BASE 0xfcf10000
+#define BAGET_LANCE_MEM_SIZE 0x10000
+#define BAGET_LANCE_IO_BASE 0xbffeff00
+
+#define BALO_OFFSET 0x400000 /* sync with ld.script.balo */
+#define BALO_SIZE 0x200000 /* sync with image segs size */
+
+/* move it to the right place, somehere in include/asm */
+#define CAUSE_DBE 0x1C
+#define CAUSE_MASK 0x7C
+
+/* Simple debug fascilities */
+extern void outc(char);
+extern void outs(char *);
+extern void baget_write(char *s, int l);
+extern int baget_printk(const char *, ...);
+extern void balo_printf( char *f, ... );
+extern void balo_hungup(void);
+
+#endif /* !(_MIPS_BAGET_H) */
diff --git a/include/asm-mips/baget/vac.h b/include/asm-mips/baget/vac.h
new file mode 100644
index 000000000..4d1614773
--- /dev/null
+++ b/include/asm-mips/baget/vac.h
@@ -0,0 +1,208 @@
+/* $Id$
+ *
+ * vac.h: Various VIC controller defines. The VIC is a VME controller
+ * used in Baget/MIPS series.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_VAC_H
+#define _MIPS_VAC_H
+
+#define VAC_SLSEL1_MASK 0x000
+#define VAC_SLSEL1_BASE 0x100
+#define VAC_SLSEL0_MASK 0x200
+#define VAC_SLSEL0_BASE 0x300
+#define VAC_ICFSEL_BASE 0x400
+#define VAC_ICFSEL_GLOBAL_VAL(x) (((x)>>8)&0xff)
+#define VAC_ICFSEL_MODULE_VAL(x) ((x)&0xff)
+#define VAC_DRAM_MASK 0x500
+#define VAC_BNDR2 0x600
+#define VAC_BNDR3 0x700
+#define VAC_A24_BASE 0x800
+#define VAC_A24_MASK (0x3f<<9)
+#define VAC_A24_D32_ENABLE (1<<8)
+#define VAC_A24_A24_CACHINH (1<<7)
+#define VAC_A24_A16D32_ENABLE (1<<6)
+#define VAC_A24_A16D32 (1<<5)
+#define VAC_A24_DATAPATH (1<<4)
+#define VAC_A24_IO_CACHINH (1<<3)
+#define VAC_REG1 0x900
+#define VAC_REG2 0xA00
+#define VAC_REG3 0xB00
+#define VAC_REG_WORD (1<<15)
+#define VAC_REG_ASIZ1 (1<<14)
+#define VAC_REG_ASIZ0 (1<<13)
+#define VAC_REG_ASIZ_VAL(x) (((x)>>13)&3)
+#define VAC_REG_CACHINH (1<<12)
+#define VAC_REG_INACTIVE (0<<10)
+#define VAC_REG_SHARED (1<<10)
+#define VAC_REG_VSB (2<<10)
+#define VAC_REG_MWB (3<<10)
+#define VAC_REG_MASK (3<<10)
+#define VAC_REG_MODE(x) (((x)>>10)&3)
+#define VAC_IOSEL4_CTRL 0xC00
+#define VAC_IOSEL5_CTRL 0xD00
+#define VAC_SHRCS_CTRL 0xE00
+#define VAC_EPROMCS_CTRL 0xF00
+#define VAC_IOSEL0_CTRL 0x1000
+#define VAC_IOSEL1_CTRL 0x1100
+#define VAC_IOSEL2_CTRL 0x1200
+#define VAC_IOSEL3_CTRL 0x1300
+#define VAC_CTRL_IOWR (1<<0)
+#define VAC_CTRL_IORD (1<<1)
+#define VAC_CTRL_DELAY_IOSELI(x) (((x)&3)<<2)
+#define VAC_CTRL_DELAY_IOSELI_VAL(x) (((x)>>2)&3)
+#define VAC_CTRL_DELAY_IOWR(x) (((x)&3)<<4)
+#define VAC_CTRL_DELAY_IOWR_VAL(x) (((x)>>4)&3)
+#define VAC_CTRL_DELAY_IORD(x) (((x)&3)<<6)
+#define VAC_CTRL_DELAY_IORD_VAL(x) (((x)>>6)&3)
+#define VAC_CTRL_RECOVERY_IOSELI(x) ((((x)-1)&7)<<8)
+#define VAC_CTRL_RECOVERY_IOSELI_VAL(x) ((((x)>>8)&7)+1)
+#define VAC_CTRL_DSACK0 (1<<11)
+#define VAC_CTRL_DSACK1 (1<<12)
+#define VAC_CTRL_DELAY_DSACKI(x) ((((x)-1)&7)<<13)
+#define VAC_CTRL_DELAY_DSACKI_VAL(x) ((((x)>>13)&7)+1)
+#define VAC_DECODE_CTRL 0x1400
+#define VAC_DECODE_FPUCS (1<<0)
+#define VAC_DECODE_CPUCLK(x) (((x)&3)<<1)
+#define VAC_DECODE_CPUCLK_VAL(x) (((x)>>1)&3)
+#define VAC_DECODE_RDR_SLSEL0 (1<<3)
+#define VAC_DECODE_RDR_SLSEL1 (1<<4)
+#define VAC_DECODE_DSACK (1<<5)
+#define VAC_DECODE_QFY_BNDR (1<<6)
+#define VAC_DECODE_QFY_ICFSEL (1<<7)
+#define VAC_DECODE_QFY_SLSEL1 (1<<8)
+#define VAC_DECODE_QFY_SLSEL0 (1<<9)
+#define VAC_DECODE_CMP_SLSEL1_LO (1<<10)
+#define VAC_DECODE_CMP_SLSEL1_HI (1<<11)
+#define VAC_DECODE_CMP_SLSEL1_VAL(x) (((x)>>10)&3)
+#define VAC_DECODE_DRAMCS (3<<12)
+#define VAC_DECODE_SHRCS (2<<12)
+#define VAC_DECODE_VSBSEL (1<<12)
+#define VAC_DECODE_EPROMCS (0<<12)
+#define VAC_DECODE_MODE_VAL(x) (((x)>>12)&3)
+#define VAC_DECODE_QFY_DRAMCS (1<<14)
+#define VAC_DECODE_DSACKI (1<<15)
+#define VAC_INT_STATUS 0x1500
+#define VAC_INT_CTRL 0x1600
+#define VAC_INT_CTRL_TIMER_PIO11 (3<<0)
+#define VAC_INT_CTRL_TIMER_PIO10 (2<<0)
+#define VAC_INT_CTRL_TIMER_PIO7 (1<<0)
+#define VAC_INT_CTRL_TIMER_DISABLE (0<<0)
+#define VAC_INT_CTRL_UART_B_PIO11 (3<<2)
+#define VAC_INT_CTRL_UART_B_PIO10 (2<<2)
+#define VAC_INT_CTRL_UART_B_PIO7 (1<<2)
+#define VAC_INT_CTRL_UART_B_DISABLE (0<<2)
+#define VAC_INT_CTRL_UART_A_PIO11 (3<<4)
+#define VAC_INT_CTRL_UART_A_PIO10 (2<<4)
+#define VAC_INT_CTRL_UART_A_PIO7 (1<<4)
+#define VAC_INT_CTRL_UART_A_DISABLE (0<<4)
+#define VAC_INT_CTRL_MBOX_PIO11 (3<<6)
+#define VAC_INT_CTRL_MBOX_PIO10 (2<<6)
+#define VAC_INT_CTRL_MBOX_PIO7 (1<<6)
+#define VAC_INT_CTRL_MBOX_DISABLE (0<<6)
+#define VAC_INT_CTRL_PIO4_PIO11 (3<<8)
+#define VAC_INT_CTRL_PIO4_PIO10 (2<<8)
+#define VAC_INT_CTRL_PIO4_PIO7 (1<<8)
+#define VAC_INT_CTRL_PIO4_DISABLE (0<<8)
+#define VAC_INT_CTRL_PIO7_PIO11 (3<<10)
+#define VAC_INT_CTRL_PIO7_PIO10 (2<<10)
+#define VAC_INT_CTRL_PIO7_PIO7 (1<<10)
+#define VAC_INT_CTRL_PIO7_DISABLE (0<<10)
+#define VAC_INT_CTRL_PIO8_PIO11 (3<<12)
+#define VAC_INT_CTRL_PIO8_PIO10 (2<<12)
+#define VAC_INT_CTRL_PIO8_PIO7 (1<<12)
+#define VAC_INT_CTRL_PIO8_DISABLE (0<<12)
+#define VAC_INT_CTRL_PIO9_PIO11 (3<<14)
+#define VAC_INT_CTRL_PIO9_PIO10 (2<<14)
+#define VAC_INT_CTRL_PIO9_PIO7 (1<<14)
+#define VAC_INT_CTRL_PIO9_DISABLE (0<<14)
+#define VAC_DEV_LOC 0x1700
+#define VAC_DEV_LOC_IOSEL(x) (1<<(x))
+#define VAC_PIO_DATA_OUT 0x1800
+#define VAC_PIO_PIN 0x1900
+#define VAC_PIO_DIRECTION 0x1A00
+#define VAC_PIO_DIR_OUT(x) (1<<(x))
+#define VAC_PIO_DIR_IN(x) (0<<(x))
+#define VAC_PIO_DIR_FCIACK (1<<14)
+#define VAC_PIO_FUNC 0x1B00
+#define VAC_PIO_FUNC_UART_A_TX (1<<0)
+#define VAC_PIO_FUNC_UART_A_RX (1<<1)
+#define VAC_PIO_FUNC_UART_B_TX (1<<2)
+#define VAC_PIO_FUNC_UART_B_RX (1<<3)
+#define VAC_PIO_FUNC_IORD (1<<4)
+#define VAC_PIO_FUNC_IOWR (1<<5)
+#define VAC_PIO_FUNC_IOSEL3 (1<<6)
+#define VAC_PIO_FUNC_IRQ7 (1<<7)
+#define VAC_PIO_FUNC_IOSEL4 (1<<8)
+#define VAC_PIO_FUNC_IOSEL5 (1<<9)
+#define VAC_PIO_FUNC_IRQ10 (1<<10)
+#define VAC_PIO_FUNC_IRQ11 (1<<11)
+#define VAC_PIO_FUNC_OUT (1<<12)
+#define VAC_PIO_FUNC_IOSEL2 (1<<13)
+#define VAC_PIO_FUNC_DELAY (1<<14)
+#define VAC_PIO_FUNC_FCIACK (1<<15)
+#define VAC_CPU_CLK_DIV 0x1C00
+#define VAC_UART_A_MODE 0x1D00
+#define VAC_UART_MODE_PARITY_ENABLE (1<<15) /* Inversed in manual ? */
+#define VAC_UART_MODE_PARITY_ODD (1<<14) /* Inversed in manual ? */
+#define VAC_UART_MODE_8BIT_CHAR (1<<13)
+#define VAC_UART_MODE_BAUD(x) (((x)&7)<<10)
+#define VAC_UART_MODE_CHAR_RX_ENABLE (1<<9)
+#define VAC_UART_MODE_CHAR_TX_ENABLE (1<<8)
+#define VAC_UART_MODE_TX_ENABLE (1<<7)
+#define VAC_UART_MODE_RX_ENABLE (1<<6)
+#define VAC_UART_MODE_SEND_BREAK (1<<5)
+#define VAC_UART_MODE_LOOPBACK (1<<4)
+#define VAC_UART_MODE_INITIAL (VAC_UART_MODE_8BIT_CHAR | \
+ VAC_UART_MODE_TX_ENABLE | \
+ VAC_UART_MODE_RX_ENABLE | \
+ VAC_UART_MODE_CHAR_TX_ENABLE | \
+ VAC_UART_MODE_CHAR_RX_ENABLE | \
+ VAC_UART_MODE_BAUD(5)) /* 9600/4 */
+#define VAC_UART_A_TX 0x1E00
+#define VAC_UART_B_MODE 0x1F00
+#define VAC_UART_A_RX 0x2000
+#define VAC_UART_RX_ERR_BREAK (1<<10)
+#define VAC_UART_RX_ERR_FRAME (1<<9)
+#define VAC_UART_RX_ERR_PARITY (1<<8)
+#define VAC_UART_RX_DATA_MASK (0xff)
+#define VAC_UART_B_RX 0x2100
+#define VAC_UART_B_TX 0x2200
+#define VAC_UART_A_INT_MASK 0x2300
+#define VAC_UART_INT_RX_READY (1<<15)
+#define VAC_UART_INT_RX_FULL (1<<14)
+#define VAC_UART_INT_RX_BREAK_CHANGE (1<<13)
+#define VAC_UART_INT_RX_ERRS (1<<12)
+#define VAC_UART_INT_TX_READY (1<<11)
+#define VAC_UART_INT_TX_EMPTY (1<<10)
+#define VAC_UART_B_INT_MASK 0x2400
+#define VAC_UART_A_INT_STATUS 0x2500
+#define VAC_UART_STATUS_RX_READY (1<<15)
+#define VAC_UART_STATUS_RX_FULL (1<<14)
+#define VAC_UART_STATUS_RX_BREAK_CHANGE (1<<13)
+#define VAC_UART_STATUS_RX_ERR_PARITY (1<<12)
+#define VAC_UART_STATUS_RX_ERR_FRAME (1<<11)
+#define VAC_UART_STATUS_RX_ERR_OVERRUN (1<<10)
+#define VAC_UART_STATUS_TX_READY (1<<9)
+#define VAC_UART_STATUS_TX_EMPTY (1<<8)
+#define VAC_UART_STATUS_INTS (0xff<<8)
+#define VAC_UART_B_INT_STATUS 0x2600
+#define VAC_TIMER_DATA 0x2700
+#define VAC_TIMER_CTRL 0x2800
+#define VAC_TIMER_ONCE (1<<15)
+#define VAC_TIMER_ENABLE (1<<14)
+#define VAC_TIMER_PRESCALE(x) (((x)&0x3F)<<8)
+#define VAC_ID 0x2900
+
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#define vac_inb(p) (*(volatile unsigned char *)(VAC_BASE + (p)))
+#define vac_outb(v,p) (*((volatile unsigned char *)(VAC_BASE + (p))) = v)
+#define vac_inw(p) (*(volatile unsigned short*)(VAC_BASE + (p)))
+#define vac_outw(v,p) (*((volatile unsigned short*)(VAC_BASE + (p))) = v)
+
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#endif /* !(_MIPS_VAC_H) */
diff --git a/include/asm-mips/baget/vic.h b/include/asm-mips/baget/vic.h
new file mode 100644
index 000000000..f995066ab
--- /dev/null
+++ b/include/asm-mips/baget/vic.h
@@ -0,0 +1,193 @@
+/* $Id$
+ *
+ * vic.h: Various VIC controller defines. The VIC is an interrupt controller
+ * used in Baget/MIPS series.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_VIC_H
+#define _MIPS_VIC_H
+
+#define VIC_VME_II 0x3
+#define VIC_VME_INT1 0x7
+#define VIC_VME_INT2 0xB
+#define VIC_VME_INT3 0xF
+#define VIC_VME_INT4 0x13
+#define VIC_VME_INT5 0x17
+#define VIC_VME_INT6 0x1B
+#define VIC_VME_INT7 0x1F
+#define VIC_DMA_INT 0x23
+#define VIC_LINT1 0x27
+#define VIC_LINT2 0x2B
+#define VIC_LINT3 0x2F
+#define VIC_LINT4 0x33
+#define VIC_LINT5 0x37
+#define VIC_LINT6 0x3B
+#define VIC_LINT7 0x3F
+#define VIC_ICGS_INT 0x43
+#define VIC_ICMS_INT 0x47
+#define VIC_INT_IPL(lev) ((~(lev))&0x7)
+#define VIC_INT_ACTIVE (1<<3)
+#define VIC_INT_AUTO (0<<4)
+#define VIC_INT_NOAUTO (1<<4)
+#define VIC_INT_LEVEL (0<<5)
+#define VIC_INT_EDGE (1<<5)
+#define VIC_INT_LOW (0<<6)
+#define VIC_INT_HIGH (1<<6)
+#define VIC_INT_ENABLE (0<<7)
+#define VIC_INT_DISABLE (1<<7)
+#define VIC_INT_SWITCH(x) (1<<(((x)&0x3)+4))
+#define VIC_ERR_INT 0x4B
+#define VIC_ERR_INT_SYSFAIL_ACTIVE (1<<3)
+#define VIC_ERR_INT_SYSFAIL (1<<4)
+#define VIC_ERR_INT_TIMO (1<<5)
+#define VIC_ERR_INT_WRPOST (1<<6)
+#define VIC_ERR_INT_ACFAIL (1<<7)
+#define VIC_ICGS_BASE 0x4F
+#define VIC_ICMS_BASE 0x53
+#define VIC_ICxS_BASE_GSWITCH_MASK 0x3
+#define VIC_ICxS_BASE_ID(x) (((x)&0x3f)<<2)
+#define VIC_LOCAL_BASE 0x57
+#define VIC_LOCAL_BASE_LINT_MASK 0x7
+#define VIC_LOCAL_BASE_ID(x) (((x)&0x1f)<<3)
+#define VIC_ERR_BASE 0x5B
+#define VIC_ERR_BASE_ACFAIL 0
+#define VIC_ERR_BASE_WRPOST 1
+#define VIC_ERR_BASE_TIMO 2
+#define VIC_ERR_BASE_SYSFAIL 3
+#define VIC_ERR_BASE_VMEACK 4
+#define VIC_ERR_BASE_DMA 5
+#define VIC_ERR_BASE_ID(x) (((x)&0x1f)<<3)
+#define VIC_ICS 0x5F
+#define VIC_IC0 0x63
+#define VIC_IC1 0x67
+#define VIC_IC2 0x6B
+#define VIC_IC3 0x6F
+#define VIC_IC4 0x73
+#define VIC_ID 0x77
+#define VIC_IC6 0x7B
+#define VIC_IC6_IRESET_STATUS (1<<7)
+#define VIC_IC6_HALT_STATUS (1<<6)
+#define VIC_IC6_SYSRESET (3<<0)
+#define VIC_IC6_RESET (2<<0)
+#define VIC_IC6_HALT (1<<0)
+#define VIC_IC6_RUN (0<<0)
+#define VIC_IC7 0x7F
+#define VIC_IC7_SYSFAIL (1<<7)
+#define VIC_IC7_RESET (1<<6)
+#define VIC_IC7_VME_MASTER (1<<5)
+#define VIC_IC7_SEMSET(x) ((1<<(x))&0x1f)
+#define VIC_VME_REQ 0x83
+#define VIC_VME_BASE1 0x87
+#define VIC_VME_BASE2 0x8B
+#define VIC_VME_BASE3 0x8F
+#define VIC_VME_BASE4 0x93
+#define VIC_VME_BASE5 0x97
+#define VIC_VME_BASE6 0x9B
+#define VIC_VME_BASE7 0x9F
+#define VIC_XFER_TIMO 0xA3
+#define VIC_XFER_TIMO_VME_PERIOD_INF (7<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_512 (6<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_256 (5<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_128 (4<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_64 (3<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_32 (2<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_16 (1<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_4 (0<<5)
+#define VIC_XFER_TIMO_VME_PERIOD_VAL(x) (((x)>>5)&7)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_INF (7<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_512 (6<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_256 (5<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_128 (4<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_64 (3<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_32 (2<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_16 (1<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_4 (0<<2)
+#define VIC_XFER_TIMO_LOCAL_PERIOD_VAL(x) (((x)>>2)&7)
+#define VIC_XFER_TIMO_ARB (1<<1)
+#define VIC_XFER_TIMO_VME (1<<0)
+#define VIC_LOCAL_TIM 0xA7
+#define VIC_LOCAL_TIM_PAS_ASSERT(x) (((x)-2)&0xf)
+#define VIC_LOCAL_TIM_PAS_ASSERT_VAL(x) (((x)&0xf)+2)
+#define VIC_LOCAT_TIM_DS_DEASSERT(x) ((((x)-1)&1)<<4)
+#define VIC_LOCAT_TIM_DS_DEASSERT_VAL(x) ((((x)>>4)&1)+1)
+#define VIC_LOCAL_TIM_PAS_DEASSERT(x) ((((x)-1)&0x7)<<5)
+#define VIC_LOCAL_TIM_PAS_DEASSERT_VAL(x) ((((x)>>5)&0x7)+1)
+#define VIC_BXFER_DEF 0xAB
+#define VIC_BXFER_DEF_VME_CROSS (1<<3)
+#define VIC_BXFER_DEF_LOCAL_CROSS (1<<2)
+#define VIC_BXFER_DEF_AMSR (1<<1)
+#define VIC_BXFER_DEF_DUAL (1<<0)
+#define VIC_IFACE_CFG 0xAF
+#define VIC_IFACE_CFG_RMC3 (1<<7)
+#define VIC_IFACE_CFG_RMC2 (1<<6)
+#define VIC_IFACE_CFG_RMC1 (1<<5)
+#define VIC_IFACE_CFG_HALT (1<<4)
+#define VIC_IFACE_CFG_NOHALT (0<<4)
+#define VIC_IFACE_CFG_NORMC (1<<3)
+#define VIC_IFACE_CFG_DEADLOCK_VAL(x) (((x)>>3)&3)
+#define VIC_IFACE_CFG_MSTAB (1<<2)
+#define VIC_IFACE_CFG_TURBO (1<<1)
+#define VIC_IFACE_CFG_NOTURBO (0<<1)
+#define VIC_IFACE_CFG_VME (1<<0)
+#define VIC_REQ_CFG 0xB3
+#define VIC_REQ_CFG_FAIRNESS_DISABLED 0
+#define VIC_REQ_CFG_FAIRNESS_ENABLED 1
+#define VIC_REQ_CFG_TIMO_DISABLED 0xf
+#define VIC_REQ_CFG_DRAM_REFRESH (1<<4)
+#define VIC_REQ_CFG_LEVEL(x) (((x)&3)<<5)
+#define VIC_REQ_CFG_PRIO_ARBITRATION (1<<7)
+#define VIC_REQ_CFG_RR_ARBITRATION (0<<7)
+#define VIC_AMS 0xB7
+#define VIC_AMS_AM_2_0 (1<<7)
+#define VIC_AMS_AM_5_3 (1<<6)
+#define VIC_AMS_CODE(x) ((x)&0x1f)
+#define VIC_BERR_STATUS 0xBB
+#define VIC_DMA_STATUS 0xBF
+#define VIC_SS0CR0 0xC3
+#define VIC_SS1CR0 0xCB
+#define VIC_SSxCR0_LOCAL_XFER_ACCEL (2)
+#define VIC_SSxCR0_LOCAL_XFER_SINGLE (1)
+#define VIC_SSxCR0_LOCAL_XFER_NONE (0)
+#define VIC_SSxCR0_A32 (0<<2)
+#define VIC_SSxCR0_A24 (1<<2)
+#define VIC_SSxCR0_A16 (2<<2)
+#define VIC_SSxCR0_USER (3<<2)
+#define VIC_SSxCR0_D32 (1<<4)
+#define VIC_SSxCR0_SUPER (1<<5)
+#define VIC_SS0CR0_TIMER_FREQ_MASK (3<<6)
+#define VIC_SS0CR0_TIMER_FREQ_NONE (0<<6)
+#define VIC_SS0CR0_TIMER_FREQ_50HZ (1<<6)
+#define VIC_SS0CR0_TIMER_FREQ_1000HZ (2<<6)
+#define VIC_SS0CR0_TIMER_FREQ_100HZ (3<<6)
+#define VIC_SS1CR0_MASTER_WRPOST (1<<6)
+#define VIC_SS1CR0_SLAVE_WRPOST (1<<7)
+#define VIC_SS0CR1 0xC7
+#define VIC_SS1CR1 0xCF
+#define VIC_SSxCR1_TF2(x) (((x)&0xf)<<4)
+#define VIC_SSxCR1_TF1(x) ((x)&0xf)
+#define VIC_RELEASE 0xD3
+#define VIC_RELEASE_BLKXFER_BLEN(x) ((x)&0x1f)
+#define VIC_RELEASE_ROR (0<<6)
+#define VIC_RELEASE_RWD (1<<6)
+#define VIC_RELEASE_ROC (2<<6)
+#define VIC_RELEASE_BCAP (3<<6)
+#define VIC_BXFER_CTRL 0xD7
+#define VIC_BXFER_CTRL_MODULE (1<<7)
+#define VIC_BXFER_CTRL_LOCAL (1<<6)
+#define VIC_BXFER_CTRL_MOVEM (1<<5)
+#define VIC_BXFER_CTRL_READ (1<<4)
+#define VIC_BXFER_CTRL_WRITE (0<<4)
+#define VIC_BXFER_CTRL_INTERLEAVE(x) ((x)&0xf)
+#define VIC_BXFER_LEN_LO 0xDB
+#define VIC_BXFER_LEN_HI 0xDF
+#define VIC_SYS_RESET 0xE3
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#define vic_inb(p) (*(volatile unsigned char *)(VIC_BASE + (p)))
+#define vic_outb(v,p) (*((volatile unsigned char *)(VIC_BASE + (p))) = v)
+
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#endif /* !(_MIPS_VIC_H) */
diff --git a/include/asm-mips/dec/interrupts.h b/include/asm-mips/dec/interrupts.h
new file mode 100644
index 000000000..5f99727cc
--- /dev/null
+++ b/include/asm-mips/dec/interrupts.h
@@ -0,0 +1,79 @@
+/*
+ * Miscellaneous definitions used to initialise the interrupt vector table
+ * with the machine-specific interrupt routines.
+ *
+ * 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.
+ *
+ * Copyright (C) 1997 by Paul M. Antoine.
+ * reworked 1998 by Harald Koerfgen.
+ */
+
+#ifndef __ASM_DEC_INTERRUPTS_H
+#define __ASM_DEC_INTERRUPTS_H
+
+/*
+ * DECstation Interrupts
+ */
+
+/*
+ * This list reflects the priority of the Interrupts.
+ * Exception: on kmins we have to handle Memory Error
+ * Interrupts before the TC Interrupts.
+ */
+#define CLOCK 0
+#define SCSI_INT 1
+#define ETHER 2
+#define SERIAL 3
+#define TC0 4
+#define TC1 5
+#define TC2 6
+#define MEMORY 7
+#define FPU 8
+#define HALT 9
+
+#define NR_INTS 10
+
+#ifndef _LANGUAGE_ASSEMBLY
+/*
+ * Data structure to hide the differences between the DECstation Interrupts
+ *
+ * If asic_mask == NULL, the interrupt is directly handled by the CPU.
+ * Otherwise this Interrupt is handled the IRQ Controller.
+ */
+
+typedef struct
+{
+ unsigned int cpu_mask; /* checking and enabling interrupts in CP0 */
+ unsigned int iemask; /* enabling interrupts in IRQ Controller */
+} decint_t;
+
+/*
+ * Interrupt table structure to hide differences between different
+ * systems such.
+ */
+extern void *cpu_ivec_tbl[8];
+extern long cpu_mask_tbl[8];
+extern long cpu_irq_nr[8];
+extern long asic_irq_nr[32];
+extern long asic_mask_tbl[32];
+
+/*
+ * Common interrupt routine prototypes for all DECStations
+ */
+extern void dec_intr_unimplemented(void);
+extern void dec_intr_fpu(void);
+extern void dec_intr_rtc(void);
+
+extern void kn02_io_int(void);
+extern void kn02ba_io_int(void);
+extern void kn03_io_int(void);
+
+extern void intr_halt(void);
+
+extern void asic_intr_unimplemented(void);
+
+#endif
+#endif
+
diff --git a/include/asm-mips/dec/ioasic_addrs.h b/include/asm-mips/dec/ioasic_addrs.h
new file mode 100644
index 000000000..a2044782e
--- /dev/null
+++ b/include/asm-mips/dec/ioasic_addrs.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ * Definitions for the address map in the JUNKIO Asic
+ *
+ * Created with Information from:
+ *
+ * "DEC 3000 300/400/500/600/700/800/900 AXP Models System Programmer's Manual"
+ *
+ * and the Mach Sources
+ */
+
+#ifndef IOASIC_ADDRS_H
+#define IOASIC_ADDRS_H
+
+#define CHUNK_SIZE 0x00040000
+
+#define SYSTEM_ROM 00*CHUNK_SIZE /* ??? */
+#define IOCTL 01*CHUNK_SIZE
+#define ESAR 02*CHUNK_SIZE
+#define LANCE 03*CHUNK_SIZE
+#define SCC0 04*CHUNK_SIZE
+#define VDAC_HI 05*CHUNK_SIZE /* maxine only */
+#define SCC1 06*CHUNK_SIZE
+#define VDAC_LO 07*CHUNK_SIZE /* maxine only */
+#define TOY 08*CHUNK_SIZE
+#define ISDN 09*CHUNK_SIZE /* maxine only */
+#define ERRADDR 09*CHUNK_SIZE /* 3maxplus only */
+#define CHKSYN 10*CHUNK_SIZE /* 3maxplus only */
+#define ACCESS_BUS 10*CHUNK_SIZE /* maxine only */
+#define MCR 11*CHUNK_SIZE /* 3maxplus only */
+#define FLOPPY 11*CHUNK_SIZE /* maxine only */
+#define SCSI 12*CHUNK_SIZE
+#define FLOPPY_DMA 13*CHUNK_SIZE /* maxine only */
+#define SCSI_DMA 14*CHUNK_SIZE
+#define RESERVED_4 15*CHUNK_SIZE
+
+/*
+ * Offsets for IOCTL registers (relative to (system_base + IOCTL))
+ */
+#define SCSI_DMA_P 0x00 /* SCSI DMA Pointer */
+#define SCSI_DMA_BP 0x10 /* SCSI DMA Buffer Pointer */
+#define LANCE_DMA_P 0x20 /* LANCE DMA Pointer */
+#define SCC0_T_DMA_P 0x30 /* Communication Port 1 Transmit DMA Pointer */
+#define SCC0_R_DMA_P 0x40 /* Communication Port 1 Receive DMA Pointer */
+#define SCC1_T_DMA_P 0x50 /* Communication Port 2 Transmit DMA Pointer */
+#define SCC1_R_DMA_P 0x60 /* Communication Port 2 Receive DMA Pointer */
+#define FLOPPY_DMA_P 0x70 /* Floppy DMA Pointer */
+#define ISDN_T_DMA_P 0x80 /* ISDN Transmit DMA Pointer */
+#define ISDN_T_DMA_BP 0x90 /* ISDN Transmit DMA Buffer Pointer */
+#define ISDN_R_DMA_P 0xa0 /* ISDN Receive DMA Pointer */
+#define ISDN_R_DMA_BP 0xb0 /* ISDN Receive DMA Buffer Pointer */
+
+#define SSR 0x100 /* System Support Register */
+#define SIR 0x110 /* System Interrupt Register */
+#define SIMR 0x120 /* System Interrupt Mask Register */
+
+/*
+ * These come from mach, meaning unkown yet
+ */
+#define SCSI_SCR 0x1b0
+#define SCSI_SDR0 0x1c0
+#define SCSI_SDR1 0x1d0
+
+#endif
diff --git a/include/asm-mips/dec/ioasic_ints.h b/include/asm-mips/dec/ioasic_ints.h
new file mode 100644
index 000000000..e1f61f1cb
--- /dev/null
+++ b/include/asm-mips/dec/ioasic_ints.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ *
+ * Definitions for the interrupt related bits in the JUNKIO Asic
+ * interrupt status register (and the interrupt mask register, of course)
+ *
+ * Created with Information from:
+ *
+ * "DEC 3000 300/400/500/600/700/800/900 AXP Models System Programmer's Manual"
+ *
+ * and the Mach Sources
+ */
+
+/*
+ * the upper 16 bits are common to all JUNKIO machines
+ * (except the FLOPPY and ISDN bits, which are Maxine sepcific)
+ */
+#define SCC0_TRANS_PAGEEND 0x80000000 /* Serial DMA Errors */
+#define SCC0_TRANS_MEMRDERR 0x40000000 /* see below */
+#define SCC0_RECV_HALFPAGE 0x20000000
+#define SCC0_RECV_PAGOVRRUN 0x10000000
+#define SCC1_TRANS_PAGEEND 0x08000000 /* end of page reached */
+#define SCC1_TRANS_MEMRDERR 0x04000000 /* SCC1 DMA memory err */
+#define SCC1_RECV_HALFPAGE 0x02000000 /* SCC1 half page */
+#define SCC1_RECV_PAGOVRRUN 0x01000000 /* SCC1 receive overrun */
+#define FLOPPY_DMA_ERROR 0x00800000 /* FDI DMA error */
+#define ISDN_TRANS_PTR_LOADED 0x00400000 /* xmitbuf ptr loaded */
+#define ISDN_RECV_PTR_LOADED 0x00200000 /* rcvbuf ptr loaded */
+#define ISDN_DMA_MEMRDERR 0x00100000 /* read or ovrrun error */
+#define SCSI_PTR_LOADED 0x00080000
+#define SCSI_PAGOVRRUN 0x00040000 /* page overrun? */
+#define SCSI_DMA_MEMRDERR 0x00020000
+#define LANCE_DMA_MEMRDERR 0x00010000
+
+/*
+ * the lower 16 bits are system specific
+ */
+
+/*
+ * The following three seem to be in common
+ */
+#define SCSI_CHIP 0x00000200
+#define LANCE_CHIP 0x00000100
+#define SCC1_CHIP 0x00000080 /* NOT on maxine */
+#define SCC0_CHIP 0x00000040
+
+/*
+ * The rest is different
+ */
+
+/* kmin aka 3min aka kn02ba aka DS5000_1xx */
+#define KMIN_TIMEOUT 0x00001000 /* CPU IO-Write Timeout */
+#define KMIN_CLOCK 0x00000020
+#define KMIN_SCSI_FIFO 0x00000004 /* SCSI Data Ready */
+
+/* kn02ca aka maxine */
+#define MAXINE_FLOPPY 0x00008000 /* FDI Interrupt */
+#define MAXINE_TC0 0x00001000 /* TC Option 0 */
+#define MAXINE_ISDN 0x00000800 /* ISDN Chip */
+#define MAXINE_FLOPPY_HDS 0x00000080 /* Floppy Status */
+#define MAXINE_TC1 0x00000020 /* TC Option 1 */
+#define MAXINE_FLOPPY_XDS 0x00000010 /* Floppy Status */
+#define MAXINE_VINT 0x00000008 /* Video Frame */
+#define MAXINE_N_VINT 0x00000004 /* Not Video frame */
+#define MAXINE_DTOP_TRANS 0x00000002 /* DTI Xmit-Rdy */
+#define MAXINE_DTOP_RECV 0x00000001 /* DTI Recv-Available */
+
+/* kn03 aka 3max+ aka DS5000_2x0 */
+#define KN03_TC2 0x00004000
+#define KN03_TC1 0x00002000
+#define KN03_TC0 0x00001000
+#define KN03_SCSI_FIFO 0x00000004 /* ??? Info from Mach */
+
+/*
+ * Now form groups, i.e. all serial interrupts, all SCSI interrupts and so on.
+ */
+#define SERIAL_INTS (SCC0_TRANS_PAGEEND | SCC0_TRANS_MEMRDERR | \
+ SCC0_RECV_HALFPAGE | SCC0_RECV_PAGOVRRUN | \
+ SCC1_TRANS_PAGEEND | SCC1_TRANS_MEMRDERR | \
+ SCC1_RECV_HALFPAGE | SCC1_RECV_PAGOVRRUN | \
+ SCC1_CHIP | SCC0_CHIP)
+
+#define XINE_SERIAL_INTS (SCC0_TRANS_PAGEEND | SCC0_TRANS_MEMRDERR | \
+ SCC0_RECV_HALFPAGE | SCC0_RECV_PAGOVRRUN | \
+ SCC0_CHIP)
+
+#define SCSI_INTS (SCSI_PTR_LOADED | SCSI_PAGOVRRUN | \
+ SCSI_DMA_MEMRDERR | SCSI_CHIP)
+
+#define KMIN_SCSI_INTS (SCSI_PTR_LOADED | SCSI_PAGOVRRUN | \
+ SCSI_DMA_MEMRDERR | SCSI_CHIP | KMIN_SCSI_FIFO)
+
+#define LANCE_INTS (LANCE_DMA_MEMRDERR | LANCE_CHIP)
+
+/*
+ * For future use ...
+ */
+#define XINE_FLOPPY_INTS (MAXINE_FLOPPY | MAXINE_FLOPPY_HDS | \
+ FLOPPY_DMA_ERROR | MAXINE_FLOPPY_XDS)
+
+#define XINE_ISDN_INTS (MAXINE_ISDN | ISDN_TRANS_PTR_LOADED | \
+ ISDN_RECV_PTR_LOADED | ISDN_DMA_MEMRDERR)
+
+#define XINE_DTOP_INTS (MAXINE_DTOP_TRANS | DTOP_RECV | \
+ ISDN_TRANS_PTR_LOADED | ISDN_RECV_PTR_LOADED | \
+ ISDN_DMA_MEMRDERR)
diff --git a/include/asm-mips/dec/kn01.h b/include/asm-mips/dec/kn01.h
new file mode 100644
index 000000000..61a46e843
--- /dev/null
+++ b/include/asm-mips/dec/kn01.h
@@ -0,0 +1,28 @@
+/*
+ * Hardware info about DEC DECstation DS2100/3100 systems (otherwise known
+ * as pmax or kn01.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * This file is under construction - you were warned!
+ */
+#ifndef __ASM_MIPS_DEC_KN01_H
+#define __ASM_MIPS_DEC_KN01_H
+
+#include <asm/addrspace.h>
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+
+#define KN01_LANCE_BASE (KSEG1ADDR(0x18000000)) /* 0xB8000000 */
+#define KN01_DZ11_BASE (KSEG1ADDR(0x1c000000)) /* 0xBC000000 */
+#define KN01_RTC_BASE (KSEG1ADDR(0x1d000000)) /* 0xBD000000 */
+
+#endif /* __ASM_MIPS_DEC_KN01_H */
diff --git a/include/asm-mips/dec/kn02.h b/include/asm-mips/dec/kn02.h
new file mode 100644
index 000000000..9888eb49f
--- /dev/null
+++ b/include/asm-mips/dec/kn02.h
@@ -0,0 +1,41 @@
+/*
+ * Hardware info about DEC DECstation 5000/2xx systems (otherwise known
+ * as 3max or kn02.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * This file is under construction - you were warned!
+ */
+#ifndef __ASM_MIPS_DEC_KN02_H
+#define __ASM_MIPS_DEC_KN02_H
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN02_CSR_ADDR KSEG1ADDR(0x1ff00000) /* system control & status reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN02_RTC_BASE KSEG1ADDR(0x1fe80000)
+#define KN02_DZ11_BASE KSEG1ADDR(0x1fe00000)
+
+/*
+ * Interrupt enable Bits
+ */
+#define KN02_SLOT0 (1<<16)
+#define KN02_SLOT1 (1<<17)
+#define KN02_SLOT2 (1<<18)
+#define KN02_SLOT5 (1<<21)
+#define KN02_SLOT6 (1<<22)
+#define KN02_SLOT7 (1<<23)
+
+#endif /* __ASM_MIPS_DEC_KN02_H */
diff --git a/include/asm-mips/dec/kn02xa.h b/include/asm-mips/dec/kn02xa.h
new file mode 100644
index 000000000..b72367fec
--- /dev/null
+++ b/include/asm-mips/dec/kn02xa.h
@@ -0,0 +1,34 @@
+/*
+ * Hardware info about DEC DECstation 5000/1xx systems (otherwise known
+ * as 3min or kn02ba. Apllies to the Personal DECstations 5000/xx (otherwise known
+ * as maxine or kn02ca) as well.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * These are addresses which have to be known early in the boot process.
+ * For other addresses refer to tc.h ioasic_addrs.h and friends.
+ */
+#ifndef __ASM_MIPS_DEC_KN02XA_H
+#define __ASM_MIPS_DEC_KN02XA_H
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN02XA_SSR_ADDR KSEG1ADDR(0x1c040100) /* system control & status reg */
+#define KN02XA_SIR_ADDR KSEG1ADDR(0x1c040110) /* system interrupt reg */
+#define KN02XA_SIRM_ADDR KSEG1ADDR(0x1c040120) /* system interrupt mask reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN02XA_RTC_BASE (KSEG1ADDR(0x1c000000 + 0x200000)) /* ASIC + SL8 */
+
+#endif /* __ASM_MIPS_DEC_KN02XA_H */
diff --git a/include/asm-mips/dec/kn03.h b/include/asm-mips/dec/kn03.h
new file mode 100644
index 000000000..87ccae4b2
--- /dev/null
+++ b/include/asm-mips/dec/kn03.h
@@ -0,0 +1,33 @@
+/*
+ * Hardware info about DEC DECstation 5000/2x0 systems (otherwise known
+ * as 3max+ or kn03.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * These are addresses which have to be known early in the boot process.
+ * For other addresses refer to tc.h ioasic_addrs.h and friends.
+ */
+#ifndef __ASM_MIPS_DEC_KN03_H
+#define __ASM_MIPS_DEC_KN03_H
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN03_SSR_ADDR KSEG1ADDR(0x1f840100) /* system control & status reg */
+#define KN03_SIR_ADDR KSEG1ADDR(0x1f840110) /* system interrupt reg */
+#define KN03_SIRM_ADDR KSEG1ADDR(0x1f840120) /* system interrupt mask reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN03_RTC_BASE (KSEG1ADDR(0x1f800000 + 0x200000)) /* ASIC + SL8 */
+
+#endif /* __ASM_MIPS_DEC_KN03_H */
diff --git a/include/asm-mips/dec/machtype.h b/include/asm-mips/dec/machtype.h
new file mode 100644
index 000000000..ed4335d19
--- /dev/null
+++ b/include/asm-mips/dec/machtype.h
@@ -0,0 +1,20 @@
+/*
+ * Various machine type definitions
+ *
+ * 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.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+#include <asm/bootinfo.h>
+
+#define TURBOCHANNEL (mips_machtype == MACH_DS5000_200 || \
+ mips_machtype == MACH_DS5000_1XX || \
+ mips_machtype == MACH_DS5000_XX || \
+ mips_machtype == MACH_DS5000_2X0)
+
+#define IOASIC (mips_machtype == MACH_DS5000_1XX || \
+ mips_machtype == MACH_DS5000_XX || \
+ mips_machtype == MACH_DS5000_2X0)
+
diff --git a/include/asm-mips/dec/tc.h b/include/asm-mips/dec/tc.h
new file mode 100644
index 000000000..64fb03374
--- /dev/null
+++ b/include/asm-mips/dec/tc.h
@@ -0,0 +1,43 @@
+/*
+ * Interface to the TURBOchannel related routines
+ *
+ * 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.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+#ifndef ASM_TC_H
+#define ASM_TC_H
+
+extern unsigned long system_base;
+
+/*
+ * Search for a TURBOchannel Option Module
+ * with a certain name. Returns slot number
+ * of the first card not in use or -ENODEV
+ * if none found.
+ */
+extern int search_tc_card(const char *);
+/*
+ * Marks the card in slot as used
+ */
+extern void claim_tc_card(int);
+/*
+ * Marks the card in slot as free
+ */
+extern void release_tc_card(int);
+/*
+ * Return base address of card in slot
+ */
+extern unsigned long get_tc_base_addr(int);
+/*
+ * Return interrupt number of slot
+ */
+extern unsigned long get_tc_irq_nr(int);
+/*
+ * Return TURBOchannel clock frequency in hz
+ */
+extern unsigned long get_tc_speed(void);
+
+#endif
diff --git a/include/asm-mips/dec/tcinfo.h b/include/asm-mips/dec/tcinfo.h
new file mode 100644
index 000000000..72ecc894a
--- /dev/null
+++ b/include/asm-mips/dec/tcinfo.h
@@ -0,0 +1,47 @@
+/*
+ * Various TURBOchannel related stuff
+ *
+ * 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.
+ *
+ * Information obtained through the get_tcinfo prom call
+ * created from:
+ *
+ * TURBOchannel Firmware Specification
+ *
+ * EK-TCAAD-FS-004
+ * from Digital Equipment Corporation
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+
+typedef struct {
+ int revision;
+ int clk_period;
+ int slot_size;
+ int io_timeout;
+ int dma_range;
+ int max_dma_burst;
+ int parity;
+ int reserved[4];
+} tcinfo;
+
+#define MAX_SLOT 7
+
+typedef struct {
+ unsigned long base_addr;
+ unsigned char name[9];
+ unsigned char vendor[9];
+ unsigned char firmware[9];
+ int interrupt;
+ int flags;
+} slot_info;
+
+/*
+ * Values for flags
+ */
+#define FREE 1<<0
+#define IN_USE 1<<1
+
+
diff --git a/include/asm-mips/dec/tcmodule.h b/include/asm-mips/dec/tcmodule.h
new file mode 100644
index 000000000..26c5a5e29
--- /dev/null
+++ b/include/asm-mips/dec/tcmodule.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * Offsets for the ROM header locations for
+ * TURBOchannel cards
+ *
+ * created from:
+ *
+ * TURBOchannel Firmware Specification
+ *
+ * EK-TCAAD-FS-004
+ * from Digital Equipment Corporation
+ *
+ * Jan.1998 Harald Koerfgen
+ */
+
+#define OLDCARD 0x3c0000
+
+#define ROM_WIDTH 0x3e0
+#define ROM_STRIDE 0x3e4
+#define ROM_SIZE 0x3e8
+#define SLOT_SIZE 0x3ec
+#define PATTERN0 0x3f0
+#define PATTERN1 0x3f4
+#define PATTERN2 0x3f8
+#define PATTERN3 0x3fc
+#define FIRM_VER 0x400
+#define VENDOR 0x420
+#define MODULE 0x440
+#define FIRM_TYPE 0x460
+#define FLAGS 0x470
+
+#define ROM_OBJECTS 0x480