]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.34pre15 2.0.34pre15
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:45 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:45 +0000 (15:11 -0500)
120 files changed:
Documentation/Configure.help
Documentation/rtc.txt
arch/alpha/Makefile
arch/alpha/boot/Makefile
arch/alpha/boot/bootp.c [new file with mode: 0644]
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/Makefile
arch/alpha/kernel/apecs.c
arch/alpha/kernel/bios32.c
arch/alpha/kernel/cia.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/head.S
arch/alpha/kernel/irq.c
arch/alpha/kernel/lca.c
arch/alpha/kernel/process.c
arch/alpha/kernel/pyxis.c [new file with mode: 0644]
arch/alpha/kernel/setup.c
arch/alpha/kernel/signal.c
arch/alpha/kernel/smc.c [new file with mode: 0644]
arch/alpha/kernel/t2.c [new file with mode: 0644]
arch/alpha/kernel/traps.c
arch/alpha/math-emu/fp-emul.c
arch/alpha/mm/init.c
arch/i386/kernel/entry.S
arch/i386/kernel/ptrace.c
arch/i386/kernel/smp.c
drivers/block/genhd.c
drivers/block/ide.c
drivers/block/rd.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/h8.c [new file with mode: 0644]
drivers/char/h8.h [new file with mode: 0644]
drivers/char/mem.c
drivers/char/misc.c
drivers/char/rtc.c
drivers/char/selection.h
drivers/char/tga.c
drivers/char/tty_io.c
drivers/net/3c509.c
drivers/net/3c59x.c
drivers/net/auto_irq.c
drivers/net/lance.c
drivers/net/ne.c
drivers/net/ppp.c
drivers/pci/pci.c
drivers/scsi/BusLogic.c
drivers/scsi/Config.in
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/README.BusLogic
drivers/scsi/README.ppa
drivers/scsi/aic7xxx.c
drivers/scsi/dtc.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/ncr53c8xx.h
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/scsi/qlogicisp.c
drivers/scsi/scsi.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_syms.c
drivers/scsi/sg.c
fs/Makefile
fs/binfmt_elf.c
fs/binfmt_em86.c [new file with mode: 0644]
fs/buffer.c
fs/dquot.c
fs/ext2/namei.c
fs/fat/dir.c
fs/isofs/inode.c
fs/select.c
fs/super.c
include/asm-alpha/a.out.h
include/asm-alpha/apecs.h
include/asm-alpha/cia.h
include/asm-alpha/dma.h
include/asm-alpha/floppy.h
include/asm-alpha/hwrpb.h
include/asm-alpha/io.h
include/asm-alpha/irq.h
include/asm-alpha/lca.h
include/asm-alpha/pal.h
include/asm-alpha/processor.h
include/asm-alpha/ptrace.h
include/asm-alpha/pyxis.h [new file with mode: 0644]
include/asm-alpha/shmparam.h
include/asm-alpha/system.h
include/asm-alpha/t2.h [new file with mode: 0644]
include/asm-i386/processor.h
include/asm-m68k/processor.h
include/asm-mips/processor.h
include/asm-ppc/processor.h
include/asm-sparc/processor.h
include/linux/fs.h
include/linux/genhd.h
include/linux/ioport.h
include/linux/lists.h
include/linux/mc146818rtc.h
include/linux/personality.h
include/linux/swap.h
include/scsi/scsi_ioctl.h
init/main.c
ipc/shm.c
kernel/exit.c
mm/mmap.c
mm/mremap.c
mm/swap_state.c
mm/swapfile.c
net/ax25/af_ax25.c
net/core/sock.c
net/ethernet/eth.c
net/ipv4/af_inet.c
net/ipv4/rarp.c
net/ipv4/tcp.c
net/ipv4/tcp_output.c
net/netrom/af_netrom.c
net/netsyms.c
net/unix/af_unix.c

index 10cda3dbe5797f64eae4c0a300e25c2521dbab0b..7b274e3dd7f18820f822b9cefa47d88eda805cb4 100644 (file)
@@ -465,31 +465,9 @@ CONFIG_SYN_COOKIES
   this option turned on the TCP/IP stack will use a cryptographic
   challenge protocol known as SYN cookies to enable legitimate users
   to continue to connect, even when your machine is under attack.
-  The RST_COOKIES option provides an alternative method to accomplish
-  the same end.  SYN cookies use less space than RST cookies,
-  but have a small probability of introducing an non timed-out
-  failure to connect in the remote TCP.  You can use both options
-  simultatenously.  If you are SYN flooded, the source address
-  reported by the kernel is likely to have been forged by the
-  attacker.  The source address is reported as an aid in tracing the
-  packets to their actual source.
-
-SYN flood protection
-CONFIG_RST_COOKIES
-  Normal TCP/IP networking is open to an attack known as SYN flooding.
-  This attack prevents legitimate users from being able to connect to
-  your computer and requires very little work for the attacker.
-  SYN cookies provide protection against this type of attack. With
-  this option turned on the TCP/IP stack will use a cryptographic
-  challenge protocol known as RST cookies to enable legitimate users
-  to continue to connect, even when your machine is under attack.
-  The SYN_COOKIES option provides an alternative method to accomplish
-  the same end. RST cookies use more space than SYN cookies on your
-  machine, but never increase the probability of a frozen connection
-  in a remote TCP. You can use both options simultatenously.  If you
-  are SYN flooded, the source address reported by the kernel is likely
-  to have been forged by the attacker.  The source address is reported
-  as an aid in tracing the packets to their actual source.
+  If you are SYN flooded, the source address reported by the kernel is 
+  likely to have been forged by the attacker.  The source address is 
+  reported as an aid in tracing the packets to their actual source.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -1868,6 +1846,15 @@ CONFIG_SCSI_PPA
   the SCSI version of the ZIP drive: it will be supported
   automatically if you enabled the generic "SCSI disk support", above.
 
+IOMEGA ZIP drive - Buggy EPP chipset support
+CONFIG_SCSI_PPA_HAVE_PEDANTIC
+  Contacts with the Iomega driver development team indicate there are
+  a few reputably bad EPP implementations in existance. The following
+  mainboard chipsets will probably require the PEDANTIC option to
+  reliably transfer data:
+       Winbond xxx837
+       National Semiconductor PC87306 (early revisions)
+
 Network device support?
 CONFIG_NETDEVICES
   You can say N here in case you don't intend to connect to any other
index e290b4177750eeba9a6562b11bd2c529b8461ac0..927ad6dca6504eb3f7ddcb7683d56751fde09d5f 100644 (file)
@@ -65,6 +65,35 @@ that will be using this driver.
 
                                                Paul Gortmaker
 
+Update in version 1.09
+======================
+
+Epoch handling is added.  Epoch is the number which should be added to the
+value of the clock's year register to get the actual year.  The default
+Linux epoch is therefore 1900.
+
+Epochs are especially useful on Alphas where different operating systems
+use different epochs, and Linux wants to be compatible with all of them.
+They may eventually be helpful on Intel architecture as well, where a
+value of an RTC register cannot exceed 99 due to BCD tradition originated
+from DOS.
+
+When the epoch is set to 1900, the new code behaves exactly like the old
+one with respect to the BCD wrapping: values 00 - 69 are treated as if
+they were 100 - 169.  That means that after the 2000th year epoch 1900
+will be the same as epoch 2000.
+
+Two new ioctls are introduced to read and set the epoch, RTC_EPOCH_READ
+and RTC_EPOCH_SET.  They can be used in exactly the same manner as
+RTC_IRQP_READ and RTC_IRQP_SET, so they are not included in the example
+program below.
+
+On Alphas an epoch autodetection is performed.  Currently 3 epochs
+are recognised: Linux (1900), Digital UNIX (1952) and Windows NT (1980).
+
+Nikita Schmidt <cetus@snowball.ucd.ie>
+
+
 -------------------- 8< ---------------- 8< -----------------------------
 
 /*
index a234e945366270c4b26f59f2f068a19fff058c04..2467ba8ebb908e6d1caa7755ea779ef3d5347789 100644 (file)
@@ -26,6 +26,21 @@ endif
 
 CFLAGS := $(CFLAGS) -mno-fp-regs
 
+# determine if we can use the BWX instructions with GAS
+$(shell rm -f /tmp/GAS_VER)
+#$(shell $(AS) --version >& /tmp/GAS_VER)
+$(shell $(AS) --version > /tmp/GAS_VER 2>&1)
+OLD_GAS := $(shell if cat /tmp/GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi)
+
+ifneq ($(OLD_GAS),yes)
+ CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE
+
+# if PYXIS, then enable use of BWIO space
+ ifeq ($(CONFIG_ALPHA_PYXIS),y)
+  CFLAGS := $(CFLAGS) -DBWIO_ENABLED
+ endif
+endif
+
 HEAD := arch/alpha/kernel/head.o
 
 SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \
@@ -57,3 +72,6 @@ archclean:
 
 archdep:
        @$(MAKEBOOT) dep
+
+bootpfile:
+       @$(MAKEBOOT) bootpfile
index b3d888a9231f81022297876563719f42fd4fd29b..ee2ecd37952bde414dada29124cecb1e8ad2968e 100644 (file)
@@ -26,6 +26,7 @@ endif
        $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 OBJECTS = head.o main.o
+BPOBJECTS = head.o bootp.o
 TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo
 VMLINUX = $(TOPDIR)/vmlinux
 OBJSTRIP = tools/objstrip
@@ -44,6 +45,9 @@ bootimage:    tools/mkbb tools/lxboot tools/bootlx vmlinux.nh
        ( cat tools/lxboot tools/bootlx vmlinux.nh ) > bootimage
        tools/mkbb bootimage tools/lxboot
 
+bootpfile:     tools/bootph vmlinux.nh
+       ( cat tools/bootph vmlinux.nh ) > bootpfile
+
 srmboot:       bootdevice bootimage
        dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1
        tools/mkbb $(BOOTDEV) tools/lxboot
@@ -59,6 +63,8 @@ vmlinux.gz: vmlinux
 #
 main.o: ksize.h
 
+bootp.o: ksize.h
+
 ksize.h: $(OBJSTRIP) vmlinux.nh
        echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@
 
@@ -82,6 +88,9 @@ tools/lxboot: $(OBJSTRIP) bootloader
 tools/bootlx: bootloader $(OBJSTRIP)
        $(OBJSTRIP) -vb bootloader tools/bootlx
 
+tools/bootph: bootpheader $(OBJSTRIP)
+       $(OBJSTRIP) -vb bootpheader tools/bootph
+
 $(OBJSTRIP): $(OBJSTRIP).c
        $(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP)
 
@@ -95,8 +104,15 @@ bootloader: $(OBJECTS)
                -o bootloader && strip bootloader || \
                (rm -f bootloader && exit 1)
 
+bootpheader: $(BPOBJECTS)
+       $(LD) $(LINKFLAGS) \
+               $(BPOBJECTS) \
+               $(LIBS) \
+               -o bootpheader && strip bootpheader || \
+               (rm -f bootpheader && exit 1)
+
 clean:
        rm -f $(TARGETS) bootloader bootimage vmlinux.nh \
-               tools/mkbb tools/bootlx tools/lxboot
+               tools/mkbb tools/bootlx tools/lxboot ksize.h
 
 dep:
diff --git a/arch/alpha/boot/bootp.c b/arch/alpha/boot/bootp.c
new file mode 100644 (file)
index 0000000..5342503
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * arch/alpha/boot/bootp.c
+ *
+ * Copyright (C) 1997 Jay Estabrook
+ *
+ * This file is used for creating a bootp file for the Linux/AXP kernel
+ *
+ * based significantly on the arch/alpha/boot/main.c of Linus Torvalds
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <asm/system.h>
+#include <asm/console.h>
+#include <asm/hwrpb.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include <stdarg.h>
+
+#include "ksize.h"
+
+extern int vsprintf(char *, const char *, va_list);
+extern unsigned long switch_to_osf_pal(unsigned long nr,
+       struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
+       unsigned long vptb, unsigned long *kstk);
+
+int printk(const char * fmt, ...)
+{
+       va_list args;
+       int i, j, written, remaining, num_nl;
+       static char buf[1024];
+       char * str;
+
+       va_start(args, fmt);
+       i = vsprintf(buf, fmt, args);
+       va_end(args);
+
+       /* expand \n into \r\n: */
+
+       num_nl = 0;
+       for (j = 0; j < i; ++j) {
+           if (buf[j] == '\n')
+               ++num_nl;
+       }
+       remaining = i + num_nl;
+       for (j = i - 1; j >= 0; --j) {
+           buf[j + num_nl] = buf[j];
+           if (buf[j] == '\n') {
+               --num_nl;
+               buf[j + num_nl] = '\r';
+           }
+       }
+
+       str = buf;
+       do {
+           written = puts(str, remaining);
+           remaining -= written;
+           str += written;
+       } while (remaining > 0);
+       return i;
+}
+
+#define hwrpb (*INIT_HWRPB)
+
+/*
+ * Find a physical address of a virtual object..
+ *
+ * This is easy using the virtual page table address.
+ */
+struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
+{
+       unsigned long address = (unsigned long) pcb;
+       unsigned long result;
+
+       result = vptb[address >> 13];
+       result >>= 32;
+       result <<= 13;
+       result |= address & 0x1fff;
+       return (struct pcb_struct *) result;
+}      
+
+/*
+ * This function moves into OSF/1 pal-code, and has a temporary
+ * PCB for that. The kernel proper should replace this PCB with
+ * the real one as soon as possible.
+ *
+ * The page table muckery in here depends on the fact that the boot
+ * code has the L1 page table identity-map itself in the second PTE
+ * in the L1 page table. Thus the L1-page is virtually addressable
+ * itself (through three levels) at virtual address 0x200802000.
+ *
+ * As we don't want it there anyway, we also move the L1 self-map
+ * up as high as we can, so that the last entry in the L1 page table
+ * maps the page tables.
+ *
+ * As a result, the OSF/1 pal-code will instead use a virtual page table
+ * map located at 0xffffffe00000000.
+ */
+#define pcb_va ((struct pcb_struct *) 0x20000000)
+#define old_vptb (0x0000000200000000UL)
+#define new_vptb (0xfffffffe00000000UL)
+void pal_init(void)
+{
+       unsigned long i, rev, sum;
+       unsigned long *L1, *l;
+       struct percpu_struct * percpu;
+       struct pcb_struct * pcb_pa;
+
+       /* Find the level 1 page table and duplicate it in high memory */
+       L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
+       L1[1023] = L1[1];
+
+       percpu = (struct percpu_struct *)
+                       (hwrpb.processor_offset + (unsigned long) &hwrpb),
+               
+       pcb_va->ksp = 0;
+       pcb_va->usp = 0;
+       pcb_va->ptbr = L1[1] >> 32;
+       pcb_va->asn = 0;
+       pcb_va->pcc = 0;
+       pcb_va->unique = 0;
+       pcb_va->flags = 1;
+       pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
+       printk("Switching to OSF PAL-code .. ");
+       /*
+        * a0 = 2 (OSF)
+        * a1 = return address, but we give the asm the vaddr of the PCB
+        * a2 = physical addr of PCB
+        * a3 = new virtual page table pointer
+        * a4 = KSP (but we give it 0, asm sets it)
+        */
+       i = switch_to_osf_pal(
+               2,
+               pcb_va,
+               pcb_pa,
+               new_vptb,
+               0);
+       if (i) {
+               printk("failed, code %ld\n", i);
+               halt();
+       }
+       rev = percpu->pal_revision = percpu->palcode_avail[2];
+
+       hwrpb.vptb = new_vptb;
+
+       /* update checksum: */
+       sum = 0;
+       for (l = (unsigned long *) &hwrpb;
+            l < (unsigned long *) &hwrpb.chksum;
+            ++l)
+               sum += *l;
+       hwrpb.chksum = sum;
+
+       printk("Ok (rev %lx)\n", rev);
+       /* remove the old virtual page-table mapping */
+       L1[1] = 0;
+       flush_tlb_all();
+}
+
+static inline long load(unsigned long dst,
+                       unsigned long src,
+                       unsigned long count)
+{
+       extern void * memcpy(void *, const void *, size_t);
+
+       memcpy((void *)dst, (void *)src, count);
+       return count;
+}
+
+/*
+ * Start the kernel.
+ */
+static void runkernel(void)
+{
+       __asm__ __volatile__(
+               "bis %1,%1,$30\n\t"
+               "bis %0,%0,$26\n\t"
+               "ret ($26)"
+               : /* no outputs: it doesn't even return */
+               : "r" (START_ADDR),
+                 "r" (PAGE_SIZE + INIT_STACK));
+}
+
+extern char _end;
+#define KERNEL_ORIGIN \
+       ((((unsigned long)&_end) + 511) & ~511)
+
+void start_kernel(void)
+{
+       static long i;
+       static int nbytes;
+       static char envval[256];
+       char envbuf[256];
+
+       printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
+
+       if (hwrpb.pagesize != 8192) {
+               printk("Expected 8kB pages, got %ldkB\n",
+                      hwrpb.pagesize >> 10);
+               return;
+       }
+       pal_init();
+
+       nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
+                         envbuf, sizeof(envbuf));
+       if (nbytes < 0 || nbytes >= sizeof(envbuf)) {
+               nbytes = 0;
+       }
+
+       envbuf[nbytes] = '\0';
+       memcpy(envval, envbuf, nbytes+1);
+       printk("Loading the kernel...'%s'\n", envval);
+
+       /* NOTE: *no* callbacks or printouts from here on out!!! */
+
+       /*
+        * HACK alert:
+        *
+        * assume direct copy will fail due to overlap of virtual source
+        * and physical destination, so move it way high physical first,
+        * then move it back to its final resting place...
+        *
+        * this way could fail, too, but it works on the platforms *I* have
+        */
+       i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
+        i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
+
+       strcpy((char*)ZERO_PAGE, envval);
+
+       runkernel();
+
+       for (i = 0 ; i < 0x100000000 ; i++)
+               /* nothing */;
+       halt();
+}
index 3d6af2841855a42451afc69ada00654dc6a6d8e3..05cd3bdbd86106ec7f9d9344bc52f9322ab1c8b1 100644 (file)
@@ -6,8 +6,12 @@ mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
 # clear all implied options (don't want default values for those):
 unset CONFIG_CROSSCOMPILE CONFIG_NATIVE
-unset CONFIG_PCI CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS
+unset CONFIG_PCI CONFIG_ALPHA_EISA
+unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA CONFIG_ALPHA_T2
+unset CONFIG_ALPHA_PYXIS
+unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5
 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
+unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -43,49 +47,123 @@ choice 'Alpha system type' \
         EB64+          CONFIG_ALPHA_EB64P              \
         EB164          CONFIG_ALPHA_EB164              \
         PC164          CONFIG_ALPHA_PC164              \
+        LX164          CONFIG_ALPHA_LX164              \
+        SX164          CONFIG_ALPHA_SX164              \
         Jensen         CONFIG_ALPHA_JENSEN             \
         Noname         CONFIG_ALPHA_NONAME             \
+        Takara         CONFIG_ALPHA_TAKARA             \
         Mikasa         CONFIG_ALPHA_MIKASA             \
+        Noritake       CONFIG_ALPHA_NORITAKE           \
         Alcor          CONFIG_ALPHA_ALCOR              \
+        Miata          CONFIG_ALPHA_MIATA              \
+        Sable          CONFIG_ALPHA_SABLE              \
+        AlphaBook1     CONFIG_ALPHA_BOOK1              \
+        Ruffian        CONFIG_ALPHA_RUFFIAN            \
         Platform2000   CONFIG_ALPHA_P2K" Cabriolet
+
+if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
+then
+       define_bool CONFIG_ALPHA_NONAME y
+fi
 if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \
        -o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ]
 then
        define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_EV4 y
        define_bool CONFIG_ALPHA_LCA y
 fi
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-       -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
-       -o "$CONFIG_ALPHA_XL" = "y" ]
+       -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ]
 then
        define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_EV4 y
        define_bool CONFIG_ALPHA_APECS y
 fi
 if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-       -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" ]
+       -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \
+       -o "$CONFIG_ALPHA_TAKARA" = "y" ]
 then
        define_bool CONFIG_PCI y
        define_bool CONFIG_ALPHA_EV5 y
        define_bool CONFIG_ALPHA_CIA y
+fi
+if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+then
+       bool 'Pinnacle or Primo CPU daughtercard?' CONFIG_ALPHA_PRIMO
+       if [ "$CONFIG_ALPHA_PRIMO" = "y" ]
+       then
+               define_bool CONFIG_ALPHA_EV5 y
+               define_bool CONFIG_ALPHA_CIA y
+else
+               define_bool CONFIG_ALPHA_EV4 y
+               define_bool CONFIG_ALPHA_APECS y
+       fi
+       define_bool CONFIG_PCI y
+fi
+if [ "$CONFIG_ALPHA_SABLE" = "y" ]
+then
+       bool 'EV5 or EV56 CPU daughtercard?' CONFIG_ALPHA_GAMMA
+       if [ "$CONFIG_ALPHA_GAMMA" = "y" ]
+       then
+               define_bool CONFIG_ALPHA_EV5 y
 else
+               define_bool CONFIG_ALPHA_EV4 y
+       fi
+       define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_T2 y
+fi
+if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \
+        -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ]
+then
+       define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_EV5 y
+       define_bool CONFIG_ALPHA_PYXIS y
+fi
+if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
+then
+       define_bool CONFIG_ALPHA_EV4 y
+fi
+if [ "$CONFIG_ALPHA_EV4" = "y" ]
+then
        # EV45 and older do not support all rounding modes in hw:
        define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
        -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
-       -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" ]
+       -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
+       -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
+       -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
+       -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ]
 then
-       bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+  bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
+      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
+    fi
+  fi
+fi
+if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
+       -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+then
+       define_bool CONFIG_ALPHA_EISA y
 fi
 if [ "$CONFIG_ALPHA_XL" = "y" ]
 then
        define_bool CONFIG_ALPHA_AVANTI y
 fi
 
+bool 'Kernel GDB support' CONFIG_KGDB
+if [ "$CONFIG_KGDB" = "y" ]; then
+  bool 'Kernel tracing support?' CONFIG_KGDB_TRACING
+fi
+
 bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'TGA Console Support' CONFIG_TGA_CONSOLE
+  if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
+    bool 'VGA Console Support' CONFIG_VGA_CONSOLE
+  fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
   fi
@@ -94,6 +172,7 @@ bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 endmenu
 
 source drivers/block/Config.in
@@ -163,3 +242,7 @@ if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
+
+if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then
+  define_bool CONFIG_VGA_CONSOLE y
+fi
index 9f33eeaa45afe87be8031aec32651c73d053adeb..4f758e5b64fdc420b429650aeed38defaeea8b13 100644 (file)
@@ -36,12 +36,16 @@ CONFIG_PCI=y
 CONFIG_ALPHA_EV5=y
 CONFIG_ALPHA_CIA=y
 CONFIG_ALPHA_SRM=y
+CONFIG_KGDB=y
+CONFIG_KGDB_TRACING=n
 # CONFIG_SERIAL_ECHO is not set
 CONFIG_TGA_CONSOLE=y
+CONFIG_VGA_CONSOLE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_EM86=y
 
 #
 # Floppy, IDE, and other block devices
index 4aa11ce788622073df7e4044aa34d1998db6a22d..cac0ffe5a04b6c289e2dcf42aa51c705c84889db 100644 (file)
@@ -16,7 +16,12 @@ all: kernel.o head.o
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-           bios32.o ptrace.o time.o apecs.o lca.o cia.o ksyms.o
+           bios32.o ptrace.o time.o apecs.o lca.o cia.o t2.o pyxis.o \
+           ksyms.o smc.o
+
+ifdef CONFIG_KGDB
+O_OBJS += kgdb.o
+endif
 
 all: kernel.o head.o
 
index f4554bcc13a78371307f9f55e3969adaef01c3e4..c907454102b37ef4ba5c3c369b1cb3c607e0be0a 100644 (file)
@@ -20,7 +20,7 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
+
 /*
  * BIOS32-style PCI interface:
  */
@@ -33,13 +33,16 @@ extern int alpha_sys_type;
 # define DBG(args)
 #endif
 
-#define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int  *
 
 static volatile unsigned int apecs_mcheck_expected = 0;
 static volatile unsigned int apecs_mcheck_taken = 0;
-static unsigned long apecs_jd, apecs_jd1, apecs_jd2;
+static unsigned int apecs_jd, apecs_jd1, apecs_jd2;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT;
+unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -142,15 +145,15 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
        /* reset status register to avoid losing errors: */
-       stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
-       *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+       stat0 = *((vuip)APECS_IOC_DCSR);
+       *((vuip)APECS_IOC_DCSR) = stat0;
        mb();
        DBG(("conf_read: APECS DCSR was 0x%x\n", stat0));
        /* if Type1 access, must set HAE #2 */
        if (type1) {
-               haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+               haxr2 = *((vuip)APECS_IOC_HAXR2);
                mb();
-               *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+               *((vuip)APECS_IOC_HAXR2) = haxr2 | 1;
                DBG(("conf_read: TYPE1 access\n"));
        }
 
@@ -159,7 +162,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        apecs_mcheck_taken = 0;
        mb();
        /* access configuration space: */
-       value = *((volatile unsigned int *)addr);
+       value = *((vuip)addr);
        mb();
        mb();
        if (apecs_mcheck_taken) {
@@ -179,7 +182,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        draina();
 
        /* now look for any errors */
-       stat0 = *((unsigned int *)APECS_IOC_DCSR);
+       stat0 = *((vuip)APECS_IOC_DCSR);
        DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0));
        if (stat0 & 0xffe0U) { /* is any error bit set? */
                /* if not NDEV, print status */
@@ -188,7 +191,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
                }
 
                /* reset error status: */
-               *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+               *((vuip)APECS_IOC_DCSR) = stat0;
                mb();
                wrmces(0x7);                    /* reset machine check */
                value = 0xffffffff;
@@ -197,7 +200,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
 
        /* if Type1 access, must reset HAE #2 so normal IO space ops work */
        if (type1) {
-               *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+               *((vuip)APECS_IOC_HAXR2) = haxr2 & ~1;
                mb();
        }
        restore_flags(flags);
@@ -224,22 +227,22 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
        cli();
 
        /* reset status register to avoid losing errors: */
-       stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
-       *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
+       stat0 = *((vuip)APECS_IOC_DCSR);
+       *((vuip)APECS_IOC_DCSR) = stat0;
        mb();
 
        /* if Type1 access, must set HAE #2 */
        if (type1) {
-               haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
+               haxr2 = *((vuip)APECS_IOC_HAXR2);
                mb();
-               *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
+               *((vuip)APECS_IOC_HAXR2) = haxr2 | 1;
        }
 
        draina();
        apecs_mcheck_expected = 1;
        mb();
        /* access configuration space: */
-       *((volatile unsigned int *)addr) = value;
+       *((vuip)addr) = value;
        mb();
        mb();
        apecs_mcheck_expected = 0;
@@ -254,7 +257,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
        draina();
 
        /* now look for any errors */
-       stat0 = *((unsigned int *)APECS_IOC_DCSR);
+       stat0 = *((vuip)APECS_IOC_DCSR);
        if (stat0 & 0xffe0U) { /* is any error bit set? */
                /* if not NDEV, print status */
                if (!(stat0 & 0x0800)) {
@@ -262,7 +265,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
                }
 
                /* reset error status: */
-               *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
+               *((vuip)APECS_IOC_DCSR) = stat0;
                mb();
                wrmces(0x7);                    /* reset machine check */
        }
@@ -270,7 +273,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
 
        /* if Type1 access, must reset HAE #2 so normal IO space ops work */
        if (type1) {
-               *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
+               *((vuip)APECS_IOC_HAXR2) = haxr2 & ~1;
                mb();
        }
        restore_flags(flags);
@@ -417,6 +420,38 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)APECS_IOC_TB2R = 0;
 
 #else  /* CONFIG_ALPHA_XL */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 1 for enabled and mapped to 0 */
+       if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) && (*(vuip)APECS_IOC_TB1R == 0))
+       {
+         APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+         printk("apecs_init: using Window 1 settings\n");
+         printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n",
+                *(vuip)APECS_IOC_PB1R,
+                *(vuip)APECS_IOC_PM1R,
+                *(vuip)APECS_IOC_TB1R);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) && (*(vuip)APECS_IOC_TB2R == 0))
+       {
+         APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+         printk("apecs_init: using Window 2 settings\n");
+         printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n",
+                *(vuip)APECS_IOC_PB2R,
+                *(vuip)APECS_IOC_PM2R,
+                *(vuip)APECS_IOC_TB2R);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, window 2 is disabled.  In the future, we may
@@ -428,9 +463,11 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
        *(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
        *(vuip)APECS_IOC_TB1R  = 0;
+       }
 #endif /* CONFIG_ALPHA_XL */
 
 #ifdef CONFIG_ALPHA_CABRIOLET
+#if 0
        /*
         * JAE: HACK!!! for now, hardwire if configured...
         * davidm: Older miniloader versions don't set the clockfrequency
@@ -448,10 +485,13 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
            unsigned long *l, sum;
 
            sum = 0;
-           for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l)
+           for (l = (unsigned long *) hwrpb;
+                l < (unsigned long *) &hwrpb->chksum;
+                ++l)
              sum += *l;
            hwrpb->chksum = sum;
        }
+#endif
 #endif /* CONFIG_ALPHA_CABRIOLET */
 
        /*
@@ -462,10 +502,10 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
         */
        {
 #if 0
-         unsigned int haxr2 = *((unsigned int *)APECS_IOC_HAXR2); mb();
+         unsigned int haxr2 = *((vuip)APECS_IOC_HAXR2); mb();
          if (haxr2) printk("apecs_init: HAXR2 was 0x%x\n", haxr2);
 #endif
-         *((unsigned int *)APECS_IOC_HAXR2) = 0; mb();
+         *((vuip)APECS_IOC_HAXR2) = 0; mb();
        }
 
 
@@ -474,15 +514,15 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
 
 int apecs_pci_clr_err(void)
 {
-       apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+       apecs_jd = *((vuip)APECS_IOC_DCSR);
        if (apecs_jd & 0xffe0L) {
-               apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR);
-               *((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
-               apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
+               apecs_jd1 = *((vuip)APECS_IOC_SEAR);
+               *((vuip)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
+               apecs_jd = *((vuip)APECS_IOC_DCSR);
                mb();
        }
-       *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA;
-       apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA);
+       *((vuip)APECS_IOC_TBIA) = APECS_IOC_TBIA;
+       apecs_jd2 = *((vuip)APECS_IOC_TBIA);
        mb();
        return 0;
 }
@@ -526,8 +566,8 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
 #define MCHK_NO_DEVSEL 0x205L
 #define MCHK_NO_TABT 0x204L
        if (apecs_mcheck_expected &&
-           (((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_DEVSEL) ||
-            ((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_TABT))
+           (((unsigned int)mchk_header->code == MCHK_NO_DEVSEL) ||
+            ((unsigned int)mchk_header->code == MCHK_NO_TABT))
            )
        {
 #else
@@ -550,19 +590,21 @@ void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
                printk("apecs_machine_check: HW correctable (0x%lx)\n", vector);
        }
        else {
-               printk("APECS machine check:\n");
-               printk("  vector=0x%lx la_ptr=0x%lx\n",
+               printk(KERN_CRIT "APECS machine check:\n");
+               printk(KERN_CRIT "  vector=0x%lx la_ptr=0x%lx\n",
                       vector, la_ptr);
-               printk("  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+               printk(KERN_CRIT
+                      "  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
                       regs->pc, mchk_header->size, mchk_header->proc_offset,
                       mchk_header->sys_offset);
-               printk("  expected %d DCSR 0x%lx PEAR 0x%lx\n",
+               printk(KERN_CRIT "  expected %d DCSR 0x%lx PEAR 0x%lx\n",
                       apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
                       mchk_sysdata->epic_pear);
 
                ptr = (unsigned long *)la_ptr;
                for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
-                   printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+                   printk(KERN_CRIT " +%lx %lx %lx\n",
+                          i*sizeof(long), ptr[i], ptr[i+1]);
                }
 #if 0
                /* doesn't work with MILO */
index 2220552e0c7dabfe53d3728e2522901452057ae6..d05128960200ea55a4d8beb58683bf3c2b170492 100644 (file)
@@ -57,7 +57,7 @@ asmlinkage int sys_pciconfig_write()
 #include <asm/hwrpb.h>
 #include <asm/io.h>
 #include <asm/segment.h>
-
+#include <asm/dma.h>
 
 #define KB             1024
 #define MB             (1024*KB)
@@ -73,6 +73,8 @@ asmlinkage int sys_pciconfig_write()
 
 
 /*
+ * PCI_MODIFY
+ *
  * Temporary internal macro.  If this 0, then do not write to any of
  * the PCI registers, merely read them (i.e., use configuration as
  * determined by SRM).  The SRM seem do be doing a less than perfect
@@ -89,34 +91,72 @@ asmlinkage int sys_pciconfig_write()
  * the graphics card---there have been some rumor that the #9 BIOS
  * incorrectly resets that address to 0...).
  */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+#define PCI_MODIFY             0
+static struct pci_dev *irq_dev_to_reset[16];
+static unsigned char irq_to_reset[16];
+static int irq_reset_count = 0;
+static struct pci_dev *io_dev_to_reset[16];
+static unsigned char io_reg_to_reset[16];
+static unsigned int io_to_reset[16];
+static int io_reset_count = 0;
+#else /* SRM_SETUP */
 #define PCI_MODIFY             1
+#endif /* SRM_SETUP */
 
 extern struct hwrpb_struct *hwrpb;
 
-
 #if PCI_MODIFY
 
 /* NOTE: we can't just blindly use 64K for machines with EISA busses; they
    may also have PCI-PCI bridges present, and then we'd configure the bridge
    incorrectly */
-#if 0
-static unsigned int    io_base  = 64*KB;       /* <64KB are (E)ISA ports */
+/* NOTE also that we may need this stuff for SRM_SETUP also, since certain
+   SRM consoles screw up and allocate I/O space addresses > 64K behind
+   PCI-to_PCI bridges, which can't pass addresses larger than 64K... */
+#if defined(CONFIG_ALPHA_EISA)
+static unsigned int    io_base  = 0x9000;      /* start above 8th slot */
 #else
-static unsigned int    io_base  = 0xb000;
+static unsigned int    io_base  = 0x8000;
 #endif
 
 #if defined(CONFIG_ALPHA_XL)
 /*
-   an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
-   that get passed through the PCI<->ISA bridge chip. Because this causes
-   us to set the PCI->Mem window bases lower than normal, we've gotta allocate
-   PCI bus devices' memory addresses *above* the PCI<->memory mapping windows,
-   so that CPU memory DMA addresses issued by a bus device don't conflict
-   with bus memory addresses, like frame buffer memory for graphics cards.
+   An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address
+   that get passed through the PCI<->ISA bridge chip. Although this causes
+   us to set the PCI->Mem window bases lower than normal, we still allocate
+   PCI bus devices' memory addresses *below* the low DMA mapping window,
+   and hope they fit below 64Mb (to avoid conflicts), and so that they can
+   be accessed via SPARSE space.
+
+   We accept the risk that a broken Myrinet card will be put into a true XL
+   and thus can more easily run into the problem described below.
+*/
+static unsigned int    mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */
+
+#elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS)
+/*
+   We try to make this address *always* have more than 1 bit set.
+   this is so that devices like the broken Myrinet card will always have
+   a PCI memory address that will never match a IDSEL address in
+   PCI Config space, which can cause problems with early rev cards.
+
+   However, APECS and LCA have only 34 bits for physical addresses, thus
+   limiting PCI bus memory addresses for SPARSE access to be less than 128Mb.
 */
-static unsigned int    mem_base = 1024*MB;
-#else /* CONFIG_ALPHA_XL */
-static unsigned int    mem_base = 16*MB;       /* <16MB is ISA memory */
+static unsigned int    mem_base = 64*MB + 2*MB;
+
+#else
+/*
+   We try to make this address *always* have more than 1 bit set.
+   this is so that devices like the broken Myrinet card will always have
+   a PCI memory address that will never match a IDSEL address in
+   PCI Config space, which can cause problems with early rev cards.
+
+   Because CIA and PYXIS and T2 have more bits for physical addresses,
+   they support an expanded range of SPARSE memory addresses.
+*/
+static unsigned int    mem_base = 128*MB + 16*MB;
 #endif /* CONFIG_ALPHA_XL */
 
 /*
@@ -128,7 +168,7 @@ static void disable_dev(struct pci_dev *dev)
        struct pci_bus *bus;
        unsigned short cmd;
 
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#if defined(CONFIG_ALPHA_EISA)
        /*
         * HACK: the PCI-to-EISA bridge does not seem to identify
         *       itself as a bridge... :-(
@@ -139,6 +179,18 @@ static void disable_dev(struct pci_dev *dev)
         }
 #endif
 
+       /*
+        * we don't have code that will init the CYPRESS bridge correctly
+        * so we do the next best thing, and depend on the previous
+        * console code to do the right thing, and ignore it here... :-\
+        */
+       if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) {
+#if 0
+         printk("disable_dev: ignoring CYPRESS bridge...\n");
+#endif
+         return;
+       }
+
        bus = dev->bus;
        pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
@@ -160,7 +212,7 @@ static void layout_dev(struct pci_dev *dev)
        unsigned int base, mask, size, reg;
        unsigned int alignto;
 
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+#if defined(CONFIG_ALPHA_EISA)
        /*
         * HACK: the PCI-to-EISA bridge does not seem to identify
         *       itself as a bridge... :-(
@@ -171,10 +223,36 @@ static void layout_dev(struct pci_dev *dev)
         }
 #endif
 
+       /*
+        * we don't have code that will init the CYPRESS bridge correctly
+        * so we do the next best thing, and depend on the previous
+        * console code to do the right thing, and ignore it here... :-\
+        */
+       if ((dev->vendor == 0x1080) && (dev->device == 0xC693)) {
+#if 0
+         printk("layout_dev: ignoring CYPRESS bridge...\n");
+#endif
+         return;
+       }
+
        bus = dev->bus;
        pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
        for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+
+#ifdef NOT_NOW
+         if ((dev->vendor == 0x1080) && (dev->device == 0xC693) &&
+             ((PCI_FUNC(dev->devfn) == 1) || (PCI_FUNC(dev->devfn) == 2)))
+         { /* if primary or secondary IDE on the CYPRESS bridge */
+             if ((reg == PCI_BASE_ADDRESS_0) || (reg == PCI_BASE_ADDRESS_1)) {
+#if 0
+                 printk("layout_dev: ignoring CYPRESS IDE base reg 0/1\n");
+#endif
+                 continue; /* ignore first two registers */
+             }
+         }
+#endif /* NOT_NOW */
+
                /*
                 * Figure out how much space and of what type this
                 * device wants.
@@ -182,6 +260,10 @@ static void layout_dev(struct pci_dev *dev)
                pcibios_write_config_dword(bus->number, dev->devfn, reg,
                                           0xffffffff);
                pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
+#if 0
+printk("layout_dev: slot %d fn %d off 0x%x base 0x%x\n",
+       PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), reg, base);
+#endif
                if (!base) {
                        /* this base-address register is unused */
                        continue;
@@ -201,11 +283,23 @@ static void layout_dev(struct pci_dev *dev)
                        mask = (~base << 1) | 0x1;
                        size = (mask & base) & 0xffffffff;
                        /* align to multiple of size of minimum base */
+#if 0
                        alignto = MAX(0x400, size) ;
+#else
+                       /*
+                          If we align to 0x800 bounds, we probably avoid
+                          having devices in any 0xzCzz range, which is
+                          where the DE4X5 driver probes for EISA cards.
+                          Adaptecs, especially, resent such intrusions. :-(
+                       */
+                       alignto = MAX(0x800, size) ;
+#endif
                        base = ALIGN(io_base, alignto );
                        io_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn, 
                                                   reg, base | 0x1);
+                       DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n",
+                                 dev->device, base, size));
                } else {
                        unsigned int type;
                        /*
@@ -266,7 +360,7 @@ static void layout_dev(struct pci_dev *dev)
                        base = ALIGN(mem_base, alignto);
                        if (size > 7 * 16*MB) {
                                printk("bios32 WARNING: slot %d, function %d "
-                                      "requests  %dB of contiguous address "
+                                      "requests 0x%x bytes of contig address "
                                       " space---don't use sparse memory "
                                       " accesses on this device!!\n",
                                       PCI_SLOT(dev->devfn),
@@ -277,7 +371,8 @@ static void layout_dev(struct pci_dev *dev)
                                        base += 16*MB;
                                        base  = ALIGN(base, alignto);
                                }
-                               if (base / (128*MB) != (base + size) / (128*MB)) {
+                               if (base / (128*MB) != (base + size) / (128*MB))
+                               {
                                        base &= ~(128*MB - 1);
                                        base += (128 + 16)*MB;
                                        base  = ALIGN(base, alignto);
@@ -286,13 +381,15 @@ static void layout_dev(struct pci_dev *dev)
                        mem_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn,
                                                   reg, base);
+                       DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n",
+                                 dev->device, base, size));
                }
-        }
+       } /* end for-loop */
        /* enable device: */
        if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
            dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
-           dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
-           dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+           dev->class >>  8 == PCI_CLASS_STORAGE_IDE ||
+           dev->class >> 16 == PCI_BASE_CLASS_DISPLAY)
        {
                /*
                 * All of these (may) have I/O scattered all around
@@ -305,21 +402,24 @@ static void layout_dev(struct pci_dev *dev)
 
        pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
                                  cmd | PCI_COMMAND_MASTER);
-       DBG_DEVS(("layout_dev: bus %d  slot 0x%x  VID 0x%x  DID 0x%x  class 0x%x\n",
-                 bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
+
+       DBG_DEVS(("layout_dev: bus %d slot %d VID 0x%x DID 0x%x class 0x%x cmd 0x%x\n",
+                 bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
+                 dev->class, cmd|PCI_COMMAND_MASTER));
 }
 
 
-static void layout_bus(struct pci_bus *bus)
+static int layout_bus(struct pci_bus *bus)
 {
        unsigned int l, tio, bio, tmem, bmem;
        struct pci_bus *child;
        struct pci_dev *dev;
+       int found_vga = 0;
 
        DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
 
        if (!bus->devices && !bus->children)
-         return;
+         return 0;
 
        /*
         * Align the current bases on appropriate boundaries (4K for
@@ -338,7 +438,11 @@ static void layout_bus(struct pci_bus *bus)
         * decoders are programmed consistently.
         */
        for (dev = bus->devices; dev; dev = dev->sibling) {
-               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+                    || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+                   ) {
                        disable_dev(dev) ;
                }
        }
@@ -349,9 +453,15 @@ static void layout_bus(struct pci_bus *bus)
        DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
 
        for (dev = bus->devices; dev; dev = dev->sibling) {
-               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+                   || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+                   ) {
                        layout_dev(dev);
                }
+               if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+                       found_vga = 1;
        }
        /*
         * Recursively allocate space for all of the sub-buses:
@@ -359,7 +469,7 @@ static void layout_bus(struct pci_bus *bus)
        DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number));
 
        for (child = bus->children; child; child = child->next) {
-               layout_bus(child);
+               found_vga += layout_bus(child);
         }
        /*
         * Align the current bases on 4K and 1MB boundaries:
@@ -375,7 +485,8 @@ static void layout_bus(struct pci_bus *bus)
                 */
                pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
                                          0x1c, &l);
-               l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000);
+               l = (l & 0xffff0000) | ((bio >> 8) & 0x00f0) | 
+                   ((tio - 1) & 0xf000);
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
                                           0x1c, l);
                /*
@@ -391,10 +502,13 @@ static void layout_bus(struct pci_bus *bus)
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
                                           0x24, 0x0000ffff);
                /*
-                * Tell bridge that there is an ISA bus in the system:
+                * Tell bridge that there is an ISA bus in the system,
+                * and (possibly) a VGA as well.
                 */
+               l = 0x00040000; /* ISA present */
+               if (found_vga) l |= 0x00080000; /* VGA present */
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
-                                          0x3c, 0x00040000);
+                                          0x3c, l);
                /*
                 * Clear status bits, enable I/O (for downstream I/O),
                 * turn on master enable (for upstream I/O), turn on
@@ -404,6 +518,7 @@ static void layout_bus(struct pci_bus *bus)
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
                                           0x4, 0xffff0007);
        }
+       return found_vga;
 }
 
 #endif /* !PCI_MODIFY */
@@ -501,9 +616,9 @@ static inline void enable_ide(long ide_base)
 }
 
 /* 
- * A small note about bridges and interrupts.    The DECchip 21050 (and later chips)
- * adheres to the PCI-PCI bridge specification.   This says that the interrupts on
- * the other side of a bridge are swizzled in the following manner:
+ * A small note about bridges and interrupts. The DC 21050 (and later chips)
+ * adheres to the PCI-PCI bridge specification. This says that the interrupts
+ * on the other side of a bridge are swizzled in the following manner:
  *
  * Dev    Interrupt   Interrupt 
  *        Pin on      Pin on 
@@ -541,13 +656,86 @@ static inline unsigned char bridge_swizzle(unsigned char pin, unsigned int slot)
         return (((pin-1) + slot) % 4) + 1 ;
 }
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* look for mis-configured devices' IO space addresses behind bridges */
+static void check_behind_io(struct pci_dev *dev)
+{
+       struct pci_bus *bus = dev->bus;
+       unsigned int reg, orig_base, new_base, found_one = 0;
+
+       for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+               /* read the current setting, check for I/O space and >= 64K */
+               pcibios_read_config_dword(bus->number, dev->devfn, reg, &orig_base);
+               if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO))
+                       continue; /* unused or non-IO */
+               if (orig_base < 64*1024) {
+#if 1
+printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base);
+#endif
+                       if (orig_base & ~1)
+                         continue; /* OK! */
+                       orig_base = 0x12001; /* HACK! FIXME!! */
+               }
+
+               /* HACK ALERT! for now, just subtract 32K from the
+                  original address, which should give us addresses
+                  in the range 0x8000 and up */
+               new_base = orig_base - 0x8000;
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base, new_base);
+#endif
+               pcibios_write_config_dword(bus->number, dev->devfn,
+                                          reg, new_base);
+
+               io_dev_to_reset[io_reset_count] = dev;
+               io_reg_to_reset[io_reset_count] = reg;
+               io_to_reset[io_reset_count] = orig_base;
+               io_reset_count++;
+               found_one++;
+       } /* end for-loop */
+
+       /* if any were modified, gotta hack the bridge IO limits too... */
+       if (found_one) {
+           if (bus->self) {
+               struct pci_dev *bridge = bus->self;
+               unsigned int l;
+               /*
+                * Set up the top and bottom of the PCI I/O segment
+                * for this bus.
+                */
+               pcibios_read_config_dword(bridge->bus->number,
+                                         bridge->devfn, 0x1c, &l);
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n",
+       bus->number, PCI_SLOT(bridge->devfn), l);
+#endif
+               l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn, 0x1c, l);
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn,
+                                          0x3c, 0x00040000);
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn,
+                                          0x4, 0xffff0007);
+           } else
+               printk("check_behind_io: WARNING! bus->self NULL\n");
+       }
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+
 /*
  * Most evaluation boards share most of the fixup code, which is isolated here.
  * This function is declared "inline" as only one platform will ever be selected
  * in any given kernel.  If that platform doesn't need this code, we don't want
  * it around as dead code.
  */
-static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
+static inline void common_fixup(
+       long min_idsel,
+       long max_idsel,
+       long irqs_per_slot,
                                char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot],
                                long ide_base)
 {
@@ -559,37 +747,122 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
         * Go through all devices, fixing up irqs as we see fit:
         */
        for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE
-#if defined(CONFIG_ALPHA_MIKASA) || defined(CONFIG_ALPHA_ALCOR)
+               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+#if defined(CONFIG_ALPHA_EISA)
                    /* PCEB (PCI to EISA bridge) does not identify
                       itself as a bridge... :-( */
                    && !((dev->vendor==0x8086) && (dev->device==0x482))
 #endif
+#ifdef CONFIG_ALPHA_BOOK1
+                    || (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
                    ) {
                        dev->irq = 0;
                        /*
-                        * This device is not on the primary bus, we need to figure out which
-                        * interrupt pin it will come in on.   We know which slot it will come
-                        * in on 'cos that slot is where the bridge is.   Each time the interrupt
-                        * line passes through a PCI-PCI bridge we must apply the swizzle function
+                        * This device is not on the primary bus,
+                        * we need to figure out which
+                        * interrupt pin it will come in on.
+                        * We know which slot it will come
+                        * in on 'cuz that slot is where the bridge is.
+                        * Each time the interrupt
+                        * line passes through a PCI-PCI bridge
+                        * we must apply the swizzle function
                         * (see the inline static routine above).
                         */
                        if (dev->bus->number != 0) {
-                               struct pci_dev *curr = dev ;
-                               /* read the pin and do the PCI-PCI bridge interrupt pin swizzle */
-                               pcibios_read_config_byte(dev->bus->number, dev->devfn,
-                                                        PCI_INTERRUPT_PIN, &pin);
+                               /* read the pin and do the PCI-PCI bridge
+                                  interrupt pin swizzle */
+                               pcibios_read_config_byte(dev->bus->number,
+                                                        dev->devfn,
+                                                        PCI_INTERRUPT_PIN,
+                                                        &pin);
                                /* cope with 0 */
                                if (pin == 0) pin = 1 ;
-                               /* follow the chain of bridges, swizzling as we go */
+                               /* follow the chain of bridges,
+                                  swizzling as we go */
+#if defined(CONFIG_ALPHA_MIATA)
+                               /* check first for the built-in bridge */
+                               if ((PCI_SLOT(dev->bus->self->devfn) == 8) ||
+                                   (PCI_SLOT(dev->bus->self->devfn) == 20)) {
+                                 slot = PCI_SLOT(dev->devfn) + 9;
+#if 0
+                                 printk("MIATA: bus 1 slot %d pin %d irq %d "
+                                        "min_idsel %d\n",
+                                        PCI_SLOT(dev->devfn), pin,
+                                        irq_tab[slot - min_idsel][pin],
+                                        min_idsel);
+#endif
+                               }
+                               else /* must be a card-based bridge */
+                               {
+                                 struct pci_dev *curr = dev ;
                                do {
+                                 if ((PCI_SLOT(curr->bus->self->devfn) == 8) ||
+                                     (PCI_SLOT(curr->bus->self->devfn) == 20))
+                                   {
+                                     slot = PCI_SLOT(curr->devfn) + 5;
+                                     break;
+                                   }
                                        /* swizzle */
-                                       pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ;
+                                   pin = bridge_swizzle(
+                                                 pin, PCI_SLOT(curr->devfn)) ;
+                                   /* move up the chain of bridges */
+                                   curr = curr->bus->self ;
+                                   /* slot of the next bridge. */
+                                   slot = PCI_SLOT(curr->devfn);
+                                 } while (curr->bus->self) ;
+                               }
+#elif defined(CONFIG_ALPHA_NORITAKE)
+                               /* check first for the built-in bridge */
+                               if (PCI_SLOT(dev->bus->self->devfn) == 8) {
+                                 slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */
+#if 0
+                                 printk("NORITAKE: bus 1 slot %d pin %d "
+                                        "irq %d min_idsel %d\n",
+                                        PCI_SLOT(dev->devfn), pin,
+                                        irq_tab[slot - min_idsel][pin],
+                                        min_idsel);
+#endif
+                               }
+                               else /* must be a card-based bridge */
+                               {
+                                 struct pci_dev *curr = dev ;
+                                 do {
+                                   if (PCI_SLOT(curr->bus->self->devfn) == 8) {
+                                     slot = PCI_SLOT(curr->devfn) + 15;
+                                     break;
+                                   }
+                                   /* swizzle */
+                                   pin = bridge_swizzle(
+                                               pin, PCI_SLOT(curr->devfn)) ;
+                                   /* move up the chain of bridges */
+                                   curr = curr->bus->self ;
+                                   /* slot of the next bridge. */
+                                   slot = PCI_SLOT(curr->devfn);
+                                 } while (curr->bus->self) ;
+                               }
+#else /* not MIATA or NORITAKE */
+                               {
+                                 struct pci_dev *curr = dev ;
+                                 do {
+                                       /* swizzle */
+                                       pin = bridge_swizzle(
+                                                 pin, PCI_SLOT(curr->devfn)) ;
                                        /* move up the chain of bridges */
                                        curr = curr->bus->self ;
                                } while (curr->bus->self) ;
                                /* The slot is the slot of the last bridge. */
                                slot = PCI_SLOT(curr->devfn) ;
+                               }
+#endif /* not MIATA or NORITAKE */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+                               /*
+                                 must make sure that SRM didn't screw up
+                                 and allocate an address > 64K for I/O
+                                 space behind a PCI-PCI bridge
+                               */
+                               check_behind_io(dev);
+#endif /* CONFIG_ALPHA_SRM_SETUP */
                        } else {
                                /* work out the slot */
                                slot = PCI_SLOT(dev->devfn) ;
@@ -601,28 +874,193 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
                        }
                        if (irq_tab[slot - min_idsel][pin] != -1)
                                dev->irq = irq_tab[slot - min_idsel][pin];
-#if PCI_MODIFY
-                       /* tell the device: */
+
+#ifdef CONFIG_ALPHA_SRM
+                       {
+                         unsigned char irq_orig;
+                         /* read the original SRM-set IRQ and tell */
+                         pcibios_read_config_byte(dev->bus->number,
+                                                   dev->devfn,
+                                                   PCI_INTERRUPT_LINE,
+                                                   &irq_orig);
+                         if (irq_orig != dev->irq) {
+                           printk("common_fixup: bus %d slot 0x%x "
+                                  "SRM IRQ 0x%x changed to 0x%x\n",
+                                  dev->bus->number,PCI_SLOT(dev->devfn),
+                                  irq_orig, dev->irq);
+#ifdef CONFIG_ALPHA_SRM_SETUP
+                           irq_dev_to_reset[irq_reset_count] = dev;
+                           irq_to_reset[irq_reset_count] = irq_orig;
+                           irq_reset_count++;
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+                         }
+                       }
+#endif /* SRM */
+
+                       /* always tell the device, so the driver knows */
                        pcibios_write_config_byte(dev->bus->number, dev->devfn,
                                                  PCI_INTERRUPT_LINE, dev->irq);
-#endif
+
+       DBG_DEVS(("common_fixup: bus %d  slot 0x%x  VID 0x%x  DID 0x%x\n"
+                 "              int_slot 0x%x  pin 0x%x  irq 0x%x\n",
+                 dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+                 dev->device, slot, pin, dev->irq));
+
                        /*
                         * if it's a VGA, enable its BIOS ROM at C0000
                         */
                        if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
-                         pcibios_write_config_dword(dev->bus->number,
+                         /* but if its a Cirrus 543x/544x DISABLE it, */
+                         /* since enabling ROM disables the memory... */
+                         if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+                             (dev->device >= 0x00a0) &&
+                             (dev->device <= 0x00ac)) {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
+                                       dev->devfn,
+                                       PCI_ROM_ADDRESS,
+                                       0x00000000);
+                         } else {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
                                                     dev->devfn,
                                                     PCI_ROM_ADDRESS,
                                                     0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
                        }
                }
-
+                       /*
+                        * if it's a SCSI, disable its BIOS ROM
+                        */
+                       if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
+                         pcibios_write_config_dword(dev->bus->number,
+                                                    dev->devfn,
+                                                    PCI_ROM_ADDRESS,
+                                                    0x0000000);
+                       }
+#ifdef NOT_NOW
+                       if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+                        && (PCI_FUNC(dev->devfn) == 1))
+                       {
+#if 0
+{
+int i; unsigned char b; unsigned short w; unsigned int d;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 1: PCI CMD reg = 0x%x\n", w);
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w);
+ printk("common_fixup: CYPRESS fn 1: PCI STS reg = 0x%x\n", w);
+ for (i = 0x10; i <= 0x14; i+=4) {
+   pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,d);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d);
+ printk("common_fixup: CYPRESS fn 1: PCI register offset 0x20 = 0x%x\n", d);
+ for (i = 0x3c; i <= 0x3d; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b);
+   printk("common_fixup: CYPRESS fn 1: PCI register offset 0x%x = 0x%x\n",i,b);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d);
+ printk("common_fixup: CYPRESS fn 1: PCI register offset 0x40 = 0x%x\n",d);
+}
+#endif
+                       }
+                       if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+                        && (PCI_FUNC(dev->devfn) == 2))
+                       {
+#if 0
+{
+int i; unsigned char b; unsigned short w; unsigned int d;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 2: PCI CMD reg = 0x%x\n", w);
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 6, &w);
+ printk("common_fixup: CYPRESS fn 2: PCI STS reg = 0x%x\n", w);
+ for (i = 0x10; i <= 0x14; i+=4) {
+   pcibios_read_config_dword(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,d);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x20, &d);
+ printk("common_fixup: CYPRESS fn 2: PCI register offset 0x20 = 0x%x\n", d);
+ for (i = 0x3c; i <= 0x3d; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &b);
+   printk("common_fixup: CYPRESS fn 2: PCI register offset 0x%x = 0x%x\n",i,b);
+ }
+ pcibios_read_config_dword(dev->bus->number, dev->devfn, 0x40, &d);
+ printk("common_fixup: CYPRESS fn 2: PCI register offset 0x40 = 0x%x\n",d);
+}
+#endif
+                       }
+#endif /* NOT_NOW */
+               } else { /* it *is* a bridge... */
+#ifdef NOT_NOW
+                       /*
+                        * if it's CYPRESS PCI-ISA bridge, disable IDE
+                        *  interrupt routing through PCI (ie do through PIC)
+                        */
+                       if ((dev->vendor == 0x1080) && (dev->device == 0xC693)
+                        && (PCI_FUNC(dev->devfn) == 0))
+                       {
+#if 0
+{
+int i; unsigned char d; unsigned short w;
+ pcibios_read_config_word(dev->bus->number, dev->devfn, 4, &w);
+ printk("common_fixup: CYPRESS fn 0: PCI CMD reg = 0x%x\n", w);
+ for (i = 0x40; i < 0x50; i++) {
+   pcibios_read_config_byte(dev->bus->number, dev->devfn, i, &d);
+   printk("common_fixup: CYPRESS fn 0: PCI register offset 0x%x = 0x%x\n",
+         i, d);
+ }
+ for (i=1; i <= 5; i++) {
+   outb(i, 0x22);
+   printk("CY control reg %d: 0x%02x\n", i, inb(0x23));
+ }
+}
+#endif
+#if 0
+                         pcibios_write_config_word(dev->bus->number,
+                                                   dev->devfn, 0x04, 0x0007);
+
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x40, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x41, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x42, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x43, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x44, 0x27);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x45, 0xe0);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x48, 0xf0);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x49, 0x40);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x4a, 0x00);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x4b, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x4c, 0x80);
+                         pcibios_write_config_byte(dev->bus->number,
+                                                   dev->devfn, 0x4d, 0x70);
+#endif
+                         outb(0, DMA1_RESET_REG);
+                         outb(0, DMA2_RESET_REG);
+                         outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
+                         outb(0, DMA2_MASK_REG);
+#if 0
+                         outb(0, DMA1_CLR_MASK_REG);
+                         outb(0, DMA2_CLR_MASK_REG);
+#endif
+                       }
+#endif /* NOT_NOW */
+               }
        }
        if (ide_base) {
                enable_ide(ide_base);
        }
 }
 
+
 /*
  * The EB66+ is very similar to the EB66 except that it does not have
  * the on-board NCR and Tulip chips.  In the code below, I have used
@@ -639,6 +1077,7 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
 static inline void eb66p_fixup(void)
 {
        char irq_tab[5][5] = {
+          /*INT  INTA  INTB  INTC   INTD */
                {16+0, 16+0, 16+5,  16+9, 16+13},       /* IdSel 6,  slot 0, J25 */
                {16+1, 16+1, 16+6, 16+10, 16+14},       /* IdSel 7,  slot 1, J26 */
                {  -1,   -1,   -1,    -1,    -1},       /* IdSel 8,  SIO         */
@@ -650,7 +1089,7 @@ static inline void eb66p_fixup(void)
 
 
 /*
- * The PC164 has 19 PCI interrupts, four from each of the four PCI
+ * The PC164/LX164 have 19 PCI interrupts, four from each of the four PCI
  * slots, the SIO, PCI/IDE, and USB.
  * 
  * Each of the interrupts can be individually masked. This is
@@ -693,12 +1132,9 @@ static inline void eb66p_fixup(void)
 
 static inline void alphapc164_fixup(void)
 {
-       extern int SMCInit(void);
+       extern void SMC93X_Init(void);
        char irq_tab[7][5] = {
-         /*
-          *      int   intA  intB   intC   intD
-          *      ----  ----  ----   ----   ----
-          */
+          /*INT   INTA  INTB   INTC   INTD */
                { 16+2, 16+2, 16+9,  16+13, 16+17},     /* IdSel  5,  slot 2, J20 */
                { 16+0, 16+0, 16+7,  16+11, 16+15},     /* IdSel  6,  slot 0, J29 */
                { 16+1, 16+1, 16+8,  16+12, 16+16},     /* IdSel  7,  slot 1, J26 */
@@ -710,7 +1146,7 @@ static inline void alphapc164_fixup(void)
 
        common_fixup(5, 11, 5, irq_tab, 0);
 
-       SMCInit();
+       SMC93X_Init();
 }
 
 /*
@@ -729,6 +1165,7 @@ static inline void alphapc164_fixup(void)
 static inline void cabriolet_fixup(void)
 {
        char irq_tab[5][5] = {
+          /*INT   INTA  INTB  INTC   INTD */
                { 16+2, 16+2, 16+7, 16+11, 16+15},      /* IdSel 5,  slot 2, J21 */
                { 16+0, 16+0, 16+5,  16+9, 16+13},      /* IdSel 6,  slot 0, J19 */
                { 16+1, 16+1, 16+6, 16+10, 16+14},      /* IdSel 7,  slot 1, J20 */
@@ -785,6 +1222,7 @@ static inline void cabriolet_fixup(void)
 static inline void eb66_and_eb64p_fixup(void)
 {
        char irq_tab[5][5] = {
+          /*INT  INTA  INTB  INTC   INTD */
                {16+7, 16+7, 16+7, 16+7,  16+7},        /* IdSel 5,  slot ?, ?? */
                {16+0, 16+0, 16+2, 16+4,  16+9},        /* IdSel 6,  slot ?, ?? */
                {16+1, 16+1, 16+3, 16+8, 16+10},        /* IdSel 7,  slot ?, ?? */
@@ -796,7 +1234,7 @@ static inline void eb66_and_eb64p_fixup(void)
 
 
 /*
- * Fixup configuration for MIKASA (NORITAKE is different)
+ * Fixup configuration for MIKASA
  *
  * Summary @ 0x536:
  * Bit      Meaning
@@ -847,6 +1285,86 @@ static inline void mikasa_fixup(void)
        common_fixup(6, 13, 5, irq_tab, 0);
 }
 
+/*
+ * Fixup configuration for NORITAKE
+ *
+ * Summary @ 0x542, summary register #1:
+ * Bit      Meaning
+ * 0        All valid ints from summary regs 2 & 3
+ * 1        QLOGIC ISP1020A SCSI
+ * 2        Interrupt Line A from slot 0
+ * 3        Interrupt Line B from slot 0
+ * 4        Interrupt Line A from slot 1
+ * 5        Interrupt line B from slot 1
+ * 6        Interrupt Line A from slot 2
+ * 7        Interrupt Line B from slot 2
+ * 8        Interrupt Line A from slot 3
+ * 9        Interrupt Line B from slot 3
+ *10        Interrupt Line A from slot 4
+ *11        Interrupt Line B from slot 4
+ *12        Interrupt Line A from slot 5
+ *13        Interrupt Line B from slot 5
+ *14        Interrupt Line A from slot 6
+ *15        Interrupt Line B from slot 6
+ *
+ * Summary @ 0x544, summary register #2:
+ * Bit      Meaning
+ * 0        OR of all unmasked ints in SR #2
+ * 1        OR of secondary bus ints
+ * 2        Interrupt Line C from slot 0
+ * 3        Interrupt Line D from slot 0
+ * 4        Interrupt Line C from slot 1
+ * 5        Interrupt line D from slot 1
+ * 6        Interrupt Line C from slot 2
+ * 7        Interrupt Line D from slot 2
+ * 8        Interrupt Line C from slot 3
+ * 9        Interrupt Line D from slot 3
+ *10        Interrupt Line C from slot 4
+ *11        Interrupt Line D from slot 4
+ *12        Interrupt Line C from slot 5
+ *13        Interrupt Line D from slot 5
+ *14        Interrupt Line C from slot 6
+ *15        Interrupt Line D from slot 6
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  7       Intel PCI-EISA bridge chip
+ *  8       DEC PCI-PCI bridge chip
+ * 11       PCI on board slot 0
+ * 12       PCI on board slot 1
+ * 13       PCI on board slot 2
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+static inline void noritake_fixup(void)
+{
+       char irq_tab[15][5] = {
+         /*INT    INTA   INTB   INTC   INTD */
+         /* note: IDSELs 16, 17, and 25 are CORELLE only */
+          { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 17,  S3 Trio64 */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 18,  PCEB */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 19,  PPB  */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 20,  ???? */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 21,  ???? */
+         { 16+2,  16+2,  16+3,  32+2,  32+3},  /* IdSel 22,  slot 0 */
+         { 16+4,  16+4,  16+5,  32+4,  32+5},  /* IdSel 23,  slot 1 */
+         { 16+6,  16+6,  16+7,  32+6,  32+7},  /* IdSel 24,  slot 2 */
+         { 16+8,  16+8,  16+9,  32+8,  32+9},  /* IdSel 25,  slot 3 */
+         /* the following 5 are actually on PCI bus 1, across the bridge */
+          { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
+          { 16+8,  16+8,  16+9,  32+8,  32+9},  /* IdSel 17,  slot 3 */
+          {16+10, 16+10, 16+11, 32+10, 32+11},  /* IdSel 18,  slot 4 */
+          {16+12, 16+12, 16+13, 32+12, 32+13},  /* IdSel 19,  slot 5 */
+          {16+14, 16+14, 16+15, 32+14, 32+15},  /* IdSel 20,  slot 6 */
+       };
+       common_fixup(5, 19, 5, irq_tab, 0);
+}
+
 /*
  * Fixup configuration for ALCOR
  *
@@ -892,8 +1410,10 @@ static inline void mikasa_fixup(void)
  */
 static inline void alcor_fixup(void)
 {
-       char irq_tab[6][5] = {
+       char irq_tab[7][5] = {
          /*INT    INTA   INTB   INTC   INTD */
+         /* note: IDSEL 17 is XLT only */
+         {16+13, 16+13, 16+13, 16+13, 16+13},  /* IdSel 17,  TULIP  */
          { 16+8,  16+8,  16+9, 16+10, 16+11},  /* IdSel 18,  slot 0 */
          {16+16, 16+16, 16+17, 16+18, 16+19},  /* IdSel 19,  slot 3 */
          {16+12, 16+12, 16+13, 16+14, 16+15},  /* IdSel 20,  slot 4 */
@@ -901,9 +1421,10 @@ static inline void alcor_fixup(void)
          { 16+0,  16+0,  16+1,  16+2,  16+3},  /* IdSel 22,  slot 2 */
          { 16+4,  16+4,  16+5,  16+6,  16+7},  /* IdSel 23,  slot 1 */
        };
-       common_fixup(7, 12, 5, irq_tab, 0);
+       common_fixup(6, 12, 5, irq_tab, 0);
 }
 
+#if 0
 /*
  * Fixup configuration for ALPHA XLT (EV5/EV56)
  *
@@ -959,7 +1480,303 @@ static inline void xlt_fixup(void)
        };
        common_fixup(6, 12, 5, irq_tab, 0);
 }
+#endif /* 0 */
 
+/*
+ * Fixup configuration for ALPHA SABLE (2100) - 2100A is different ??
+ *
+ * Summary Registers (536/53a/53c):
+ * Bit      Meaning
+ *-----------------
+ * 0        PCI slot 0
+ * 1        NCR810 (builtin)
+ * 2        TULIP (builtin)
+ * 3        mouse
+ * 4        PCI slot 1
+ * 5        PCI slot 2
+ * 6        keyboard
+ * 7        floppy
+ * 8        COM2
+ * 9        parallel port
+ *10        EISA irq 3
+ *11        EISA irq 4
+ *12        EISA irq 5
+ *13        EISA irq 6
+ *14        EISA irq 7
+ *15        COM1
+ *16        EISA irq 9
+ *17        EISA irq 10
+ *18        EISA irq 11
+ *19        EISA irq 12
+ *20        EISA irq 13
+ *21        EISA irq 14
+ *22        NC
+ *23        IIC
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  0       TULIP
+ *  1       SCSI
+ *  2       PCI-EISA bridge
+ *  3       none
+ *  4       none
+ *  5       none
+ *  6       PCI on board slot 0
+ *  7       PCI on board slot 1
+ *  8       PCI on board slot 2
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent
+   with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables
+   in irq.c
+ */
+static inline void sable_fixup(void)
+{
+        char irq_tab[9][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+          { 32+0,  32+0,  32+0,  32+0,  32+0},  /* IdSel 0,  TULIP  */
+          { 32+1,  32+1,  32+1,  32+1,  32+1},  /* IdSel 1,  SCSI   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 2,  SIO   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 3,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 4,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 5,  none   */
+          { 32+2,  32+2,  32+2,  32+2,  32+2},  /* IdSel 6,  slot 0 */
+          { 32+3,  32+3,  32+3,  32+3,  32+3},  /* IdSel 7,  slot 1 */
+          { 32+4,  32+4,  32+4,  32+4,  32+4},  /* IdSel 8,  slot 2 */
+        };
+        common_fixup(0, 8, 5, irq_tab, 0);
+}
+
+/*
+ * Fixup configuration for MIATA (EV56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit      Meaning
+ * 0        Fan Fault
+ * 1        NMI
+ * 2        Halt/Reset switch
+ * 3        none
+ * 4        CID0 (Riser ID)
+ * 5        CID1 (Riser ID)
+ * 6        Interval timer
+ * 7        PCI-ISA Bridge
+ * 8        Ethernet
+ * 9        EIDE (deprecated, ISA 14/15 used)
+ *10        none
+ *11        USB
+ *12        Interrupt Line A from slot 4
+ *13        Interrupt Line B from slot 4
+ *14        Interrupt Line C from slot 4
+ *15        Interrupt Line D from slot 4
+ *16        Interrupt Line A from slot 5
+ *17        Interrupt line B from slot 5
+ *18        Interrupt Line C from slot 5
+ *19        Interrupt Line D from slot 5
+ *20        Interrupt Line A from slot 1
+ *21        Interrupt Line B from slot 1
+ *22        Interrupt Line C from slot 1
+ *23        Interrupt Line D from slot 1
+ *24        Interrupt Line A from slot 2
+ *25        Interrupt Line B from slot 2
+ *26        Interrupt Line C from slot 2
+ *27        Interrupt Line D from slot 2
+ *27        Interrupt Line A from slot 3
+ *29        Interrupt Line B from slot 3
+ *30        Interrupt Line C from slot 3
+ *31        Interrupt Line D from slot 3
+ *
+ * The device to slot mapping looks like:
+ *
+ * Slot     Device
+ *  3       DC21142 Ethernet
+ *  4       EIDE CMD646
+ *  5       none
+ *  6       USB
+ *  7       PCI-ISA bridge
+ *  8       PCI-PCI Bridge      (SBU Riser)
+ *  9       none
+ * 10       none
+ * 11       PCI on board slot 4 (SBU Riser)
+ * 12       PCI on board slot 5 (SBU Riser)
+ *
+ *  These are behind the bridge, so I'm not sure what to do...
+ *
+ * 13       PCI on board slot 1 (SBU Riser)
+ * 14       PCI on board slot 2 (SBU Riser)
+ * 15       PCI on board slot 3 (SBU Riser)
+ *   
+ *
+ * This two layered interrupt approach means that we allocate IRQ 16 and 
+ * above for PCI interrupts.  The IRQ relates to which bit the interrupt
+ * comes in on.  This makes interrupt processing much easier.
+ */
+static inline void miata_fixup(void)
+{
+       extern int es1888_init(void);
+       extern void SMC669_Init(void); /* might be a MiataGL */
+        char irq_tab[18][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+          {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8},  /* IdSel 14,  DC21142/3 */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 15,  EIDE   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 16,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 17,  none   */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 18,  PCI-ISA */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 19,  PCI-PCI old */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 20,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 21,  none    */
+          {16+12, 16+12, 16+13, 16+14, 16+15},  /* IdSel 22,  slot 4 */
+          {16+16, 16+16, 16+17, 16+18, 16+19},  /* IdSel 23,  slot 5 */
+         /* the following 7 are actually on PCI bus 1, across the bridge */
+         {16+11, 16+11, 16+11, 16+11, 16+11},  /* IdSel 24,  QLISP on GL  */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 25,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 26,  none    */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 27,  none    */
+          {16+20, 16+20, 16+21, 16+22, 16+23},  /* IdSel 28,  slot 1 */
+          {16+24, 16+24, 16+25, 16+26, 16+27},  /* IdSel 29,  slot 2 */
+          {16+28, 16+28, 16+29, 16+30, 16+31},  /* IdSel 30,  slot 3 */
+         /* this bridge is on the main bus of the later original MIATA */
+          {   -1,    -1,    -1,    -1,    -1},  /* IdSel 31,  PCI-PCI new */
+        };
+       common_fixup(3, 20, 5, irq_tab, 0);
+       SMC669_Init(); /* might be a MiataGL, so try to find one of these */
+       es1888_init();
+}
+
+/*
+ * Fixup configuration for SX164 (PCA56+PYXIS)
+ *
+ * Summary @ PYXIS_INT_REQ:
+ * Bit      Meaning
+ * 0        RSVD
+ * 1        NMI
+ * 2        Halt/Reset switch
+ * 3        MBZ
+ * 4        RAZ
+ * 5        RAZ
+ * 6        Interval timer (RTC)
+ * 7        PCI-ISA Bridge
+ * 8        Interrupt Line A from slot 3
+ * 9        Interrupt Line A from slot 2
+ *10        Interrupt Line A from slot 1
+ *11        Interrupt Line A from slot 0
+ *12        Interrupt Line B from slot 3
+ *13        Interrupt Line B from slot 2
+ *14        Interrupt Line B from slot 1
+ *15        Interrupt line B from slot 0
+ *16        Interrupt Line C from slot 3
+ *17        Interrupt Line C from slot 2
+ *18        Interrupt Line C from slot 1
+ *19        Interrupt Line C from slot 0
+ *20        Interrupt Line D from slot 3
+ *21        Interrupt Line D from slot 2
+ *22        Interrupt Line D from slot 1
+ *23        Interrupt Line D from slot 0
+ *
+ * IdSel       
+ *   5  32 bit PCI option slot 2
+ *   6  64 bit PCI option slot 0
+ *   7  64 bit PCI option slot 1
+ *   8  Cypress I/O
+ *   9  32 bit PCI option slot 3
+ * 
+ */
+
+static inline void sx164_fixup(void)
+{
+       extern void SMC669_Init(void);
+       char irq_tab[5][5] = {
+          /*INT    INTA   INTB   INTC   INTD */
+         { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */
+         { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */
+         { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */
+         {    -1,    -1,    -1,    -1,    -1}, /* IdSel 8 SIO        */
+         { 16+ 8, 16+ 8, 16+12, 16+16, 16+20}  /* IdSel 9 slot 3 J15 */
+       };
+
+       common_fixup(5, 9, 5, irq_tab, 0);
+
+       SMC669_Init();
+}
+
+static inline void ruffian_fixup(void)
+{
+       struct pci_dev *dev;
+
+       /*
+        * Go through all devices
+        */
+       for (dev = pci_devices; dev; dev = dev->next) {
+               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+                       /*
+                        * if it's a VGA, enable its BIOS ROM at C0000
+                        */
+                       if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+                         /* but if its a Cirrus 543x/544x DISABLE it, */
+                         /* since enabling ROM disables the memory... */
+                          if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+                              (dev->device >= 0x00a0) &&
+                              (dev->device <= 0x00ac)) {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
+                                       dev->devfn,
+                                       PCI_ROM_ADDRESS,
+                                       0x00000000);
+                         } else {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
+                                       dev->devfn,
+                                       PCI_ROM_ADDRESS,
+                                       0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+                         }
+                       }
+                       /*
+                        * if it's a SCSI, disable its BIOS ROM
+                        */
+                       if ((dev->class >> 8) == PCI_CLASS_STORAGE_SCSI) {
+                         pcibios_write_config_dword(dev->bus->number,
+                                                    dev->devfn,
+                                                    PCI_ROM_ADDRESS,
+                                                    0x0000000);
+                       }
+               }
+       }
+}
+
+/*
+ * The Takara has PCI devices 1, 2, and 3 configured to slots 20,
+ * 19, and 18 respectively, in the default configuration. They can
+ * also be jumpered to slots 8, 7, and 6 respectively, which is fun
+ * because the SIO ISA bridge can also be slot 7. However, the SIO
+ * doesn't explicitly generate PCI-type interrupts, so we can
+ * assign it whatever the hell IRQ we like and it doesn't matter.
+ */
+static inline void takara_fixup(void)
+{
+       char irq_tab[15][5] = {
+           { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
+           { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot  7 == device 2 */
+           { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot  8 == device 1 */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot  9 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 10 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 11 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 12 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 13 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 14 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 15 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 16 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 17 == nothing */
+           { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot 18 == device 3 */
+           { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot 19 == device 2 */
+           { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot 20 == device 1 */
+       };
+
+       common_fixup(6, 20, 5, irq_tab, 0x26e);
+}
 
 /*
  * Fixup configuration for all boards that route the PCI interrupts
@@ -1029,7 +1846,12 @@ static inline void sio_fixup(void)
         *  they are co-indicated when the platform type "Noname" is
         *  selected... :-(
         */
+#ifdef CONFIG_ALPHA_BOOK1
+        /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */
+        const unsigned int route_tab = 0x0e0f0a0a;
+#else /* CONFIG_ALPHA_BOOK1 */
        const unsigned int route_tab = 0x0b0a0f09;
+#endif  /* CONFIG_ALPHA_BOOK1 */
 #else /* CONFIG_ALPHA_NONAME */
        const unsigned int route_tab = 0x0b0a090f;
 #endif /* CONFIG_ALPHA_NONAME */
@@ -1044,7 +1866,11 @@ static inline void sio_fixup(void)
         */
        level_bits = 0;
        for (dev = pci_devices; dev; dev = dev->next) {
-               if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE)
+               if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE)
+#ifdef CONFIG_ALPHA_BOOK1
+                    && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)
+#endif /* CONFIG_ALPHA_BOOK1 */
+                    )
                        continue;
                dev->irq = 0;
                if (dev->bus->number != 0) {
@@ -1076,16 +1902,17 @@ static inline void sio_fixup(void)
 
                if (slot < 6 || slot >= 6 + sizeof(pirq_tab)/sizeof(pirq_tab[0])) {
                        printk("bios32.sio_fixup: "
-                              "weird, found device %04x:%04x in non-existent slot %d!!\n",
+                              "weird, found device %04x:%04x "
+                              "in non-existent slot %d!!\n",
                               dev->vendor, dev->device, slot);
                        continue;
                }
                pirq = pirq_tab[slot - 6][pin];
 
                DBG_DEVS(("sio_fixup: bus %d  slot 0x%x  VID 0x%x  DID 0x%x\n"
-                         "           int_slot 0x%x  int_pin 0x%x,  pirq 0x%x\n",
-                         dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
-                         slot, pin, pirq));
+                         "           int_slot 0x%x  pin 0x%x  pirq 0x%x\n",
+                         dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor,
+                         dev->device, slot, pin, pirq));
                /*
                 * if it's a VGA, enable its BIOS ROM at C0000
                 */
@@ -1107,15 +1934,51 @@ static inline void sio_fixup(void)
 
                dev->irq = (route_tab >> (8 * pirq)) & 0xff;
 
+#ifndef CONFIG_ALPHA_BOOK1
+                /* do not set *ANY* level triggers for AlphaBook1 */
                /* must set the PCI IRQs to level triggered */
                level_bits |= (1 << dev->irq);
+#endif /* !CONFIG_ALPHA_BOOK1 */
 
 #if PCI_MODIFY
                /* tell the device: */
                pcibios_write_config_byte(dev->bus->number, dev->devfn,
                                          PCI_INTERRUPT_LINE, dev->irq);
 #endif
+
+#ifdef CONFIG_ALPHA_BOOK1
+                /*
+                 * on the AlphaBook1, the PCMCIA chip (Cirrus 6729)
+                 * is sensitive to PCI bus bursts, so we must DISABLE
+                 * burst mode for the NCR 8xx SCSI... :-(
+                *
+                * Note that the NCR810 SCSI driver must preserve the
+                *  setting of the bit in order for this to work. At the
+                *  moment (2.0.29), ncr53c8xx.c does NOT do this, but
+                *  53c7,8xx.c DOES...
+                 */
+                if ((dev->vendor == PCI_VENDOR_ID_NCR) &&
+                    ((dev->device == PCI_DEVICE_ID_NCR_53C810) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C815) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C820) ||
+                     (dev->device == PCI_DEVICE_ID_NCR_53C825)
+                     )) {
+                   unsigned int io_port;
+                   unsigned char ctest4;
+
+                    pcibios_read_config_dword(dev->bus->number, dev->devfn,
+                                              PCI_BASE_ADDRESS_0, &io_port);
+                    io_port &= PCI_BASE_ADDRESS_IO_MASK;
+                    ctest4 = inb(io_port+0x21);
+                    if (!(ctest4 & 0x80)) {
+                       printk("AlphaBook1 NCR init: setting burst disable\n");
+                        outb(ctest4 | 0x80, io_port+0x21);
+                    }
        }
+#endif /* CONFIG_ALPHA_BOOK1 */
+
+       } /* end for devs */
+
        /*
         * Now, make all PCI interrupts level sensitive.  Notice:
         * these registers must be accessed byte-wise.  inw()/outw()
@@ -1125,21 +1988,43 @@ static inline void sio_fixup(void)
         *  so that the only bits getting set are for devices actually found.
         * Note that we do preserve the remainder of the bits, which we hope
         *  will be set correctly by ARC/SRM.
+        *
+        * Note: we at least preserve any level-set bits on AlphaBook1
         */
        level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff);
        outb((level_bits >> 0) & 0xff, 0x4d0);
        outb((level_bits >> 8) & 0xff, 0x4d1);
+
+#ifdef CONFIG_ALPHA_BOOK1
+        {
+         unsigned char orig, config;
+         /* on the AlphaBook1, make sure that register PR1 indicates 1Mb mem */
+         outb(0x0f, 0x3ce); orig = inb(0x3cf); /* read PR5  */
+         outb(0x0f, 0x3ce); outb(0x05, 0x3cf); /* unlock PR0-4 */
+         outb(0x0b, 0x3ce); config = inb(0x3cf); /* read PR1 */
+         if ((config & 0xc0) != 0xc0) {
+            printk("AlphaBook1 VGA init: setting 1Mb memory\n");
+            config |= 0xc0;
+            outb(0x0b, 0x3ce); outb(config, 0x3cf); /* write PR1 */
+         }
+         outb(0x0f, 0x3ce); outb(orig, 0x3cf); /* (re)lock PR0-4 */
+        }
+#endif /* CONFIG_ALPHA_BOOK1 */
+
+#ifndef CONFIG_ALPHA_BOOK1
+        /* do not do IDE init for AlphaBook1 */
        enable_ide(0x26e);
+#endif /* !CONFIG_ALPHA_BOOK1 */
 }
 
 
 #ifdef CONFIG_TGA_CONSOLE
-extern void tga_console_init(void);
+extern void tga_console_find(void);
 #endif /* CONFIG_TGA_CONSOLE */
 
 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
-#if PCI_MODIFY
+#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN)
        /*
         * Scan the tree, allocating PCI memory and I/O space.
         */
@@ -1153,7 +2038,7 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
        sio_fixup();
 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164)
        cabriolet_fixup();
-#elif defined(CONFIG_ALPHA_PC164)
+#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
        alphapc164_fixup();
 #elif defined(CONFIG_ALPHA_EB66P)
        eb66p_fixup();
@@ -1163,16 +2048,26 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
        eb66_and_eb64p_fixup();
 #elif defined(CONFIG_ALPHA_MIKASA)
        mikasa_fixup();
-#elif defined(CONFIG_ALPHA_ALCOR)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
        alcor_fixup();
-#elif defined(CONFIG_ALPHA_XLT)
-       xlt_fixup();
+#elif defined(CONFIG_ALPHA_SABLE)
+       sable_fixup();
+#elif defined(CONFIG_ALPHA_MIATA)
+       miata_fixup();
+#elif defined(CONFIG_ALPHA_NORITAKE)
+       noritake_fixup();
+#elif defined(CONFIG_ALPHA_SX164)
+       sx164_fixup();
+#elif defined(CONFIG_ALPHA_TAKARA)
+       takara_fixup();
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+       ruffian_fixup();
 #else
 #      error You must tell me what kind of platform you want.
 #endif
 
 #ifdef CONFIG_TGA_CONSOLE
-        tga_console_init();
+        tga_console_find();
 #endif /* CONFIG_TGA_CONSOLE */
 
        return mem_start;
@@ -1282,262 +2177,117 @@ asmlinkage int sys_pciconfig_write(
        }
         return err;
 }
-#ifdef CONFIG_ALPHA_PC164
-
-/* device "activate" register contents */
-#define DEVICE_ON              1
-#define DEVICE_OFF             0
-
-/* configuration on/off keys */
-#define CONFIG_ON_KEY          0x55
-#define CONFIG_OFF_KEY         0xaa
-
-/* configuration space device definitions */
-#define FDC                    0
-#define IDE1                   1
-#define IDE2                   2
-#define PARP                   3
-#define SER1                   4
-#define SER2                   5
-#define RTCL                   6
-#define KYBD                   7
-#define AUXIO                  8
-
-/* Chip register offsets from base */
-#define CONFIG_CONTROL         0x02
-#define INDEX_ADDRESS          0x03
-#define LOGICAL_DEVICE_NUMBER  0x07
-#define DEVICE_ID              0x20
-#define DEVICE_REV             0x21
-#define POWER_CONTROL          0x22
-#define POWER_MGMT             0x23
-#define OSC                    0x24
-
-#define ACTIVATE               0x30
-#define ADDR_HI                        0x60
-#define ADDR_LO                        0x61
-#define INTERRUPT_SEL          0x70
-#define INTERRUPT_SEL_2                0x72 /* KYBD/MOUS only */
-#define DMA_CHANNEL_SEL                0x74 /* FDC/PARP only */
-
-#define FDD_MODE_REGISTER      0x90
-#define FDD_OPTION_REGISTER    0x91
-
-/* values that we read back that are expected ... */
-#define VALID_DEVICE_ID                2
-
-/* default device addresses */
-#define KYBD_INTERRUPT         1
-#define MOUS_INTERRUPT         12
-#define COM2_BASE              0x2f8
-#define COM2_INTERRUPT         3
-#define COM1_BASE              0x3f8
-#define COM1_INTERRUPT         4
-#define PARP_BASE              0x3bc
-#define PARP_INTERRUPT         7
-
-#define SMC_DEBUG 0
-
-unsigned long SMCConfigState( unsigned long baseAddr )
-{
-    unsigned char devId;
-    unsigned char devRev;
-
-    unsigned long configPort;
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    configPort = indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )configPort + 1 );
-
-    outb(CONFIG_ON_KEY, configPort);
-    outb(CONFIG_ON_KEY, configPort);
-    outb(DEVICE_ID, indexPort);
-    devId = inb(dataPort);
-    if ( devId == VALID_DEVICE_ID ) {
-        outb(DEVICE_REV, indexPort);
-        devRev = inb(dataPort);
-    }
-    else {
-        baseAddr = 0;
-    }
-    return( baseAddr );
-}
-
-void SMCRunState( unsigned long baseAddr )
-{
-    outb(CONFIG_OFF_KEY, baseAddr);
-}
 
-unsigned long SMCDetectUltraIO(void)
-{
-    unsigned long baseAddr;
-
-    baseAddr = 0x3F0;
-    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
-        return( baseAddr );
-    }
-    baseAddr = 0x370;
-    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
-        return( baseAddr );
-    }
-    return( ( unsigned long )0 );
-}
+#if (defined(CONFIG_ALPHA_PC164) || \
+     defined(CONFIG_ALPHA_LX164) || \
+     defined(CONFIG_ALPHA_SX164) || \
+     defined(CONFIG_ALPHA_EB164) || \
+     defined(CONFIG_ALPHA_EB66P) || \
+     defined(CONFIG_ALPHA_CABRIOLET)) && defined(CONFIG_ALPHA_SRM)
 
-void SMCEnableDevice( unsigned long baseAddr,
-                     unsigned long device,
-                     unsigned long portaddr,
-                     unsigned long interrupt)
+/*
+  on the above machines, under SRM console, we must use the CSERVE PALcode
+  routine to manage the interrupt mask for us, otherwise, the kernel/HW get
+  out of sync with what the PALcode thinks it needs to deliver/ignore
+ */
+void
+cserve_update_hw(unsigned long irq, unsigned long mask)
 {
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(device, dataPort);
-
-    outb(ADDR_LO, indexPort);
-    outb(( portaddr & 0xFF ), dataPort);
-
-    outb(ADDR_HI, indexPort);
-    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
+    extern void cserve_ena(unsigned long);
+    extern void cserve_dis(unsigned long);
 
-    outb(INTERRUPT_SEL, indexPort);
-    outb(interrupt, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
+    if (mask & (1UL << irq))
+       /* disable */
+       cserve_dis(irq - 16);
+    else
+      /* enable */
+       cserve_ena(irq - 16);
+    return;
 }
+#endif /* (PC164 || LX164 || SX164 || EB164 || CABRIO) && SRM */
 
-void SMCEnableKYBD( unsigned long baseAddr )
-{
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+#ifdef CONFIG_ALPHA_MIATA
 
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(KYBD, dataPort);
-
-    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
-    outb(KYBD_INTERRUPT, dataPort);
-
-    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
-    outb(MOUS_INTERRUPT, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
-}
-
-void SMCEnableFDC( unsigned long baseAddr )
+/* init the built-in ES1888 sound chip (SB16 compatible) */
+int es1888_init(void)
 {
-    unsigned long indexPort;
-    unsigned long dataPort;
-
-    unsigned char oldValue;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
-
-    outb(LOGICAL_DEVICE_NUMBER, indexPort);
-    outb(FDC, dataPort);
-
-    outb(FDD_MODE_REGISTER, indexPort);
-    oldValue = inb(dataPort);
-
-    oldValue |= 0x0E;                   /* Enable burst mode */
-    outb(oldValue, dataPort);
-
-    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
-    outb(0x06, dataPort );
-
-    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
-    outb(0x02, dataPort);
-
-    outb(ACTIVATE, indexPort);
-    outb(DEVICE_ON, dataPort);
+    /* sequence of IO reads to init the audio controller */
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x0229);
+    inb(0x022b);
+    inb(0x0229);
+    inb(0x0220); /* this sets the base address to 0x220 */
+
+    /* sequence to set DMA channels */
+    outb(0x01, 0x0226); /* reset */
+    inb(0x0226); /* pause */
+    outb(0x00, 0x0226); /* release reset */
+    while (!(inb(0x022e) & 0x80)) /* wait for bit 7 to assert*/
+        continue;
+    inb(0x022a); /* pause */
+    outb(0xc6, 0x022c); /* enable extended mode */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0xb1, 0x022c); /* setup for write to Interrupt CR */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0x14, 0x022c); /* set IRQ 5 */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0xb2, 0x022c); /* setup for write to DMA CR */
+    while (inb(0x022c) & 0x80) /* wait for bit 7 to deassert */
+        continue;
+    outb(0x18, 0x022c); /* set DMA channel 1 */
+
+    return 0;
 }
 
-#if SMC_DEBUG
-void SMCReportDeviceStatus( unsigned long baseAddr )
-{
-    unsigned long indexPort;
-    unsigned long dataPort;
-    unsigned char currentControl;
-
-    indexPort = baseAddr;
-    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+#endif /* CONFIG_ALPHA_MIATA */
 
-    outb(POWER_CONTROL, indexPort);
-    currentControl = inb(dataPort);
-
-    if ( currentControl & ( 1 << FDC ) )
-        printk( "\t+FDC Enabled\n" );
-    else
-        printk( "\t-FDC Disabled\n" );
-
-    if ( currentControl & ( 1 << IDE1 ) )
-        printk( "\t+IDE1 Enabled\n" );
-    else
-        printk( "\t-IDE1 Disabled\n" );
-
-    if ( currentControl & ( 1 << IDE2 ) )
-        printk( "\t+IDE2 Enabled\n" );
-    else
-        printk( "\t-IDE2 Disabled\n" );
-
-    if ( currentControl & ( 1 << PARP ) )
-        printk( "\t+PARP Enabled\n" );
-    else
-        printk( "\t-PARP Disabled\n" );
-
-    if ( currentControl & ( 1 << SER1 ) )
-        printk( "\t+SER1 Enabled\n" );
-    else
-        printk( "\t-SER1 Disabled\n" );
-
-    if ( currentControl & ( 1 << SER2 ) )
-        printk( "\t+SER2 Enabled\n" );
-    else
-        printk( "\t-SER2 Disabled\n" );
-
-    printk( "\n" );
-}
-#endif
-
-int SMCInit(void)
+#ifdef CONFIG_ALPHA_SRM_SETUP
+void reset_for_srm(void)
 {
-    unsigned long SMCUltraBase;
-
-    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
-        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
-               SMCUltraBase );
-#if SMC_DEBUG
-        SMCReportDeviceStatus( SMCUltraBase );
-#endif
-        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
-        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
-        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
-       /* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */
-        SMCEnableKYBD( SMCUltraBase );
-        SMCEnableFDC( SMCUltraBase );
-#if SMC_DEBUG
-        SMCReportDeviceStatus( SMCUltraBase );
+       extern void scrreset(void);
+       struct pci_dev *dev;
+       int i;
+
+       /* reset any IRQs that we changed */
+       for (i = 0; i < irq_reset_count; i++) {
+           dev = irq_dev_to_reset[i];
+
+           pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                     PCI_INTERRUPT_LINE, irq_to_reset[i]);
+#if 1
+           printk("reset_for_srm: bus %d slot 0x%x "
+                  "SRM IRQ 0x%x changed back from 0x%x\n",
+                  dev->bus->number, PCI_SLOT(dev->devfn),
+                  irq_to_reset[i], dev->irq);
 #endif
-        SMCRunState( SMCUltraBase );
-        return( 1 );
-    }
-    else {
-#if SMC_DEBUG
-        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
+       }
+
+       /* reset any IO addresses that we changed */
+       for (i = 0; i < io_reset_count; i++) {
+           dev = io_dev_to_reset[i];
+
+           pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                     io_reg_to_reset[i], io_to_reset[i]);
+#if 1
+           printk("reset_for_srm: bus %d slot 0x%x "
+                  "SRM IO restored to 0x%x\n",
+                  dev->bus->number, PCI_SLOT(dev->devfn),
+                  io_to_reset[i]);
 #endif
-        return( 0 );
-    }
 }
 
-#endif /* CONFIG_ALPHA_PC164 */
+       /* reset the visible screen to the top of display memory */
+       scrreset();
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
 
 #endif /* CONFIG_PCI */
index ea59808e43295f9f4b0d462106639c1b82384d14..6b4648bfd3af46ccd7bd454902c238cdc1ccbf3f 100644 (file)
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
+
+/*
+ * Machine check reasons.  Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR           0x0080
+#define MCHK_K_TCPERR          0x0082
+#define MCHK_K_HERR            0x0084
+#define MCHK_K_ECC_C           0x0086
+#define MCHK_K_ECC_NC          0x0088
+#define MCHK_K_OS_BUGCHECK     0x008A
+#define MCHK_K_PAL_BUGCHECK    0x0090
+
 /*
  * BIOS32-style PCI interface:
  */
 
 #ifdef CONFIG_ALPHA_CIA
 
-#ifdef DEBUG 
-# define DBG(args)     printk args
+/* #define DEBUG_MCHECK */
+/* #define DEBUG_CONFIG */
+/* #define DEBUG_DUMP_REGS */
+
+#ifdef DEBUG_MCHECK
+# define DBGM(args)    printk args
 #else
-# define DBG(args)
+# define DBGM(args)
+#endif
+#ifdef DEBUG_CONFIG
+# define DBGC(args)    printk args
+#else
+# define DBGC(args)
 #endif
 
-#define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int  *
 
 static volatile unsigned int CIA_mcheck_expected = 0;
 static volatile unsigned int CIA_mcheck_taken = 0;
-static unsigned long CIA_jd, CIA_jd1, CIA_jd2;
+static unsigned int CIA_jd;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT;
+unsigned int CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT;
+unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -88,7 +113,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
 {
        unsigned long addr;
 
-       DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+       DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
             bus, device_fn, where, pci_addr, type1));
 
        if (bus == 0) {
@@ -97,7 +122,8 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
                /* type 0 configuration cycle: */
 
                if (device > 20) {
-                       DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device));
+                       DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n",
+                            device));
                        return -1;
                }
 
@@ -109,7 +135,7 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
                addr = (bus << 16) | (device_fn << 8) | (where);
        }
        *pci_addr = addr;
-       DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+       DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
        return 0;
 }
 
@@ -120,22 +146,25 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        unsigned int stat0, value;
        unsigned int cia_cfg = 0; /* to keep gcc quiet */
 
+       value = 0xffffffffU;
+       mb();
+
        save_flags(flags);      /* avoid getting hit by machine check */
        cli();
 
-       DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+       DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
        /* reset status register to avoid losing errors: */
-       stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
-       *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+       stat0 = *((vuip)CIA_IOC_CIA_ERR);
+       *((vuip)CIA_IOC_CIA_ERR) = stat0;
        mb();
-       DBG(("conf_read: CIA ERR was 0x%x\n", stat0));
+       DBGC(("conf_read: CIA ERR was 0x%x\n", stat0));
        /* if Type1 access, must set CIA CFG */
        if (type1) {
-               cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+               cia_cfg = *((vuip)CIA_IOC_CFG);
+               *((vuip)CIA_IOC_CFG) = cia_cfg | 1;
                mb();
-               *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
-               DBG(("conf_read: TYPE1 access\n"));
+               DBGC(("conf_read: TYPE1 access\n"));
        }
 
        mb();
@@ -144,7 +173,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        CIA_mcheck_taken = 0;
        mb();
        /* access configuration space: */
-       value = *((volatile unsigned int *)addr);
+       value = *((vuip)addr);
        mb();
        mb();
        if (CIA_mcheck_taken) {
@@ -154,39 +183,14 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        }
        CIA_mcheck_expected = 0;
        mb();
-       /*
-        * david.rusling@reo.mts.dec.com.  This code is needed for the
-        * EB64+ as it does not generate a machine check (why I don't
-        * know).  When we build kernels for one particular platform
-        * then we can make this conditional on the type.
-        */
-#if 0
-       draina();
-
-       /* now look for any errors */
-       stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
-       DBG(("conf_read: CIA ERR after read 0x%x\n", stat0));
-       if (stat0 & 0x8280U) { /* is any error bit set? */
-               /* if not NDEV, print status */
-               if (!(stat0 & 0x0080)) {
-                       printk("CIA.c:conf_read: got stat0=%x\n", stat0);
-               }
-
-               /* reset error status: */
-               *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
-               mb();
-               wrmces(0x7);                    /* reset machine check */
-               value = 0xffffffff;
-       }
-#endif
 
        /* if Type1 access, must reset IOC CFG so normal IO space ops work */
        if (type1) {
-               *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+               *((vuip)CIA_IOC_CFG) = cia_cfg & ~1;
                mb();
        }
 
-       DBG(("conf_read(): finished\n"));
+       DBGC(("conf_read(): finished\n"));
 
        restore_flags(flags);
        return value;
@@ -203,60 +207,36 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
        cli();
 
        /* reset status register to avoid losing errors: */
-       stat0 = *((volatile unsigned int *)CIA_IOC_CIA_ERR);
-       *((volatile unsigned int *)CIA_IOC_CIA_ERR) = stat0;
+       stat0 = *((vuip)CIA_IOC_CIA_ERR);
+       *((vuip)CIA_IOC_CIA_ERR) = stat0;
        mb();
-       DBG(("conf_write: CIA ERR was 0x%x\n", stat0));
+       DBGC(("conf_write: CIA ERR was 0x%x\n", stat0));
        /* if Type1 access, must set CIA CFG */
        if (type1) {
-               cia_cfg = *((unsigned int *)CIA_IOC_CFG);
+               cia_cfg = *((vuip)CIA_IOC_CFG);
+               *((vuip)CIA_IOC_CFG) = cia_cfg | 1;
                mb();
-               *((unsigned int *)CIA_IOC_CFG) = cia_cfg | 1;
-               DBG(("conf_read: TYPE1 access\n"));
+               DBGC(("conf_write: TYPE1 access\n"));
        }
 
        draina();
        CIA_mcheck_expected = 1;
        mb();
        /* access configuration space: */
-       *((volatile unsigned int *)addr) = value;
-       mb();
+       *((vuip)addr) = value;
        mb();
-       CIA_mcheck_expected = 0;
        mb();
-       /*
-        * david.rusling@reo.mts.dec.com.  This code is needed for the
-        * EB64+ as it does not generate a machine check (why I don't
-        * know).  When we build kernels for one particular platform
-        * then we can make this conditional on the type.
-        */
-#if 0
-       draina();
-
-       /* now look for any errors */
-       stat0 = *((unsigned int *)CIA_IOC_CIA_ERR);
-       DBG(("conf_write: CIA ERR after write 0x%x\n", stat0));
-       if (stat0 & 0x8280U) { /* is any error bit set? */
-               /* if not NDEV, print status */
-               if (!(stat0 & 0x0080)) {
-                       printk("CIA.c:conf_read: got stat0=%x\n", stat0);
-               }
 
-               /* reset error status: */
-               *((volatile unsigned long *)CIA_IOC_CIA_ERR) = stat0;
+       CIA_mcheck_expected = 0;
                mb();
-               wrmces(0x7);                    /* reset machine check */
-               value = 0xffffffff;
-       }
-#endif
 
        /* if Type1 access, must reset IOC CFG so normal IO space ops work */
        if (type1) {
-               *((unsigned int *)CIA_IOC_CFG) = cia_cfg & ~1;
+               *((vuip)CIA_IOC_CFG) = cia_cfg & ~1;
                mb();
        }
 
-       DBG(("conf_write(): finished\n"));
+       DBGC(("conf_write(): finished\n"));
        restore_flags(flags);
 }
 
@@ -377,16 +357,135 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
 
 unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
 {
-        unsigned int cia_err ;
+        unsigned int cia_tmp;
+
+#ifdef DEBUG_DUMP_REGS
+       {
+          unsigned int temp;
+#if 1
+         temp = *((vuip)CIA_IOC_CIA_REV); mb();
+          printk("CIA_init: CIA_REV was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PCI_LAT); mb();
+          printk("CIA_init: CIA_PCI_LAT was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CIA_CTRL); mb();
+          printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
+         temp = *((vuip)0xfffffc8740000140UL); mb();
+          printk("CIA_init: CIA_CTRL1 was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_HAE_MEM); mb();
+          printk("CIA_init: CIA_HAE_MEM was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_HAE_IO); mb();
+          printk("CIA_init: CIA_HAE_IO was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CFG); mb();
+          printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CACK_EN); mb();
+          printk("CIA_init: CIA_CACK_EN was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CFG); mb();
+          printk("CIA_init: CIA_CFG was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CIA_DIAG); mb();
+          printk("CIA_init: CIA_DIAG was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_DIAG_CHECK); mb();
+          printk("CIA_init: CIA_DIAG_CHECK was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PERF_MONITOR); mb();
+          printk("CIA_init: CIA_PERF_MONITOR was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PERF_CONTROL); mb();
+          printk("CIA_init: CIA_PERF_CONTROL was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CIA_ERR); mb();
+          printk("CIA_init: CIA_ERR was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_CIA_STAT); mb();
+          printk("CIA_init: CIA_STAT was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_MCR); mb();
+          printk("CIA_init: CIA_MCR was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_ERR_MASK); mb();
+          printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp);
+#endif
+         temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb();
+          printk("CIA_init: W0_BASE was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb();
+          printk("CIA_init: W1_BASE was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb();
+          printk("CIA_init: W2_BASE was 0x%x\n", temp);
+         temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb();
+          printk("CIA_init: W3_BASE was 0x%x\n", temp);
+       }
+#endif /* DEBUG_DUMP_REGS */
 
         /* 
         * Set up error reporting.
         */
-       cia_err = *(vuip)CIA_IOC_CIA_ERR ;
-       cia_err |= (0x1 << 7) ;   /* master abort */
-       *(vuip)CIA_IOC_CIA_ERR = cia_err ;
+       cia_tmp = *(vuip)CIA_IOC_CIA_ERR;
+       cia_tmp |= 0x180 ;   /* master, target abort */
+       *(vuip)CIA_IOC_CIA_ERR = cia_tmp ;
        mb() ;
 
+       cia_tmp = *(vuip)CIA_IOC_CIA_CTRL;
+       cia_tmp |= 0x400;   /* turn on FILL_ERR to get mchecks */
+       *(vuip)CIA_IOC_CIA_CTRL = cia_tmp ;
+       mb() ;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T0_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 0 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W0_BASE,
+                *(vuip)CIA_IOC_PCI_W0_MASK,
+                *(vuip)CIA_IOC_PCI_T0_BASE);
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T1_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 1 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W1_BASE,
+                *(vuip)CIA_IOC_PCI_W1_MASK,
+                *(vuip)CIA_IOC_PCI_T1_BASE);
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T2_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 2 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W2_BASE,
+                *(vuip)CIA_IOC_PCI_W2_MASK,
+                *(vuip)CIA_IOC_PCI_T2_BASE);
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T3_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 3 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W3_BASE,
+                *(vuip)CIA_IOC_PCI_W3_MASK,
+                *(vuip)CIA_IOC_PCI_T3_BASE);
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, windows 1,2 and 3 are disabled.  In the future, we may
@@ -401,6 +500,7 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)CIA_IOC_PCI_W1_BASE = 0x0 ;
        *(vuip)CIA_IOC_PCI_W2_BASE = 0x0 ;
        *(vuip)CIA_IOC_PCI_W3_BASE = 0x0 ;
+       }
 
        /*
         * check ASN in HWRPB for validity, report if bad
@@ -412,17 +512,44 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
        }
 
         /*
-         * Finally, clear the CIA_CFG register, which gets used
+         *  Next, clear the CIA_CFG register, which gets used
          *  for PCI Config Space accesses. That is the way
          *  we want to use it, and we do not want to depend on
          *  what ARC or SRM might have left behind...
          */
         {
+          unsigned int cia_cfg = *((vuip)CIA_IOC_CFG); mb();
+          if (cia_cfg) {
+             printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+             *((vuip)CIA_IOC_CFG) = 0; mb();
+         }
+        }
+        {
+          unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+          unsigned int cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
 #if 0
-          unsigned int cia_cfg = *((unsigned int *)CIA_IOC_CFG); mb();
-          if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+         printk("CIA_init: HAE_MEM was 0x%x\n", cia_hae_mem);
+         printk("CIA_init: HAE_IO was 0x%x\n", cia_hae_io);
 #endif
-          *((unsigned int *)CIA_IOC_CFG) = 0; mb();
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+           sigh... For the SRM setup, unless we know apriori what the HAE
+           contents will be, we need to setup the arbitrary region bases
+           so we can test against the range of addresses and tailor the
+           region chosen for the SPARSE memory access.
+
+           see include/asm-alpha/cia.h for the SPARSE mem read/write
+         */
+         cia_sm_base_r1 = (cia_hae_mem      ) & 0xe0000000UL; /* region 1 */
+         cia_sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; /* region 2 */
+         cia_sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; /* region 3 */
+#else /* SRM_SETUP */
+         *((vuip)CIA_IOC_HAE_MEM) = 0; mb();
+         cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+         *((vuip)CIA_IOC_HAE_IO) = 0; mb();
+         cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
+#endif /* SRM_SETUP */
         }
  
        return mem_start;
@@ -430,9 +557,9 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
 
 int cia_pci_clr_err(void)
 {
-       CIA_jd = *((unsigned int *)CIA_IOC_CIA_ERR);
-       DBG(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
-       *((unsigned long *)CIA_IOC_CIA_ERR) = 0x0080;
+       CIA_jd = *((vuip)CIA_IOC_CIA_ERR);
+       DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
+       *((vuip)CIA_IOC_CIA_ERR) = 0x0180;
        mb();
        return 0;
 }
@@ -440,41 +567,45 @@ int cia_pci_clr_err(void)
 void cia_machine_check(unsigned long vector, unsigned long la_ptr,
                         struct pt_regs * regs)
 {
-#if 0
-        printk("CIA machine check ignored\n") ;
-#else
        struct el_common *mchk_header;
+       struct el_procdata *mchk_procdata;
        struct el_CIA_sysdata_mcheck *mchk_sysdata;
+       unsigned long * ptr;
+       const char * reason;
+       char buf[128];
+       long i;
 
        mchk_header = (struct el_common *)la_ptr;
-
+       mchk_procdata =
+               (struct el_procdata *)(la_ptr + mchk_header->proc_offset);
        mchk_sysdata = 
          (struct el_CIA_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
 
-       DBG(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
-       DBG(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+       DBGM(("cia_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
+       DBGM(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
             regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
-       DBG(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+       DBGM(("cia_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
             CIA_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
-#ifdef DEBUG
+#ifdef DEBUG_MCHECK
        {
            unsigned long *ptr;
            int i;
 
            ptr = (unsigned long *)la_ptr;
            for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
-               printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+                       printk(" +%lx %lx %lx\n", i*sizeof(long),
+                              ptr[i], ptr[i+1]);
            }
        }
-#endif /* DEBUG */
+#endif /* DEBUG_MCHECK */
        /*
         * Check if machine check is due to a badaddr() and if so,
         * ignore the machine check.
         */
        mb();
        mb();
-       if (CIA_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
-               DBG(("CIA machine check expected\n"));
+       if (CIA_mcheck_expected) {
+               DBGM(("CIA machine check expected\n"));
                CIA_mcheck_expected = 0;
                CIA_mcheck_taken = 1;
                mb();
@@ -483,12 +614,58 @@ void cia_machine_check(unsigned long vector, unsigned long la_ptr,
                cia_pci_clr_err();
                wrmces(0x7);
                mb();
+               return;
+       }
+
+       switch ((unsigned int) mchk_header->code) {
+             case MCHK_K_TPERR:        reason = "tag parity error"; break;
+             case MCHK_K_TCPERR:       reason = "tag control parity error"; break;
+             case MCHK_K_HERR:         reason = "generic hard error"; break;
+             case MCHK_K_ECC_C:        reason = "correctable ECC error"; break;
+             case MCHK_K_ECC_NC:       reason = "uncorrectable ECC error"; break;
+             case MCHK_K_OS_BUGCHECK:  reason = "OS-specific PAL bugcheck"; break;
+             case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break;
+             case 0x96: reason = "i-cache read retryable error"; break;
+             case 0x98: reason = "processor detected hard error"; break;
+
+               /* system specific (these are for Alcor, at least): */
+             case 0x203: reason = "system detected uncorrectable ECC error"; break;
+             case 0x205: reason = "parity error detected by CIA"; break;
+             case 0x207: reason = "non-existent memory error"; break;
+             case 0x209: reason = "PCI SERR detected"; break;
+             case 0x20b: reason = "PCI data parity error detected"; break;
+             case 0x20d: reason = "PCI address parity error detected"; break;
+             case 0x20f: reason = "PCI master abort error"; break;
+             case 0x211: reason = "PCI target abort error"; break;
+             case 0x213: reason = "scatter/gather PTE invalid error"; break;
+             case 0x215: reason = "flash ROM write error"; break;
+             case 0x217: reason = "IOA timeout detected"; break;
+             case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+             case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+             case 0x21d: reason = "EISA bus time-out"; break;
+             case 0x21f: reason = "EISA software generated NMI"; break;
+             case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+             default:
+               sprintf(buf, "reason for machine-check unknown (0x%x)",
+                       (unsigned int) mchk_header->code);
+               reason = buf;
+               break;
+       }
+       wrmces(rdmces());       /* reset machine check pending flag */
+       mb();
+
+       printk(KERN_CRIT "  CIA machine check: %s%s\n",
+              reason, mchk_header->retry ? " (retryable)" : "");
+       printk(KERN_CRIT "   vector=0x%lx la_ptr=0x%lx pc=0x%lx\n",
+              vector, la_ptr, regs->pc);
+
+       /* dump the the logout area to give all info: */
+
+       ptr = (unsigned long *)la_ptr;
+       for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+           printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+                  i*sizeof(long), ptr[i], ptr[i+1]);
        }
-#if 1
-       else
-         printk("CIA machine check NOT expected\n") ;
-#endif
-#endif
 }
 
 #endif /* CONFIG_ALPHA_CIA */
index b7a64848655a718e7995ef3516a76862c8fd0bf8..a5b738a4c18b72efe1dcde5a20b9783334b78835 100644 (file)
@@ -4,6 +4,7 @@
  * kernel entry-points
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt   .long PAL_halt
@@ -22,7 +23,7 @@
 /*
  * stack offsets
  */
-#define SP_OFF         160
+#define SP_OFF         184
 
 #define SWITCH_STACK_SIZE 320
 
  * regs 9-15 preserved by C code
  * regs 16-18 saved by PAL-code
  * regs 29-30 saved and set up by PAL-code
+ * JRP - Save regs 16-18 in a special area of the stack, so that
+ * the palcode-provided values are available to the signal handler.
  */
 #define SAVE_ALL                       \
-       subq    $30,160,$30;            \
+       subq    $30,184,$30;            \
        stq     $0,0($30);              \
        stq     $1,8($30);              \
        stq     $2,16($30);             \
        stq     $28,144($30);           \
        lda     $2,hae;                 \
        ldq     $2,HAE_CACHE($2);       \
-       stq     $2,152($30)
+       stq     $2,152($30);            \
+       stq     $16,160($30);           \
+       stq     $17,168($30);           \
+       stq     $18,176($30)
 
 #define RESTORE_ALL                    \
        lda     $8,hae;                 \
        ldq     $26,128($30);           \
        ldq     $27,136($30);           \
        ldq     $28,144($30);           \
-       addq    $30,160,$30
+       addq    $30,184,$30
 
 .text
 .set noat
-#ifdef __linux__
+#if defined(__linux__) && !defined(__ELF__)
   .set singlegp
 #endif
 
@@ -160,6 +166,36 @@ entArith:
 .globl entIF
 .ent   entIF
 entIF:
+#ifdef CONFIG_KGDB
+       bne     $16,1f          /* not a bpt trap -> */
+       /*
+        * Call kgdb if it's enabled and if "current" is not being
+        * traced or if we get a bpt in kernel mode (the architecture
+        * manual defines the values of $17 and $18 as "unpredictable",
+        * so they are fair game).
+        */
+       lda     $17,kgdb_enabled
+       ldl     $17,0($17)
+       beq     $17,1f          /* kgdb not enabled -> */
+
+#ifndef CONFIG_ALPHA_CABRIOLET
+       /*
+        * MILO on Cabriolet doesn't seem to setup the PS in the
+        * PALframe correctly. (davidm@azstarnet.com)
+        */
+       ldq     $18,0($30)      /* get ps */
+       and     $18,8,$18
+       beq     $18,entKGDB
+#endif
+
+       lda     $17,current_set
+       ldq     $17,0($17)
+       bis     $31,PF_PTRACED,$18
+       ldq     $17,TASK_FLAGS($17)
+       and     $17,$18,$17
+       beq     $17,entKGDB
+1:
+#endif
        SAVE_ALL
        lda     $27,do_entIF
        lda     $26,ret_from_sys_call
@@ -759,3 +795,127 @@ sys_call_table:
        .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
        .quad sys_nanosleep, sys_mremap, do_entSys, do_entSys, do_entSys
        .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys
+
+
+#ifdef CONFIG_KGDB
+
+#define KGDB_STACK_SIZE        (8*1024)
+
+       .lcomm  kgdb_stack_bottom, KGDB_STACK_SIZE
+
+/*
+ * The following is the nasty part of entering KGDB.  GDB assumes that
+ * it can access the memory below the interrupted thread's stack
+ * pointer (SP).  This means that the stub cannot run on this stack
+ * (interrupts could overwrite changes made by GDB).  Similarly, we do
+ * not want to bother the GDB user with the call chain leading from
+ * the interrupt handler to this function.  That is, the SP reported
+ * to GDB should be the thread's SP at the point it was interrupted.  We
+ * achieve all this by switching to KGDB's own stack before saving any
+ * registers (of course, the PAL-generated frame is already on the stack and
+ * we copy that part explicitly).  GDB does whatever it wants to the
+ * thread's stack; and when it continues execution, we restore the
+ * registers from the private stack and return from the interrupt.
+ *
+ * This is not re-entrant---gdb on the host probably would get confused
+ * anyway, but we probably ought to detect that case at the least...
+ */
+.align 3
+.globl entKGDB
+.ent   entKGDB
+entKGDB:
+       lda     $16,kgdb_stack_bottom
+       lda     $16,(KGDB_STACK_SIZE-48)($16)
+       bis     $31,$30,$17     /* save real sp in a1 */
+       bis     $31,$16,$30     /* update sp atomically! */
+       SAVE_ALL                /* save regular stuff */
+       /*
+        * Only now can we disable interrupts (swpipl may step on
+        * t0,t8..t11, and a0):
+        */
+       bis     $31,7,$16
+       call_pal PAL_swpipl
+
+       /* copy PAL frame to kgdb stack: */
+
+       ldq     $1,0($17)
+       ldq     $2,8($17)
+       ldq     $3,16($17)
+       ldq     $4,24($17)
+       ldq     $5,32($17)
+       ldq     $6,40($17)
+
+       stq     $1,0+184($30)
+       stq     $2,8+184($30)
+       stq     $3,16+184($30)
+       stq     $4,24+184($30)
+       stq     $5,32+184($30)
+       stq     $6,40+184($30)
+
+       /* allocate space for and save caller saved regs as well as orig sp: */
+
+       lda     $30,-320($30)
+       addq    $17,48,$17      /* pop PAL frame */
+       stq     $17,0($30)      /* save original sp */
+
+       stq      $9,0x08($30); stq $10,0x10($30); stq $11,0x18($30)
+       stq     $12,0x20($30); stq $13,0x28($30); stq $14,0x30($30)
+       stq     $15,0x38($30)
+
+       stt     $f0,0x40($30);   stt $f1,0x48($30);   stt $f2,0x50($30);   stt $f3,0x58($30)
+       stt     $f4,0x60($30);   stt $f5,0x68($30);   stt $f6,0x70($30);   stt $f7,0x78($30)
+       stt     $f8,0x80($30);   stt $f9,0x88($30);   stt $f10,0x90($30);  stt $f11,0x98($30)
+       stt     $f12,0xa0($30);  stt $f13,0xa8($30);  stt $f14,0xb0($30);  stt $f15,0xb8($30)
+       stt     $f16,0xc0($30);  stt $f17,0xc8($30);  stt $f18,0xd0($30);  stt $f19,0xd8($30)
+       stt     $f20,0xe0($30);  stt $f21,0xe8($30);  stt $f22,0xf0($30);  stt $f23,0xf8($30)
+       stt     $f24,0x100($30); stt $f25,0x108($30); stt $f26,0x110($30); stt $f27,0x118($30)
+       stt     $f28,0x120($30); stt $f29,0x128($30); stt $f30,0x130($30); stt $f31,0x138($30)
+
+       bis     $31,$30,$16
+
+       lda     $27,kgdb_handle_exception
+       jsr     $26,($27),kgdb_handle_exception
+
+       ldq     $17,0($30)      /* load new sp and caller-saved registers */
+
+       ldq      $9,0x08($30); ldq $10,0x10($30); ldq $11,0x18($30)
+       ldq     $12,0x20($30); ldq $13,0x28($30); ldq $14,0x30($30)
+       ldq     $15,0x38($30)
+
+       ldt     $f0,0x40($30);   ldt $f1,0x48($30);   ldt $f2,0x50($30);   ldt $f3,0x58($30)
+       ldt     $f4,0x60($30);   ldt $f5,0x68($30);   ldt $f6,0x70($30);   ldt $f7,0x78($30)
+       ldt     $f8,0x80($30);   ldt $f9,0x88($30);   ldt $f10,0x90($30);  ldt $f11,0x98($30)
+       ldt     $f12,0xa0($30);  ldt $f13,0xa8($30);  ldt $f14,0xb0($30);  ldt $f15,0xb8($30)
+       ldt     $f16,0xc0($30);  ldt $f17,0xc8($30);  ldt $f18,0xd0($30);  ldt $f19,0xd8($30)
+       ldt     $f20,0xe0($30);  ldt $f21,0xe8($30);  ldt $f22,0xf0($30);  ldt $f23,0xf8($30)
+       ldt     $f24,0x100($30); ldt $f25,0x108($30); ldt $f26,0x110($30); ldt $f27,0x118($30)
+       ldt     $f28,0x120($30); ldt $f29,0x128($30); ldt $f30,0x130($30); ldt $f31,0x138($30)
+       lda     $30,320($30)    /* pop extra register frame */
+
+       /*
+        * Copy PAL frame from kgdb stack to new stack so we can rti
+        * to it:
+        */
+       ldq     $1,0+184($30)
+       ldq     $2,8+184($30)
+       ldq     $3,16+184($30)
+       ldq     $4,24+184($30)
+       ldq     $5,32+184($30)
+       ldq     $6,40+184($30)
+
+       subq    $17,48,$17      /* alloc space for PAL frame on new stack */
+
+       stq     $1,0($17)
+       stq     $2,8($17)
+       stq     $3,16($17)
+       stq     $4,24($17)
+       stq     $5,32($17)
+       stq     $6,40($17)
+
+       RESTORE_ALL
+       bis     $31,$17,$30     /* establish new sp */
+       rti
+
+.end entKGDB
+
+#endif /* CONFIG_KGDB */
index 0c1fc8681ecca1c5e6299e203f6be657531d2cf7..bea8c4e64f75987e91c1864a5f401f91d1985b32 100644 (file)
@@ -92,6 +92,50 @@ wrmces:
        ret     ($26)
        .end wrmces
 
+       .align 3
+       .globl  whami
+       .ent    whami
+whami:
+       call_pal PAL_whami
+       ret     ($26)
+       .end whami
+       .align 3
+       .globl  wripir
+       .ent    wripir
+wripir:
+       call_pal PAL_wripir
+       ret     ($26)
+       .end wripir
+
+       .align 3
+       .globl  cserve_ena
+       .ent    cserve_ena
+cserve_ena:
+       lda     $30,-0x08($30)
+       stq     $17,0($30)
+       bis     $16,$16,$17
+       lda     $16,52($31)
+       call_pal PAL_cserve
+       ldq     $17,0($30)
+       lda     $30,0x08($30)
+       ret     ($26)
+       .end    cserve_ena
+
+       .align 3
+       .globl  cserve_dis
+       .ent    cserve_dis
+cserve_dis:
+       lda     $30,-0x08($30)
+       stq     $17,0($30)
+       bis     $16,$16,$17
+       lda     $16,53($31)
+       call_pal PAL_cserve
+       ldq     $17,0($30)
+       lda     $30,0x08($30)
+       ret     ($26)
+       .end    cserve_dis
+
        #
        # The following two functions don't need trapb/excb instructions
        # around the mf_fpcr/mt_fpcr instructions because (a) the kernel
index a8d293a2eabc4b4ae7cd14fc2f3f53e34cf124fb..3defc0878c66e2e063b19ecabcf6435faa348f63 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/dma.h>
 
 extern void timer_interrupt(struct pt_regs * regs);
+extern void cserve_update_hw(unsigned long, unsigned long);
 
 #if NR_IRQS > 64
 #  error Unable to handle more than 64 irq levels.
@@ -42,7 +43,8 @@ extern void timer_interrupt(struct pt_regs * regs);
  *      0.. 7  first (E)ISA PIC (irq level 0..7)
  *      8..15  second (E)ISA PIC (irq level 8..15)
  *   Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT):
- *     16..47  PCI interrupts 0..31 (int at GRU_INT_MASK)
+ *    or PYXIS (e.g. Miata, PC164-LX)
+ *     16..47  PCI interrupts 0..31 (xxx_INT_MASK reg)
  *   Mikasa:
  *     16..31  PCI interrupts 0..15 (short at I/O port 536)
  *   Other systems (not Mikasa) with 16 PCI interrupt lines:
@@ -50,13 +52,43 @@ extern void timer_interrupt(struct pt_regs * regs);
  *     24..31  PCI interrupts 8..15 (char at I/O port 27)
  *   Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164):
  *     16..32  PCI interrupts 0..31 (int at I/O port 804)
+ *   Takara:
+ *      16..19  PCI interrupts A thru D
+ *   For SABLE, which is really baroque, we manage 40 IRQ's, but the
+ *   hardware really only supports 24, not via normal ISA PIC,
+ *   but cascaded custom 8259's, etc.
+ *      0-7  (char at 536)
+ *      8-15 (char at 53a)
+ *     16-23 (char at 53c)
  */
 static unsigned long irq_mask = ~0UL;
 
+#ifdef CONFIG_ALPHA_SABLE
+/* note that the vector reported by the SRM PALcode corresponds to the
+   interrupt mask bits, but we have to manage via more normal IRQs */
+static char sable_irq_to_mask[NR_IRQS] = {
+       -1,  6, -1,  8, 15, 12,  7,  9, /* pseudo PIC  0-7  */
+       -1, 16, 17, 18,  3, -1, 21, 22, /* pseudo PIC  8-15 */
+       -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7  */
+       -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */
+        2,  1,  0,  4,  5, -1, -1, -1, /* pseudo PCI */
+       };
+#define IRQ_TO_MASK(irq) (sable_irq_to_mask[(irq)])
+static char sable_mask_to_irq[NR_IRQS] = {
+       34, 33, 32, 12, 35, 36,  1,  6, /* mask 0-7  */
+        3,  7, -1, -1,  5, -1, -1,  4, /* mask 8-15  */
+        9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23  */
+       };
+#else /* CONFIG_ALPHA_SABLE */
+#define IRQ_TO_MASK(irq) (irq)
+#endif /* CONFIG_ALPHA_SABLE */
 
 /*
  * Update the hardware with the irq mask passed in MASK.  The function
  * exploits the fact that it is known that only bit IRQ has changed.
+ *
+ * There deliberately isn't a case in here for the Takara since it
+ * wouldn't work anyway because the interrupt controller is bizarre.
  */
 static void update_hw(unsigned long irq, unsigned long mask)
 {
@@ -65,32 +97,111 @@ static void update_hw(unsigned long irq, unsigned long mask)
        mask |= 0x7ff00000UL << 16;
 #endif
        switch (irq) {
-#if NR_IRQS == 48
-             default:
+
+#ifdef CONFIG_ALPHA_SABLE
+  /* SABLE does everything different, so we manage it that way... :-( */
+  /* the "irq" argument is really the mask bit number */
+       case 0 ... 7:
+         outb(mask, 0x537);
+         break;
+       case 8 ... 15:
+         outb(mask >> 8, 0x53b);
+         break;
+       case 16 ... 23:
+         outb(mask >> 16, 0x53d);
+         break;
+#else /* SABLE */
+
+#if defined(CONFIG_ALPHA_NORITAKE)
+         /* note inverted sense of mask bits: */
+       case 16 ... 31:
+         outw(~(mask >> 16), 0x54a);
+         break;
+       case 32 ... 47:
+         outw(~(mask >> 32), 0x54c);
+         break;
+#endif /* NORITAKE */
+
+#if defined(CONFIG_ALPHA_MIATA)
+       case 16 ... 47:
+         { unsigned long temp;
+         /* note inverted sense of mask bits: */
+         /* make CERTAIN none of the bogus ints get enabled */
+         *(unsigned long *)PYXIS_INT_MASK =
+           ~((long)mask >> 16) & ~0x400000000000063bUL; mb();
+         temp = *(unsigned long *)PYXIS_INT_MASK;
+         break;
+         }
+#endif /* MIATA */
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+       case 16 ... 47:
+         { unsigned long temp;
+         /* note inverted sense of mask bits: */
+         /* make CERTAIN none of the bogus ints get enabled */
+         *(unsigned long *)PYXIS_INT_MASK =
+           ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb();
+         temp = *(unsigned long *)PYXIS_INT_MASK;
+         break;
+         }
+#endif /* RUFFIAN */
+
+#if defined(CONFIG_ALPHA_SX164)
+       case 16 ... 39:
+#if defined(CONFIG_ALPHA_SRM)
+         cserve_update_hw(irq, mask);
+         break;
+#else
+         { unsigned long temp;
+         /* make CERTAIN none of the bogus ints get enabled */
+         *(unsigned long *)PYXIS_INT_MASK =
+             ~((long)mask >> 16) & ~0x000000000000003bUL; mb();
+         temp = *(unsigned long *)PYXIS_INT_MASK;
+         break;
+         }
+#endif /* SRM */
+#endif /* SX164 */
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+       case 16 ... 47:
                /* note inverted sense of mask bits: */
                *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb();
                break;
+#endif /* ALCOR || XLT */
 
-#elif NR_IRQS == 33
-             default:
-               outl(mask >> 16, 0x804);
+#if defined(CONFIG_ALPHA_CABRIOLET) || \
+    defined(CONFIG_ALPHA_EB66P)     || \
+    defined(CONFIG_ALPHA_EB164)     || \
+    defined(CONFIG_ALPHA_PC164)     || \
+    defined(CONFIG_ALPHA_LX164)
+#if defined(CONFIG_ALPHA_SRM)
+      case 16 ... 34:
+       cserve_update_hw(irq, mask);
+        break;
+#else /* SRM */
+      case 16 ... 34:
+       outl(irq_mask >> 16, 0x804);
                break;
+#endif /* SRM */
+#endif /* CABRIO || EB66P || EB164 || PC164 || LX164 */
 
-#elif defined(CONFIG_ALPHA_MIKASA)
-             default:
+#if defined(CONFIG_ALPHA_MIKASA)
+       case 16 ... 31:
                outw(~(mask >> 16), 0x536); /* note invert */
                break;
+#endif /* MIKASA */
 
-#elif NR_IRQS == 32
+#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
              case 16 ... 23:
                outb(mask >> 16, 0x26);
                break;
-
-             default:
+       case 24 ... 31:
                outb(mask >> 24, 0x27);
                break;
-#endif
+#endif /* EB66 || EB64P */
+
                /* handle ISA irqs last---fast devices belong on PCI... */
+       /* this is common for all except SABLE! */
 
              case  0 ... 7:    /* ISA PIC1 */
                outb(mask, 0x21);
@@ -99,7 +210,10 @@ static void update_hw(unsigned long irq, unsigned long mask)
              case  8 ...15:    /* ISA PIC2 */
                outb(mask >> 8, 0xA1);
                break;
-       }
+
+#endif /* SABLE */
+
+       } /* end switch (irq) */
 }
 
 static inline void mask_irq(unsigned long irq)
@@ -120,7 +234,7 @@ void disable_irq(unsigned int irq_nr)
 
        save_flags(flags);
        cli();
-       mask_irq(irq_nr);
+       mask_irq(IRQ_TO_MASK(irq_nr));
        restore_flags(flags);
 }
 
@@ -130,7 +244,7 @@ void enable_irq(unsigned int irq_nr)
 
        save_flags(flags);
        cli();
-       unmask_irq(irq_nr);
+       unmask_irq(IRQ_TO_MASK(irq_nr));
        restore_flags(flags);
 }
 
@@ -164,7 +278,32 @@ int get_irq_list(char *buf)
 
 static inline void ack_irq(int irq)
 {
+#ifdef CONFIG_ALPHA_SABLE
+  /* note that the "irq" here is really the mask bit number */
+       switch (irq) {
+       case 0 ... 7:
+         outb(0xE0 | (irq - 0), 0x536);
+         outb(0xE0 | 1, 0x534); /* slave 0 */
+         break;
+       case 8 ... 15:
+         outb(0xE0 | (irq - 8), 0x53a);
+         outb(0xE0 | 3, 0x534); /* slave 1 */
+         break;
+       case 16 ... 24:
+         outb(0xE0 | (irq - 16), 0x53c);
+         outb(0xE0 | 4, 0x534); /* slave 2 */
+         break;
+       }
+#else /* CONFIG_ALPHA_SABLE */
        if (irq < 16) {
+#if defined(CONFIG_ALPHA_RUFFIAN)
+               /* ack pyxis ISA interrupt */
+               *(unsigned long *)PYXIS_INT_REQ = (0x01UL << 7);
+               if (irq > 7) {
+                       outb(0x20,0xa0);
+               }
+               outb(0x20,0x20);
+#else /* RUFFIAN */
                /* ACK the interrupt making it the lowest priority */
                /*  First the slave .. */
                if (irq > 7) {
@@ -178,7 +317,16 @@ static inline void ack_irq(int irq)
                *(int *)GRU_INT_CLEAR = 0x80000000; mb();
                *(int *)GRU_INT_CLEAR = 0x00000000; mb();
 #endif /* ALCOR || XLT */
+#endif /* RUFFIAN */  
        }
+#if defined(CONFIG_ALPHA_RUFFIAN)
+        else {
+         /* ack pyxis int */
+         *(unsigned long *)PYXIS_INT_REQ = (1UL << (irq-16));
+        }
+#endif /* RUFFIAN */        
+
+#endif /* CONFIG_ALPHA_SABLE */
 }
 
 int request_irq(unsigned int irq, 
@@ -236,7 +384,7 @@ int request_irq(unsigned int irq,
        *p = action;
 
        if (!shared)
-               unmask_irq(irq);
+               unmask_irq(IRQ_TO_MASK(irq));
 
        restore_flags(flags);
        return 0;
@@ -264,7 +412,7 @@ void free_irq(unsigned int irq, void *dev_id)
                cli();
                *p = action->next;
                if (!irq[irq_action])
-                       mask_irq(irq);
+                       mask_irq(IRQ_TO_MASK(irq));
                restore_flags(flags);
                kfree(action);
                return;
@@ -323,25 +471,39 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
        struct irqaction * action;
 
        if ((unsigned) irq > NR_IRQS) {
-               printk("device_interrupt: unexpected interrupt %d\n", irq);
+               printk("device_interrupt: illegal interrupt %d\n", irq);
+               return;
+       }
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+       /* RUFFIAN uses ISA IRQ #0 to deliver clock ticks */
+       if (irq == 0) {
+               timer_interrupt(regs);
+               ack_irq(0);
                return;
        }
+#endif /* RUFFIAN */
 
        kstat.interrupts[irq]++;
        action = irq_action[irq];
+
        /*
         * For normal interrupts, we mask it out, and then ACK it.
         * This way another (more timing-critical) interrupt can
         * come through while we're doing this one.
         *
-        * Note! A irq without a handler gets masked and acked, but
+        * Note! An irq without a handler gets masked and acked, but
         * never unmasked. The autoirq stuff depends on this (it looks
         * at the masks before and after doing the probing).
         */
        mask_irq(ack);
        ack_irq(ack);
-       if (!action)
+       if (!action) {
+#if 1
+               printk("device_interrupt: unexpected interrupt %d\n", irq);
+#endif
                return;
+       }
        if (action->flags & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
        do {
@@ -365,6 +527,8 @@ static inline void isa_device_interrupt(unsigned long vector,
 #      define IACK_SC  LCA_IACK_SC
 #elif defined(CONFIG_ALPHA_CIA)
 #      define IACK_SC  CIA_IACK_SC
+#elif defined(CONFIG_ALPHA_PYXIS)
+#      define IACK_SC  PYXIS_IACK_SC
 #else
        /*
         * This is bogus but necessary to get it to compile
@@ -554,8 +718,185 @@ static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
        restore_flags(flags);
 }
 
+#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+/* we have to conditionally compile this because of PYXIS_xxx symbols */
+static inline void miata_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+        unsigned long pld, tmp;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary register of PYXIS */
+        pld = (*(volatile unsigned long *)PYXIS_INT_REQ);
+
+#if 0
+        printk("[0x%08lx/0x%08lx/0x%04x]", pld,
+              *(volatile unsigned long *)PYXIS_INT_MASK,
+              inb(0x20) | (inb(0xA0) << 8));
+#endif
+
+#ifdef CONFIG_ALPHA_MIATA
+       /* for now, AND off any bits we are not interested in: */
+       /*  HALT (2), timer (6), ISA Bridge (7), 21142 (8) */
+       /*  then all the PCI slots/INTXs (12-31) */
+/* maybe HALT should only be used for SRM console boots? */
+       pld &= 0x00000000fffff9c4UL;
+#endif /* MIATA */
+#ifdef CONFIG_ALPHA_SX164
+       /* for now, AND off any bits we are not interested in: */
+       /*  HALT (2), timer (6), ISA Bridge (7) */
+       /*  then all the PCI slots/INTXs (8-23) */
+/* HALT should only be used for SRM console boots */
+       pld &= 0x0000000000ffffc0UL;
+#endif /* SX164 */
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+        while (pld) {
+                i = ffz(~pld);
+                pld &= pld - 1; /* clear least bit set */
+                if (i == 7) {
+                        isa_device_interrupt(vector, regs);
+               } else if (i == 6)
+                       continue;
+                else { /* if not timer int */
+                        device_interrupt(16 + i, 16 + i, regs);
+                }
+               *(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb();
+               tmp = *(volatile unsigned long *)PYXIS_INT_REQ;
+        }
+        restore_flags(flags);
+}
+#endif /* MIATA || SX164 */
+
+static inline void noritake_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+        unsigned long pld;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary registers */
+        /* read the interrupt summary registers of NORITAKE */
+        pld = ((unsigned long) inw(0x544) << 32) |
+             ((unsigned long) inw(0x542) << 16) |
+             ((unsigned long) inb(0xa0)  <<  8) |
+             ((unsigned long) inb(0x20));
+
+#if 0
+        printk("[0x%08lx]", pld);
+#endif
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+        while (pld) {
+               i = ffz(~pld);
+               pld &= pld - 1; /* clear least bit set */
+               if (i < 16) {
+                       isa_device_interrupt(vector, regs);
+               } else {
+                       device_interrupt(i, i, regs);
+               }
+        }
+        restore_flags(flags);
+}
+
 #endif /* CONFIG_PCI */
 
+#if defined(CONFIG_ALPHA_RUFFIAN)
+static inline void ruffian_device_interrupt(unsigned long vector,
+                                           struct pt_regs * regs)
+
+{
+       unsigned long pld, tmp;
+        unsigned int i;
+        unsigned long flags;
+
+        save_flags(flags);
+        cli();
+
+        /* read the interrupt summary register of PYXIS */
+        pld = (*(volatile unsigned long *)PYXIS_INT_REQ);
+
+        /* for now, AND off any bits we are not interested in:
+         *  HALT (2), timer (6), ISA Bridge (7), 21142 (8)
+         *  then all the PCI slots/INTXs (12-31) 
+         *  flash(5) :DWH:
+         */
+        pld &= 0x00000000ffffff9fUL;/* was ffff7f */
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+
+        while (pld) {
+               i = ffz(~pld);
+                pld &= pld - 1; /* clear least bit set */
+                if (i == 7) {
+                       isa_device_interrupt(vector, regs);
+                } else { /* if not timer int */
+                       device_interrupt(16 + i,16 + i,regs);
+                }
+                *(unsigned long *)PYXIS_INT_REQ = 1UL << i; mb();
+                tmp = *(volatile unsigned long *)PYXIS_INT_REQ;
+        }
+        restore_flags(flags);
+}
+#endif /* RUFFIAN */
+
+static inline void takara_device_interrupt(unsigned long vector,
+                                          struct pt_regs * regs)
+{
+       unsigned long flags;
+       unsigned intstatus;
+
+       save_flags(flags);
+       cli();
+
+       /*
+        * The PALcode will have passed us vectors 0x800 or 0x810,
+        * which are fairly arbitrary values and serve only to tell
+        * us whether an interrupt has come in on IRQ0 or IRQ1. If
+        * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's
+        * probably ISA, but PCI interrupts can come through IRQ0
+        * as well if the interrupt controller isn't in accelerated
+        * mode.
+        *
+        * OTOH, the accelerator thing doesn't seem to be working
+        * overly well, so what we'll do instead is try directly
+        * examining the Master Interrupt Register to see if it's a
+        * PCI interrupt, and if _not_ then we'll pass it on to the
+        * ISA handler.
+        */
+
+       intstatus = inw(0x500) & 15;
+       if (intstatus) {
+               /*
+                * This is a PCI interrupt. Check each bit and
+                * despatch an interrupt if it's set.
+                */
+               if (intstatus & 8) device_interrupt(16+3, 16+3, regs);
+               if (intstatus & 4) device_interrupt(16+2, 16+2, regs);
+               if (intstatus & 2) device_interrupt(16+1, 16+1, regs);
+               if (intstatus & 1) device_interrupt(16+0, 16+0, regs);
+       } else
+               isa_device_interrupt (vector, regs);
+
+       restore_flags(flags);
+}
+
 /*
  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
  * 0x9X0 for the local motherboard interrupts..
@@ -587,6 +928,9 @@ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * r
        save_flags(flags);
        cli();
 
+#if 0
+printk("srm_device_interrupt: vector 0x%lx\n", vector);
+#endif
 
        ack = irq = (vector - 0x800) >> 4;
 
@@ -608,11 +952,69 @@ static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * r
                irq = 7;
 #endif /* CONFIG_ALPHA_JENSEN */
 
+#ifdef CONFIG_ALPHA_MIATA
+        /*
+         * I really hate to do this, but the MIATA SRM console ignores the
+         *  low 8 bits in the interrupt summary register, and reports the
+         *  vector 0x80 *lower* than I expected from the bit numbering in
+         *  the documentation.
+         * This was done because the low 8 summary bits really aren't used
+         *  for reporting any interrupts (the PCI-ISA bridge, bit 7, isn't
+         *  used for this purpose, as PIC interrupts are delivered as the
+         *  vectors 0x800-0x8f0).
+         * But I really don't want to change the fixup code for allocation
+         *  of IRQs, nor the irq_mask maintenance stuff, both of which look
+         *  nice and clean now.
+         * So, here's this grotty hack... :-(
+         */
+        if (irq >= 16)
+               ack = irq = irq + 8;
+#endif /* CONFIG_ALPHA_MIATA */
+
+#ifdef CONFIG_ALPHA_NORITAKE
+        /*
+         * I really hate to do this, but the NORITAKE SRM console reports
+         *  PCI vectors *lower* than I expected from the bit numbering in
+         *  the documentation.
+         * But I really don't want to change the fixup code for allocation
+         *  of IRQs, nor the irq_mask maintenance stuff, both of which look
+         *  nice and clean now.
+         * So, here's this grotty hack... :-(
+         */
+        if (irq >= 16)
+               ack = irq = irq + 1;
+#endif /* CONFIG_ALPHA_NORITAKE */
+
+#ifdef CONFIG_ALPHA_SABLE
+       irq = sable_mask_to_irq[(ack)];
+#if 0
+       if (irq == 5 || irq == 9 || irq == 10 || irq == 11 ||
+           irq == 14 || irq == 15)
+       printk("srm_device_interrupt: vector=0x%lx  ack=0x%x  irq=0x%x\n",
+              vector, ack, irq);
+#endif
+#endif /* CONFIG_ALPHA_SABLE */
+
        device_interrupt(irq, ack, regs);
 
        restore_flags(flags) ;
 }
 
+/* PROBE_MASK is the bitset of irqs that we consider for autoprobing: */
+#if defined(CONFIG_ALPHA_P2K)
+  /* always mask out unused timer irq 0 and RTC irq 8 */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+  /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+  /* must leave timer irq 0 in the mask */
+# define PROBE_MASK ((1UL << NR_IRQS) - 1)
+#else
+  /* always mask out unused timer irq 0: */
+# define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
+#endif
+
 /*
  * Start listening for interrupts..
  */
@@ -624,10 +1026,13 @@ unsigned long probe_irq_on(void)
        unsigned int i;
 
        for (i = NR_IRQS - 1; i > 0; i--) {
+               if (!(PROBE_MASK & (1UL << i))) {
+                       continue;
+                }
                action = irq_action[i];
                if (!action) {
                        enable_irq(i);
-                       irqs |= (1 << i);
+                       irqs |= (1UL << i);
                }
        }
        /*
@@ -650,10 +1055,7 @@ int probe_irq_off(unsigned long irqs)
 {
        int i;
        
-       irqs &= irq_mask & ~1;  /* always mask out irq 0---it's the unused timer */
-#ifdef CONFIG_ALPHA_P2K
-       irqs &= ~(1 << 8);      /* mask out irq 8 since that's the unused RTC input to PIC */
-#endif
+       irqs &= irq_mask;
        if (!irqs)
                return 0;
        i = ffz(~irqs);
@@ -676,6 +1078,14 @@ static void machine_check(unsigned long vector, unsigned long la, struct pt_regs
        extern void cia_machine_check(unsigned long vector, unsigned long la,
                                        struct pt_regs * regs);
        cia_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_PYXIS)
+       extern void pyxis_machine_check(unsigned long vector, unsigned long la,
+                                       struct pt_regs * regs);
+       pyxis_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_T2)
+       extern void t2_machine_check(unsigned long vector, unsigned long la,
+                                    struct pt_regs * regs);
+       t2_machine_check(vector, la, regs);
 #else
        printk("Machine check\n");
 #endif
@@ -685,6 +1095,9 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon
        unsigned long a3, unsigned long a4, unsigned long a5,
        struct pt_regs regs)
 {
+#if 0
+printk("do_entInt: type 0x%lx\n", type);
+#endif
        switch (type) {
                case 0:
                        printk("Interprocessor interrupt? You must be kidding\n");
@@ -699,17 +1112,30 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon
 #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
     defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
                        srm_device_interrupt(vector, &regs);
-#elif NR_IRQS == 48
+#else /* everyone else */
+
+#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+                       miata_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_NORITAKE)
+                       noritake_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
                        alcor_and_xlt_device_interrupt(vector, &regs);
-#elif NR_IRQS == 33
+#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+      defined(CONFIG_ALPHA_EB164)     || defined(CONFIG_ALPHA_PC164) || \
+      defined(CONFIG_ALPHA_LX164)
                        cabriolet_and_eb66p_device_interrupt(vector, &regs);
 #elif defined(CONFIG_ALPHA_MIKASA)
                        mikasa_device_interrupt(vector, &regs);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
                        eb66_and_eb64p_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+                        ruffian_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_TAKARA)
+                       takara_device_interrupt(vector, &regs);
 #elif NR_IRQS == 16
                        isa_device_interrupt(vector, &regs);
 #endif
+#endif /* everyone else */
                        return;
                case 4:
                        printk("Performance counter interrupt\n");
@@ -724,23 +1150,141 @@ extern asmlinkage void entInt(void);
 
 void init_IRQ(void)
 {
+       unsigned int temp;
+
        wrent(entInt, 0);
-       dma_outb(0, DMA1_RESET_REG);
-       dma_outb(0, DMA2_RESET_REG);
-       dma_outb(0, DMA1_CLR_MASK_REG);
-       dma_outb(0, DMA2_CLR_MASK_REG);
-#if NR_IRQS == 48
+
+       outb(0, DMA1_RESET_REG);
+       outb(0, DMA2_RESET_REG);
+
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_SX164)
+       outb(0, DMA1_CLR_MASK_REG);
+       /* we need to figure out why this fails on the SX164 */
+       outb(0, DMA2_CLR_MASK_REG);
+#endif /* !SX164 */
+/* end FIXMEs */
+
+#if defined(CONFIG_ALPHA_SABLE)
+       outb(irq_mask      , 0x537); /* slave 0 */
+       outb(irq_mask >>  8, 0x53b); /* slave 1 */
+       outb(irq_mask >> 16, 0x53d); /* slave 2 */
+       outb(0x44, 0x535);      /* enable cascades in master */
+#else /* everybody but SABLE */
+
+#if defined(CONFIG_ALPHA_MIATA)
+       /* note invert on MASK bits */
+        *(unsigned long *)PYXIS_INT_MASK  =
+         ~((long)irq_mask >> 16) & ~0x400000000000063bUL; mb();
+#if 0
+       /* these break on MiataGL so we'll try not to do it at all */
+        *(unsigned long *)PYXIS_INT_HILO  = 0x000000B2UL; mb();/* ISA/NMI HI */
+        *(unsigned long *)PYXIS_RT_COUNT  = 0UL; mb();/* clear count */
+#endif
+       /* clear upper timer */
+        *(unsigned long *)PYXIS_INT_REQ  = 0x4000000000000180UL; mb();
+
+       /* Send -INTA pulses to clear any pending interrupts ...*/
+       temp = *(volatile unsigned int *) IACK_SC;
+
+       enable_irq(16 + 2);     /* enable HALT switch - SRM only? */
+        enable_irq(16 + 6);     /* enable timer */
+        enable_irq(16 + 7);     /* enable ISA PIC cascade */
+#endif /* MIATA */
+
+#if defined(CONFIG_ALPHA_SX164)
+#if !defined(CONFIG_ALPHA_SRM)
+       /* note invert on MASK bits */
+        *(unsigned long *)PYXIS_INT_MASK  = ~((long)irq_mask >> 16); mb();
+#if 0
+        *(unsigned long *)PYXIS_INT_HILO  = 0x000000B2UL; mb();/* ISA/NMI HI */
+        *(unsigned long *)PYXIS_RT_COUNT  = 0UL; mb();/* clear count */
+#endif
+#endif /* !SRM */
+        enable_irq(16 + 6);     /* enable timer */
+        enable_irq(16 + 7);     /* enable ISA PIC cascade */
+#endif /* SX164 */
+
+#if defined(CONFIG_ALPHA_NORITAKE)
+       outw(~(irq_mask >> 16), 0x54a); /* note invert */
+       outw(~(irq_mask >> 32), 0x54c); /* note invert */
+#endif /* NORITAKE */
+
+#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
        *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */
+       *(unsigned int *)GRU_INT_EDGE  = 0UL; mb();/* all are level */
+       *(unsigned int *)GRU_INT_HILO  = 0x80000000UL; mb();/* ISA only HI */
+       *(unsigned int *)GRU_INT_CLEAR = 0UL; mb();/* all clear */
        enable_irq(16 + 31);    /* enable (E)ISA PIC cascade */
-#elif NR_IRQS == 33
+#endif /* ALCOR || XLT */
+
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+    defined(CONFIG_ALPHA_PC164)     || defined(CONFIG_ALPHA_LX164) || \
+    defined(CONFIG_ALPHA_EB164)
+#if !defined(CONFIG_ALPHA_SRM)
        outl(irq_mask >> 16, 0x804);
+#endif /* !SRM */
+       /* Send -INTA pulses to clear any pending interrupts ...*/
+       temp = *(volatile unsigned int *) IACK_SC;
        enable_irq(16 +  4);    /* enable SIO cascade */
-#elif defined(CONFIG_ALPHA_MIKASA)
+#endif /* CABRIO || EB66P || PC164 || LX164 || EB164 */
+
+#if defined(CONFIG_ALPHA_MIKASA)
        outw(~(irq_mask >> 16), 0x536); /* note invert */
-#elif NR_IRQS == 32
+#endif /* MIKASA */
+
+#if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
        outb(irq_mask >> 16, 0x26);
        outb(irq_mask >> 24, 0x27);
        enable_irq(16 +  5);    /* enable SIO cascade */
-#endif
-       enable_irq(2);          /* enable cascade */
+#endif /* EB66 || EB64P */
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+       /* invert 6&7 for i82371 */
+       *(unsigned long *)PYXIS_INT_HILO  = 0x000000c0UL;mb();
+       *(unsigned long *)PYXIS_INT_CNFG  = 0x00002064UL;mb();   /* all clear */
+       *(unsigned long *)PYXIS_INT_MASK  = ((long)0x00000000UL);mb();
+       *(unsigned long *)PYXIS_INT_REQ   = 0xffffffffUL;mb();
+
+       outb(0x11,0xA0);
+       outb(0x08,0xA1);
+       outb(0x02,0xA1);
+       outb(0x01,0xA1);
+       outb(0xFF,0xA1);
+       
+       outb(0x11,0x20);
+       outb(0x00,0x21);
+       outb(0x04,0x21);
+       outb(0x01,0x21);
+       outb(0xFF,0x21);
+       
+       /* Send -INTA pulses to clear any pending interrupts ...*/
+       temp = *(volatile unsigned int *) IACK_SC;
+       
+       /* Finish writing the 82C59A PIC Operation Control Words */
+       outb(0x20,0xA0);
+       outb(0x20,0x20);
+       
+       /* Turn on the interrupt controller, the timer interrupt  */
+       enable_irq(16 + 7);     /* enable ISA PIC cascade */
+       enable_irq(0);          /* enable timer */
+#endif /* RUFFIAN */
+
+#ifdef CONFIG_ALPHA_TAKARA
+       {
+               unsigned int ctlreg = inl(0x500);
+               ctlreg &= ~0x8000;     /* return to non-accelerated mode */
+               outw(ctlreg >> 16, 0x502);
+               outw(ctlreg & 0xFFFF, 0x500);
+               ctlreg = 0x05107c00;   /* enable the PCI interrupt register */
+               printk("Setting to 0x%08x\n", ctlreg);
+               outw(ctlreg >> 16, 0x502);
+               outw(ctlreg & 0xFFFF, 0x500);
+       }
+#endif /* TAKARA */
+
+       /* and finally, everyone but SABLE does this */
+       enable_irq(2);          /* enable 2nd PIC cascade */
+
+#endif /* SABLE */
 }
index f153f5be1a05dad33f5ad5185f1046ece5a097c4..65a8aef532ff0dcc06354c1a78699d0c673656b3 100644 (file)
@@ -22,6 +22,7 @@
 #ifdef CONFIG_ALPHA_LCA
 
 #define vulp   volatile unsigned long *
+#define vuip   volatile unsigned int  *
 
 /*
  * Machine check reasons.  Defined according to PALcode sources
 #define MCHK_K_SIO_IOCHK       0x206   /* all platforms so far */
 #define MCHK_K_DCSR            0x208   /* all but Noname */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT;
+unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address and setup the LCA_IOC_CONF register
@@ -289,6 +295,40 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
 
 unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
 {
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) &&
+           (*(vulp)LCA_IOC_T_BASE0 == 0))
+       {
+         LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE += 1;
+#if 1
+         printk("lca_init: using Window 0 settings\n");
+         printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)LCA_IOC_W_BASE0,
+                *(vulp)LCA_IOC_W_MASK0,
+                *(vulp)LCA_IOC_T_BASE0);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) &&
+           (*(vulp)LCA_IOC_T_BASE1 == 0))
+       {
+         LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE += 1;
+#if 1
+         printk("lca_init: using Window 1 settings\n");
+         printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)LCA_IOC_W_BASE1,
+                *(vulp)LCA_IOC_W_MASK1,
+                *(vulp)LCA_IOC_T_BASE1);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, window 1 is disabled.  In the future, we may
@@ -296,9 +336,11 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
         * goes at 1 GB and is 1 GB large.
         */
        *(vulp)LCA_IOC_W_BASE1 = 0UL<<33;
+
        *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE;
        *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1;
        *(vulp)LCA_IOC_T_BASE0 = 0;
+       }
 
        /*
         * Disable PCI parity for now.  The NCR53c810 chip has
@@ -386,11 +428,14 @@ void ioc_error (__u32 stat0, __u32 stat1)
 
 void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs)
 {
+       unsigned long * ptr;
        const char * reason;
        union el_lca el;
        char buf[128];
+       long i;
 
-       printk("lca: machine check (la=0x%lx,pc=0x%lx)\n", la, regs->pc);
+       printk(KERN_CRIT "lca: machine check (la=0x%lx,pc=0x%lx)\n",
+              la, regs->pc);
        el.c = (struct el_common *) la;
        /*
         * The first quadword after the common header always seems to
@@ -399,9 +444,9 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
         * logout frame, the upper 32 bits is the machine check
         * revision level, which we ignore for now.
         */
-       switch (el.s->reason & 0xffffffff) {
+       switch (el.c->code & 0xffffffff) {
              case MCHK_K_TPERR:        reason = "tag parity error"; break;
-             case MCHK_K_TCPERR:       reason = "tag something parity error"; break;
+             case MCHK_K_TCPERR:       reason = "tag control parity error"; break;
              case MCHK_K_HERR:         reason = "access to non-existent memory"; break;
              case MCHK_K_ECC_C:        reason = "correctable ECC error"; break;
              case MCHK_K_ECC_NC:       reason = "non-correctable ECC error"; break;
@@ -416,7 +461,7 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
              case MCHK_K_UNKNOWN:
              default:
                sprintf(buf, "reason for machine-check unknown (0x%lx)",
-                       el.s->reason & 0xffffffff);
+                       el.c->code & 0xffffffff);
                reason = buf;
                break;
        }
@@ -425,7 +470,8 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
 
        switch (el.c->size) {
              case sizeof(struct el_lca_mcheck_short):
-               printk("  Reason: %s (short frame%s, dc_stat=%lx):\n",
+               printk(KERN_CRIT
+                      "  Reason: %s (short frame%s, dc_stat=%lx):\pn",
                       reason, el.c->retry ? ", retryable" : "", el.s->dc_stat);
                if (el.s->esr & ESR_EAV) {
                    mem_error(el.s->esr, el.s->ear);
@@ -436,11 +482,12 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
                break;
 
              case sizeof(struct el_lca_mcheck_long):
-               printk("  Reason: %s (long frame%s):\n",
+               printk(KERN_CRIT "  Reason: %s (long frame%s):\n",
                       reason, el.c->retry ? ", retryable" : "");
-               printk("    reason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
+               printk(KERN_CRIT
+                      "    reason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
                       el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
-               printk("    car: %lx\n", el.l->car);
+               printk(KERN_CRIT "    car: %lx\n", el.l->car);
                if (el.l->esr & ESR_EAV) {
                    mem_error(el.l->esr, el.l->ear);
                }
@@ -450,8 +497,55 @@ void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *
                break;
 
              default:
-               printk("  Unknown errorlog size %d\n", el.c->size);
+               printk(KERN_CRIT "  Unknown errorlog size %d\n", el.c->size);
+       }
+
+       /* dump the the logout area to give all info: */
+
+       ptr = (unsigned long *) la;
+       for (i = 0; i < el.c->size / sizeof(long); i += 2) {
+           printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+                  i*sizeof(long), ptr[i], ptr[i+1]);
        }
 }
 
+void
+lca_clock_print(void)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+
+        printk("Status of clock control:\n");
+        printk("\tPrimary clock divisor\t0x%x\n", GET_PRIMARY(pmr_reg));
+        printk("\tOverride clock divisor\t0x%x\n", GET_OVERRIDE(pmr_reg));
+        printk("\tInterrupt override is %s\n",
+              (pmr_reg & LCA_PMR_INTO) ? "on" : "off"); 
+        printk("\tDMA override is %s\n",
+              (pmr_reg & LCA_PMR_DMAO) ? "on" : "off"); 
+
+}
+
+int
+lca_get_clock(void)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+        return(GET_PRIMARY(pmr_reg));
+
+       }
+
+void
+lca_clock_fiddle(int divisor)
+{
+        long    pmr_reg;
+
+        pmr_reg = READ_PMR;
+        SET_PRIMARY_CLOCK(pmr_reg, divisor);
+/*        lca_norm_clock = divisor; */
+        WRITE_PMR(pmr_reg);
+        mb();
+}
+
 #endif /* CONFIG_ALPHA_LCA */
index 47fdf8e8b93ba6621890ceb85db70777a9d45600..705679019d51038e696756ed946bd7257f5c939b 100644 (file)
@@ -32,8 +32,9 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
-       unsigned long a3, unsigned long a4, unsigned long a5,
+asmlinkage int sys_sethae(unsigned long hae, unsigned long a1,
+                         unsigned long a2, unsigned long a3,
+                         unsigned long a4, unsigned long a5,
        struct pt_regs regs)
 {
        (&regs)->hae = hae;
@@ -52,8 +53,42 @@ asmlinkage int sys_idle(void)
        }
 }
 
+#include <asm/hwrpb.h>
+
+static void swap_context(struct thread_struct * pcb)
+{
+        __asm__ __volatile__(
+                "bis %0,%0,$16\n\t"
+                "call_pal %1\n\t"
+                : /* no outputs */
+                : "r" (pcb), "i" (PAL_swpctx)
+                : "$0", "$1", "$16", "$22", "$23", "$24", "$25");
+}
+
 void hard_reset_now(void)
 {
+#if defined(CONFIG_ALPHA_SRM_SETUP)
+       extern void reset_for_srm(void);        
+       extern struct hwrpb_struct *hwrpb;
+       extern struct thread_struct *original_pcb_ptr;
+       struct percpu_struct *cpup;
+       unsigned long flags;
+
+       cpup = (struct percpu_struct *)
+         ((unsigned long)hwrpb + hwrpb->processor_offset);
+       flags = cpup->flags;
+#if 1
+       printk("hard_reset_now: flags 0x%lx\n", flags);
+#endif
+       flags &= ~0x0000000000ff0001UL; /* clear reason to "default" */
+       flags |=  0x0000000000020000UL; /* this is "cold bootstrap" */
+/*     flags |=  0x0000000000030000UL; *//* this is "warm bootstrap" */
+/*     flags |=  0x0000000000040000UL; *//* this is "remain halted" */
+       cpup->flags = flags;
+       mb();
+       reset_for_srm();
+       swap_context(original_pcb_ptr);
+#endif
 #if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
        /* who said DEC engineer's have no sense of humor? ;-)) */
        *(int *) GRU_RESET = 0x0000dead;
diff --git a/arch/alpha/kernel/pyxis.c b/arch/alpha/kernel/pyxis.c
new file mode 100644 (file)
index 0000000..d74190d
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * Code common to all PYXIS chips.
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_PYXIS
+
+#ifdef DEBUG 
+# define DBG(args)     printk args
+#else
+# define DBG(args)
+#endif
+
+#define DEBUG_MCHECK
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args) printk args
+/* #define DEBUG_MCHECK_DUMP */
+#else
+# define DBG_MCK(args)
+#endif
+
+#define vuip   volatile unsigned int  *
+#define vulp   volatile unsigned long  *
+
+static volatile unsigned int PYXIS_mcheck_expected = 0;
+static volatile unsigned int PYXIS_mcheck_taken = 0;
+static unsigned int PYXIS_jd;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT;
+unsigned int PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT;
+unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the PYXIS_HAXR2 register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:11   Device select bit.
+ *     10:8    Function number
+ *      7:2    Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:24   reserved
+ *     23:16   bus number (8 bits = 128 possible buses)
+ *     15:11   Device number (5 bits)
+ *     10:8    function number
+ *      7:2    register number
+ *  
+ * Notes:
+ *     The function number selects which function of a multi-function device 
+ *     (e.g., scsi and ethernet).
+ * 
+ *     The register selects a DWORD (32 bit) register offset.  Hence it
+ *     doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *     bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+                       unsigned char where, unsigned long *pci_addr,
+                       unsigned char *type1)
+{
+       unsigned long addr;
+
+       DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+            bus, device_fn, where, pci_addr, type1));
+
+       if (bus == 0) {
+               int device;
+
+               device = device_fn >> 3;
+               /* type 0 configuration cycle: */
+#if NOT_NOW
+               if (device > 20) {
+                       DBG(("mk_conf_addr: device (%d) > 20, returning -1\n",
+                            device));
+                       return -1;
+               }
+#endif
+               *type1 = 0;
+               addr = (device_fn << 8) | (where);
+       } else {
+               /* type 1 configuration cycle: */
+               *type1 = 1;
+               addr = (bus << 16) | (device_fn << 8) | (where);
+       }
+       *pci_addr = addr;
+       DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+       return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+       unsigned long flags;
+       unsigned int stat0, value, temp;
+       unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+       save_flags(flags);      /* avoid getting hit by machine check */
+       cli();
+
+       DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+       /* reset status register to avoid losing errors: */
+       stat0 = *((vuip)PYXIS_ERR);
+       *((vuip)PYXIS_ERR) = stat0; mb();
+       temp = *((vuip)PYXIS_ERR);
+       DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0));
+       /* if Type1 access, must set PYXIS CFG */
+       if (type1) {
+               pyxis_cfg = *((vuip)PYXIS_CFG);
+               *((vuip)PYXIS_CFG) = pyxis_cfg | 1; mb();
+               temp = *((vuip)PYXIS_CFG);
+               DBG(("conf_read: TYPE1 access\n"));
+       }
+
+       mb();
+       draina();
+       PYXIS_mcheck_expected = 1;
+       PYXIS_mcheck_taken = 0;
+       mb();
+       /* access configuration space: */
+       value = *((vuip)addr);
+       mb();
+       mb();
+       if (PYXIS_mcheck_taken) {
+               PYXIS_mcheck_taken = 0;
+               value = 0xffffffffU;
+               mb();
+       }
+       PYXIS_mcheck_expected = 0;
+       mb();
+
+       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       if (type1) {
+               *((vuip)PYXIS_CFG) = pyxis_cfg & ~1; mb();
+               temp = *((vuip)PYXIS_CFG);
+       }
+
+       DBG(("conf_read(): finished\n"));
+
+       restore_flags(flags);
+       return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
+{
+       unsigned long flags;
+       unsigned int stat0, temp;
+       unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
+
+       save_flags(flags);      /* avoid getting hit by machine check */
+       cli();
+
+       /* reset status register to avoid losing errors: */
+       stat0 = *((vuip)PYXIS_ERR);
+       *((vuip)PYXIS_ERR) = stat0; mb();
+       temp = *((vuip)PYXIS_ERR);
+       DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0));
+       /* if Type1 access, must set PYXIS CFG */
+       if (type1) {
+               pyxis_cfg = *((vuip)PYXIS_CFG);
+               *((vuip)PYXIS_CFG) = pyxis_cfg | 1; mb();
+               temp = *((vuip)PYXIS_CFG);
+               DBG(("conf_read: TYPE1 access\n"));
+       }
+
+       draina();
+       PYXIS_mcheck_expected = 1;
+       mb();
+       /* access configuration space: */
+       *((vuip)addr) = value;
+       mb();
+       mb();
+       temp = *((vuip)PYXIS_ERR); /* do a PYXIS read to force the write */
+       PYXIS_mcheck_expected = 0;
+       mb();
+
+       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       if (type1) {
+               *((vuip)PYXIS_CFG) = pyxis_cfg & ~1; mb();
+               temp = *((vuip)PYXIS_CFG);
+       }
+
+       DBG(("conf_write(): finished\n"));
+       restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned char *value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xff;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= (pci_addr << 5) + 0x00;
+
+       *value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned short *value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xffff;
+
+       if (where & 0x1) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= (pci_addr << 5) + 0x08;
+
+       *value = conf_read(addr, type1) >> ((where & 3) * 8);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned int *value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xffffffff;
+       if (where & 0x3) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x18;
+       *value = conf_read(addr, type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned char value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x00;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned short value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x08;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+                               unsigned char where, unsigned int value)
+{
+       unsigned long addr = PYXIS_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x18;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
+{
+        unsigned int pyxis_err;
+
+#if 0
+printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK);
+printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR);
+
+printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ);
+printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK);
+printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE);
+printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO);
+printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG);
+printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT);
+#endif
+
+#if 0
+printk("pyxis_init: W0 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W0_BASE, *(vuip)PYXIS_W0_MASK, *(vuip)PYXIS_T0_BASE);
+printk("pyxis_init: W1 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W1_BASE, *(vuip)PYXIS_W1_MASK, *(vuip)PYXIS_T1_BASE);
+printk("pyxis_init: W2 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W2_BASE, *(vuip)PYXIS_W2_MASK, *(vuip)PYXIS_T2_BASE);
+printk("pyxis_init: W3 BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+       *(vuip)PYXIS_W3_BASE, *(vuip)PYXIS_W3_MASK, *(vuip)PYXIS_T3_BASE);
+#endif
+
+        /* 
+        * Set up error reporting. Make sure CPU_PE is OFF in the mask.
+        */
+       pyxis_err = *(vuip)PYXIS_ERR_MASK;
+       pyxis_err &= ~4;   
+       *(vuip)PYXIS_ERR_MASK = pyxis_err;
+       mb();
+       pyxis_err = *(vuip)PYXIS_ERR_MASK;
+
+       pyxis_err = *(vuip)PYXIS_ERR ;
+       pyxis_err |= 0x180;   /* master/target abort */
+       *(vuip)PYXIS_ERR = pyxis_err ;
+       mb() ;
+       pyxis_err = *(vuip)PYXIS_ERR ;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W0_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T0_BASE == 0) &&
+           ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 0 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W0_BASE,
+                *(vuip)PYXIS_W0_MASK,
+                *(vuip)PYXIS_T0_BASE);
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W1_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T1_BASE == 0) &&
+           ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U))
+{
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 1 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W1_BASE,
+                *(vuip)PYXIS_W1_MASK,
+                *(vuip)PYXIS_T1_BASE);
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W2_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T2_BASE == 0) &&
+           ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 2 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W2_BASE,
+                *(vuip)PYXIS_W2_MASK,
+                *(vuip)PYXIS_T2_BASE);
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W3_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T3_BASE == 0) &&
+           ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 3 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W3_BASE,
+                *(vuip)PYXIS_W3_MASK,
+                *(vuip)PYXIS_T3_BASE);
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#if 1
+       printk("pyxis_init: skipping window register rewrites... "
+              "trust DeskStation firmware!\n");
+#endif
+#else /* RUFFIAN */
+       /*
+        * Set up the PCI->physical memory translation windows.
+        * For now, windows 1,2 and 3 are disabled.  In the future, we may
+        * want to use them to do scatter/gather DMA.  Window 0
+        * goes at 1 GB and is 1 GB large.
+        */
+
+       *(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE & 0xfff00000U);
+       *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE - 1) & 0xfff00000U;
+       *(vuip)PYXIS_T0_BASE = 0;
+
+       *(vuip)PYXIS_W1_BASE = 0x0 ;
+       *(vuip)PYXIS_W2_BASE = 0x0 ;
+       *(vuip)PYXIS_W3_BASE = 0x0 ;
+       mb();
+#endif /* RUFFIAN */
+       }
+
+       /*
+        * check ASN in HWRPB for validity, report if bad
+        */
+       if (hwrpb->max_asn != MAX_ASN) {
+               printk("PYXIS_init: max ASN from HWRPB is bad (0x%lx)\n",
+                       hwrpb->max_asn);
+               hwrpb->max_asn = MAX_ASN;
+       }
+
+        /*
+         * Next, clear the PYXIS_CFG register, which gets used
+         *  for PCI Config Space accesses. That is the way
+         *  we want to use it, and we do not want to depend on
+         *  what ARC or SRM might have left behind...
+         */
+        {
+          unsigned int pyxis_cfg, temp;
+         pyxis_cfg = *((vuip)PYXIS_CFG); mb();
+         if (pyxis_cfg != 0) {
+#if 1
+           printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg);
+#endif
+           *((vuip)PYXIS_CFG) = 0; mb();
+           temp = *((vuip)PYXIS_CFG);
+         }
+        }
+        {
+          unsigned int pyxis_hae_mem = *((vuip)PYXIS_HAE_MEM);
+          unsigned int pyxis_hae_io = *((vuip)PYXIS_HAE_IO);
+#if 0
+         printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem);
+         printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io);
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+           sigh... For the SRM setup, unless we know apriori what the HAE
+           contents will be, we need to setup the arbitrary region bases
+           so we can test against the range of addresses and tailor the
+           region chosen for the SPARSE memory access.
+
+           see include/asm-alpha/pyxis.h for the SPARSE mem read/write
+         */
+         pyxis_sm_base_r1 = (pyxis_hae_mem      ) & 0xe0000000UL;/* region 1 */
+         pyxis_sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL;/* region 2 */
+         pyxis_sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL;/* region 3 */
+#else /* SRM_SETUP */
+          *((vuip)PYXIS_HAE_MEM) = 0U; mb();
+         pyxis_hae_mem = *((vuip)PYXIS_HAE_MEM);
+          *((vuip)PYXIS_HAE_IO) = 0; mb();
+         pyxis_hae_io = *((vuip)PYXIS_HAE_IO);
+#endif /* SRM_SETUP */
+        }
+
+       /*
+        * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
+        * enabling byte/word PCI bus space(s) access.
+        */
+       {
+         unsigned int ctrl1;
+         ctrl1 = *((vuip) PYXIS_CTRL1);
+         if (!(ctrl1 & 1)) {
+#if 0
+           printk("PYXIS_init: enabling byte/word PCI space\n");
+#endif
+           *((vuip) PYXIS_CTRL1) = ctrl1 | 1; mb();
+           ctrl1 = *((vuip)PYXIS_CTRL1);
+         }
+       }
+
+       return mem_start;
+}
+
+int pyxis_pci_clr_err(void)
+{
+       PYXIS_jd = *((vuip)PYXIS_ERR);
+       DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
+       *((vuip)PYXIS_ERR) = 0x0180; mb();
+       PYXIS_jd = *((vuip)PYXIS_ERR);
+       return 0;
+}
+
+void pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
+                        struct pt_regs * regs)
+{
+#if 0
+        printk("PYXIS machine check ignored\n") ;
+#else
+       struct el_common *mchk_header;
+       struct el_PYXIS_sysdata_mcheck *mchk_sysdata;
+
+       mchk_header = (struct el_common *)la_ptr;
+
+       mchk_sysdata = 
+         (struct el_PYXIS_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
+
+#if 0
+       DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+            vector, la_ptr));
+       DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->size, mchk_header->proc_offset,
+            mchk_header->sys_offset));
+       DBG_MCK(("pyxis_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+            PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr,
+            mchk_sysdata->epic_pear));
+#endif
+#ifdef DEBUG_MCHECK_DUMP
+       {
+           unsigned long *ptr;
+           int i;
+
+           ptr = (unsigned long *)la_ptr;
+           for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+               printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+           }
+       }
+#endif /* DEBUG_MCHECK_DUMP */
+       /*
+        * Check if machine check is due to a badaddr() and if so,
+        * ignore the machine check.
+        */
+       mb();
+       mb();
+       if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+               DBG(("PYXIS machine check expected\n"));
+               PYXIS_mcheck_expected = 0;
+               PYXIS_mcheck_taken = 1;
+               mb();
+               mb();
+               draina();
+               pyxis_pci_clr_err();
+               wrmces(0x7);
+               mb();
+       }
+#if 1
+       else {
+               printk("PYXIS machine check NOT expected\n") ;
+       DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+            vector, la_ptr));
+       DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->size, mchk_header->proc_offset,
+            mchk_header->sys_offset));
+               PYXIS_mcheck_expected = 0;
+               PYXIS_mcheck_taken = 1;
+               mb();
+               mb();
+               draina();
+               pyxis_pci_clr_err();
+               wrmces(0x7);
+               mb();
+       }
+#endif
+#endif
+}
+
+#if defined(CONFIG_ALPHA_RUFFIAN)
+/* NOTE: this is only used by MILO, AFAIK... */
+/*
+ * The DeskStation Ruffian motherboard firmware does not place
+ * the memory size in the PALimpure area.  Therefore, it uses
+ * the Bank Configuration Registers in PYXIS to obtain the size.
+ */
+unsigned long pyxis_get_bank_size(unsigned long offset)
+{
+  unsigned long      bank_addr;
+  
+  /* valid offsets are: 0x800, 0x840 and 0x880
+   * since Ruffian only uses three banks
+   */
+  bank_addr = (unsigned long)PYXIS_MCR + offset;
+  
+  /* check BANK_ENABLE */
+  if (*((unsigned long *)bank_addr) && 0x01)
+    {
+      /* do case on BANK_SIZE bits */
+      switch (*((unsigned long *)bank_addr) & 0x01e)
+       {
+       case 0x00: return 0x40000000UL; break; /*   1G */
+       case 0x02: return 0x20000000UL; break; /* 512M */
+       case 0x04: return 0x10000000UL; break; /* 256M */
+       case 0x06: return 0x08000000UL; break; /* 128M */
+       case 0x08: return 0x04000000UL; break; /*  64M */
+       case 0x0a: return 0x02000000UL; break; /*  32M */
+       case 0x0c: return 0x01000000UL; break; /*  16M */
+       case 0x0e: return 0x00800000UL; break; /*   8M */
+       case 0x10: return 0x80000000UL; break; /*   2G */
+       default  : return 0x00000000UL; break; /* ERROR*/
+       }
+    } else
+      return 0x00UL;
+}
+#endif /* CONFIG_ALPHA_RUFFIAN */
+
+#endif /* CONFIG_ALPHA_PYXIS */
index 7ad7c41ab0817557ee01012cd41cf37b9744e78e..5281161552c079c5b4c209105d8c770098f7f574 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/config.h>      /* CONFIG_ALPHA_LCA etc */
+#include <linux/mc146818rtc.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
@@ -58,13 +59,26 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
  * code think we're on a VGA color display.
  */
 struct screen_info screen_info = {
+#if defined(CONFIG_ALPHA_BOOK1)
+  /* the AlphaBook1 has LCD video fixed at 800x600, 37 rows and 100 cols */
+       0, 37,                  /* orig-x, orig-y */
+#else
        0, 25,                  /* orig-x, orig-y */
+#endif
        { 0, 0 },               /* unused */
        0,                      /* orig-video-page */
        0,                      /* orig-video-mode */
+#if defined(CONFIG_ALPHA_BOOK1)
+        100,                   /* orig-video-cols */
+#else
        80,                     /* orig-video-cols */
+#endif
        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+#if defined(CONFIG_ALPHA_BOOK1)
+        37,                    /* orig-video-lines */
+#else
        25,                     /* orig-video-lines */
+#endif
        1,                      /* orig-video-isVGA */
        16                      /* orig-video-points */
 };
@@ -84,9 +98,12 @@ static void init_pit (void)
     outb(0x18, 0x41);
 #endif
 
+#if !defined(CONFIG_ALPHA_RUFFIAN)
+    /* Ruffian depends on the system timer established in MILO!! */
     outb(0x36, 0x43);  /* counter 0: system timer */
     outb(0x00, 0x40);
     outb(0x00, 0x40);
+#endif /* RUFFIAN */
 
     outb(0xb6, 0x43);  /* counter 2: speaker */
     outb(0x31, 0x42);
@@ -121,9 +138,19 @@ void setup_arch(char **cmdline_p,
 
        init_pit();
 
+       if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
+#if 1
+         printk("init_timers: setting RTC_FREQ to 1024/sec\n");
+#endif
+         CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+       }
+
        hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
 
+#ifndef CONFIG_ALPHA_SRM_SETUP
        set_hae(hae.cache);     /* sync HAE register w/hae_cache */
+#endif /* !SRM_SETUP */
+
        wrmces(0x7);            /* reset enable correctable error reports */
 
        ROOT_DEV = to_kdev_t(0x0802);           /* sda2 */
@@ -154,39 +181,161 @@ void setup_arch(char **cmdline_p,
        *memory_start_p = apecs_init(*memory_start_p, *memory_end_p);
 #elif defined(CONFIG_ALPHA_CIA)
        *memory_start_p = cia_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_PYXIS)
+       *memory_start_p = pyxis_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_T2)
+       *memory_start_p = t2_init(*memory_start_p, *memory_end_p);
 #endif
 }
 
-/*
- * BUFFER is PAGE_SIZE bytes long.
+#      define N(a)     (sizeof(a)/sizeof(a[0]))
+
+/* A change was made to the HWRPB via an ECO and the following code tracks
+ * a part of the ECO.  The HWRPB version must be 5 or higher or the ECO
+ * was not implemented in the console firmware.  If its at rev 5 or greater
+ * we can get the platform ascii string name from the HWRPB.  Thats what this
+ * function does.  It checks the rev level and if the string is in the HWRPB
+ * it returns the addtess of the string ... a pointer to the platform name.
+ *
+ * Returns:
+ *      - Pointer to a ascii string if its in the HWRPB
+ *      - Pointer to a blank string if the data is not in the HWRPB.
  */
+static char *
+platform_string(void)
+{
+       struct dsr_struct *dsr;
+       static char unk_system_string[] = "N/A";
+
+        /* Go to the console for the string pointer.
+         * If the rpb_vers is not 5 or greater the rpb
+        * is old and does not have this data in it.
+        */
+        if (hwrpb->revision < 5)
+               return (unk_system_string);
+       else {
+               /* The Dynamic System Recognition struct
+                * has the system platform name starting
+                * after the character count of the string.
+                */
+               dsr =  ((struct dsr_struct *)
+                         ((char *)hwrpb + hwrpb->dsr_offset));
+               return ((char *)dsr + (dsr->sysname_off +
+                                                sizeof(long)));
+        }
+}
+
+static void
+get_sysnames(long type, long variation,
+            char **type_name, char **variation_name)
+{
+       static char *sys_unknown = "Unknown";
+       static char *systype_names[] = {
+               "0",
+               "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen",
+               "Pelican", "Morgan", "Sable", "Medulla", "Noname",
+               "Turbolaser", "Avanti", "14", "Alcor", "Tradewind",
+               "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
+               "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
+               "Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
+               "Tsunami", "Wildfire", "CUSCO"
+       };
+
+       static char *unofficial_names[] = {
+               "100",
+               "Ruffian"
+       };
+
+       static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"};
+       static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3};
+
+       static char * alcor_names[] = {"Alcor", "Maverick", "Bret"};
+       static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2};
+
+       static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"};
+       static int eb64p_indices[] = {0,0,1.2};
+
+       static char * eb66_names[] = {"EB66", "EB66+"};
+       static int eb66_indices[] = {0,0,1};
+
+       static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango",
+                                        "Tincup", "DaVinci"};
+       static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+
+       long member;
+       
+
+       /* restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
+       if (type < 0) type = -type;
+
+       /* if not in the tables, make it UNKNOWN */
+       /* else set type name to family */
+       if (type < N(systype_names)) {
+           *type_name = systype_names[type];
+       } else
+       if ((type > ST_UNOFFICIAL_BIAS) &&
+           (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) {
+           *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS];
+       } else {
+           *type_name = sys_unknown;
+           *variation_name = sys_unknown;
+           return;
+       }
+
+       /* set variation to "0"; if variation is zero, done */
+       *variation_name = systype_names[0];
+       if (variation == 0) {
+               return;
+       }
+
+       member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
+
+       switch (type) { /* select by family */
+       default: /* default to variation "0" ????FIXME???? */
+               break;
+       case ST_DEC_EB164:
+               if (member < N(eb164_indices))
+                 *variation_name = eb164_names[eb164_indices[member]];
+               break;
+       case ST_DEC_ALCOR:
+               if (member < N(alcor_indices))
+                 *variation_name = alcor_names[alcor_indices[member]];
+               break;
+       case ST_DEC_EB64P:
+               if (member < N(eb64p_indices))
+                 *variation_name = eb64p_names[eb64p_indices[member]];
+               break;
+       case ST_DEC_EB66:
+               if (member < N(eb66_indices))
+                 *variation_name = eb66_names[eb66_indices[member]];
+               break;
+       case ST_DEC_RAWHIDE:
+               if (member < N(rawhide_indices))
+                 *variation_name = rawhide_names[rawhide_indices[member]];
+               break;
+       } /* end family switch */
+       return;
+}
+
 int get_cpuinfo(char *buffer)
+/* BUFFER is PAGE_SIZE bytes long. */
 {
        const char *cpu_name[] = {
-               "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45"
-       };
-#      define SYSTYPE_NAME_BIAS        20
-       const char *systype_name[] = {
-               "Cabriolet", "EB66P", "-18", "-17", "-16", "-15",
-               "-14", "-13", "-12", "-11", "-10", "-9", "-8",
-               "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0",
-               "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen",
-               "Pelican", "8", "Sable", "AXPvme", "Noname",
-               "Turbolaser", "Avanti", "Mustang", "Alcor", "16",
-               "Mikasa", "18", "EB66", "EB64+", "21", "22", "23",
-               "24", "25", "EB164"
+               "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56",
+               "EV6", "PCA56"
        };
        struct percpu_struct *cpu;
        unsigned int cpu_index;
-       long sysname_index;
+       char *systype_name;
+       char *sysvariation_name;
        extern struct unaligned_stat {
                unsigned long count, va, pc;
        } unaligned[2];
-#      define N(a)     (sizeof(a)/sizeof(a[0]))
 
        cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
        cpu_index = (unsigned) (cpu->type - 1);
-       sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS;
+       get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
+                    &systype_name, &sysvariation_name);
 
        return sprintf(buffer,
                       "cpu\t\t\t: Alpha\n"
@@ -195,7 +344,7 @@ int get_cpuinfo(char *buffer)
                       "cpu revision\t\t: %ld\n"
                       "cpu serial number\t: %s\n"
                       "system type\t\t: %s\n"
-                      "system variation\t: %ld\n"
+                      "system variation\t: %s\n"
                       "system revision\t\t: %ld\n"
                       "system serial number\t: %s\n"
                       "cycle frequency [Hz]\t: %lu\n"
@@ -205,14 +354,13 @@ int get_cpuinfo(char *buffer)
                       "max. addr. space #\t: %ld\n"
                       "BogoMIPS\t\t: %lu.%02lu\n"
                       "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-                      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n",
+                      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
+                      "platform string\t\t: %s\n",
 
                       (cpu_index < N(cpu_name)
                        ? cpu_name[cpu_index] : "Unknown"),
                       cpu->variation, cpu->revision, (char*)cpu->serial_no,
-                      (sysname_index < N(systype_name)
-                       ? systype_name[sysname_index] : "Unknown"),
-                      hwrpb->sys_variation, hwrpb->sys_revision,
+                      systype_name, sysvariation_name, hwrpb->sys_revision,
                       (char*)hwrpb->ssn,
                       hwrpb->cycle_freq,
                       hwrpb->intr_freq / 4096,
@@ -222,6 +370,7 @@ int get_cpuinfo(char *buffer)
                       hwrpb->max_asn,
                       loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
                       unaligned[0].count, unaligned[0].pc, unaligned[0].va,
-                      unaligned[1].count, unaligned[1].pc, unaligned[1].va);
-#       undef N
+                      unaligned[1].count, unaligned[1].pc, unaligned[1].va,
+                      platform_string());
 }
+#       undef N
index 91abaf4f0390afed51f48dcaca1bb11c41e75b17..91fd485a164b6aa94b313cb95d89eeb4097ec18a 100644 (file)
@@ -203,6 +203,9 @@ static void setup_frame(struct sigaction * sa,
        put_fs_quad(regs->gp , sc->sc_regs+29);
        for (i = 0; i < 31; i++)
                put_fs_quad(sw->fp[i], sc->sc_fpregs+i);
+       put_fs_quad(regs->trap_a0, &sc->sc_traparg_a0);
+       put_fs_quad(regs->trap_a1, &sc->sc_traparg_a1);
+       put_fs_quad(regs->trap_a2, &sc->sc_traparg_a2);
 
        /*
         * The following is:
diff --git a/arch/alpha/kernel/smc.c b/arch/alpha/kernel/smc.c
new file mode 100644 (file)
index 0000000..ae9f5d8
--- /dev/null
@@ -0,0 +1,2842 @@
+/*
+ * SMC 37C93X and 37C669 initialization code
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#if 0
+# define DBG_DEVS(args)                printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/hwrpb.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+
+#define KB             1024
+#define MB             (1024*KB)
+#define GB             (1024*MB)
+
+#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
+
+/* device "activate" register contents */
+#define DEVICE_ON              1
+#define DEVICE_OFF             0
+
+/* configuration on/off keys */
+#define CONFIG_ON_KEY          0x55
+#define CONFIG_OFF_KEY         0xaa
+
+/* configuration space device definitions */
+#define FDC                    0
+#define IDE1                   1
+#define IDE2                   2
+#define PARP                   3
+#define SER1                   4
+#define SER2                   5
+#define RTCL                   6
+#define KYBD                   7
+#define AUXIO                  8
+
+/* Chip register offsets from base */
+#define CONFIG_CONTROL         0x02
+#define INDEX_ADDRESS          0x03
+#define LOGICAL_DEVICE_NUMBER  0x07
+#define DEVICE_ID              0x20
+#define DEVICE_REV             0x21
+#define POWER_CONTROL          0x22
+#define POWER_MGMT             0x23
+#define OSC                    0x24
+
+#define ACTIVATE               0x30
+#define ADDR_HI                        0x60
+#define ADDR_LO                        0x61
+#define INTERRUPT_SEL          0x70
+#define INTERRUPT_SEL_2                0x72 /* KYBD/MOUS only */
+#define DMA_CHANNEL_SEL                0x74 /* FDC/PARP only */
+
+#define FDD_MODE_REGISTER      0x90
+#define FDD_OPTION_REGISTER    0x91
+
+/* values that we read back that are expected ... */
+#define VALID_DEVICE_ID                2
+
+/* default device addresses */
+#define KYBD_INTERRUPT         1
+#define MOUS_INTERRUPT         12
+#define COM2_BASE              0x2f8
+#define COM2_INTERRUPT         3
+#define COM1_BASE              0x3f8
+#define COM1_INTERRUPT         4
+#define PARP_BASE              0x3bc
+#define PARP_INTERRUPT         7
+
+#define SMC_DEBUG 0
+
+unsigned long SMCConfigState( unsigned long baseAddr )
+{
+    unsigned char devId;
+    unsigned char devRev;
+
+    unsigned long configPort;
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    configPort = indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )configPort + 1 );
+
+    outb(CONFIG_ON_KEY, configPort);
+    outb(CONFIG_ON_KEY, configPort);
+    outb(DEVICE_ID, indexPort);
+    devId = inb(dataPort);
+    if ( devId == VALID_DEVICE_ID ) {
+        outb(DEVICE_REV, indexPort);
+        devRev = inb(dataPort);
+    }
+    else {
+        baseAddr = 0;
+    }
+    return( baseAddr );
+}
+
+void SMCRunState( unsigned long baseAddr )
+{
+    outb(CONFIG_OFF_KEY, baseAddr);
+}
+
+unsigned long SMCDetectUltraIO(void)
+{
+    unsigned long baseAddr;
+
+    baseAddr = 0x3F0;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
+        return( baseAddr );
+    }
+    baseAddr = 0x370;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
+        return( baseAddr );
+    }
+    return( ( unsigned long )0 );
+}
+
+void SMCEnableDevice( unsigned long baseAddr,
+                     unsigned long device,
+                     unsigned long portaddr,
+                     unsigned long interrupt)
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(device, dataPort);
+
+    outb(ADDR_LO, indexPort);
+    outb(( portaddr & 0xFF ), dataPort);
+
+    outb(ADDR_HI, indexPort);
+    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
+
+    outb(INTERRUPT_SEL, indexPort);
+    outb(interrupt, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableKYBD( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(KYBD, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(KYBD_INTERRUPT, dataPort);
+
+    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
+    outb(MOUS_INTERRUPT, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableFDC( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    unsigned char oldValue;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(FDC, dataPort);
+
+    outb(FDD_MODE_REGISTER, indexPort);
+    oldValue = inb(dataPort);
+
+    oldValue |= 0x0E;                   /* Enable burst mode */
+    outb(oldValue, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(0x06, dataPort );
+
+    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
+    outb(0x02, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+#if SMC_DEBUG
+void SMCReportDeviceStatus( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+    unsigned char currentControl;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(POWER_CONTROL, indexPort);
+    currentControl = inb(dataPort);
+
+    if ( currentControl & ( 1 << FDC ) )
+        printk( "\t+FDC Enabled\n" );
+    else
+        printk( "\t-FDC Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE1 ) )
+        printk( "\t+IDE1 Enabled\n" );
+    else
+        printk( "\t-IDE1 Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE2 ) )
+        printk( "\t+IDE2 Enabled\n" );
+    else
+        printk( "\t-IDE2 Disabled\n" );
+
+    if ( currentControl & ( 1 << PARP ) )
+        printk( "\t+PARP Enabled\n" );
+    else
+        printk( "\t-PARP Disabled\n" );
+
+    if ( currentControl & ( 1 << SER1 ) )
+        printk( "\t+SER1 Enabled\n" );
+    else
+        printk( "\t-SER1 Disabled\n" );
+
+    if ( currentControl & ( 1 << SER2 ) )
+        printk( "\t+SER2 Enabled\n" );
+    else
+        printk( "\t-SER2 Disabled\n" );
+
+    printk( "\n" );
+}
+#endif
+
+void SMC93X_Init(void)
+{
+    unsigned long SMCUltraBase;
+
+    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
+        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
+               SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
+       /* IDE on the SMC is not enabled; CMD646 (PCI) on MB */
+        SMCEnableKYBD( SMCUltraBase );
+        SMCEnableFDC( SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCRunState( SMCUltraBase );
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
+#endif
+    }
+}
+
+#endif /* PC164 || LX164 */
+
+/* we include MIATA because the GL has the SMC669 on board */
+#if defined(CONFIG_ALPHA_SX164) || defined(CONFIG_ALPHA_MIATA)
+
+#define SMC_DEBUG   0
+
+/* File:       smcc669_def.h
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  of  the  terms  of  such  license  and with the
+ * inclusion of the above copyright notice. This software or  any  other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ * The information in this software is  subject to change without notice
+ * and  should  not  be  construed  as a commitment by Digital Equipment
+ * Corporation.
+ *
+ * Digital assumes no responsibility for the use  or  reliability of its
+ * software on equipment which is not supplied by Digital.
+ *
+ *
+ * Abstract:   
+ *
+ *     This file contains header definitions for the SMC37c669 
+ *     Super I/O controller. 
+ *
+ * Author:     
+ *
+ *     Eric Rasmussen
+ *
+ * Modification History:
+ *
+ *     er      28-Jan-1997     Initial Entry
+ */
+
+#ifndef __SMC37c669_H
+#define __SMC37c669_H
+
+/*
+** Macros for handling device IRQs
+**
+** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15) 
+** to device IRQs (A - H).
+*/
+#define SMC37c669_DEVICE_IRQ_MASK      0x80000000
+#define SMC37c669_DEVICE_IRQ( __i )    \
+       ((SMC37c669_DEVICE_IRQ_MASK) | (__i))
+#define SMC37c669_IS_DEVICE_IRQ(__i)   \
+       (((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK))
+#define SMC37c669_RAW_DEVICE_IRQ(__i)  \
+       ((__i) & ~(SMC37c669_DEVICE_IRQ_MASK))
+
+/*
+** Macros for handling device DRQs
+**
+** The mask acts as a flag used in mapping actual ISA DMA
+** channels to device DMA channels (A - C).
+*/
+#define SMC37c669_DEVICE_DRQ_MASK      0x80000000
+#define SMC37c669_DEVICE_DRQ(__d)      \
+       ((SMC37c669_DEVICE_DRQ_MASK) | (__d))
+#define SMC37c669_IS_DEVICE_DRQ(__d)   \
+       (((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK))
+#define SMC37c669_RAW_DEVICE_DRQ(__d)  \
+       ((__d) & ~(SMC37c669_DEVICE_DRQ_MASK))
+
+#define SMC37c669_DEVICE_ID    0x3
+
+/*
+** SMC37c669 Device Function Definitions
+*/
+#define SERIAL_0       0
+#define SERIAL_1       1
+#define PARALLEL_0     2
+#define FLOPPY_0       3
+#define IDE_0          4
+#define NUM_FUNCS      5
+
+/*
+** Default Device Function Mappings
+*/
+#define COM1_BASE      0x3F8
+#define COM1_IRQ       4
+#define COM2_BASE      0x2F8
+#define COM2_IRQ       3
+#define PARP_BASE      0x3BC
+#define PARP_IRQ       7
+#define PARP_DRQ       3
+#define FDC_BASE       0x3F0
+#define FDC_IRQ                6
+#define FDC_DRQ                2
+
+/*
+** Configuration On/Off Key Definitions
+*/
+#define SMC37c669_CONFIG_ON_KEY                0x55
+#define SMC37c669_CONFIG_OFF_KEY       0xAA
+
+/*
+** SMC 37c669 Device IRQs
+*/
+#define SMC37c669_DEVICE_IRQ_A     ( SMC37c669_DEVICE_IRQ( 0x01 ) )
+#define SMC37c669_DEVICE_IRQ_B     ( SMC37c669_DEVICE_IRQ( 0x02 ) )
+#define SMC37c669_DEVICE_IRQ_C     ( SMC37c669_DEVICE_IRQ( 0x03 ) )
+#define SMC37c669_DEVICE_IRQ_D     ( SMC37c669_DEVICE_IRQ( 0x04 ) )
+#define SMC37c669_DEVICE_IRQ_E     ( SMC37c669_DEVICE_IRQ( 0x05 ) )
+#define SMC37c669_DEVICE_IRQ_F     ( SMC37c669_DEVICE_IRQ( 0x06 ) )
+/*      SMC37c669_DEVICE_IRQ_G     *** RESERVED ***/
+#define SMC37c669_DEVICE_IRQ_H     ( SMC37c669_DEVICE_IRQ( 0x08 ) )
+
+/*
+** SMC 37c669 Device DMA Channel Definitions
+*/
+#define SMC37c669_DEVICE_DRQ_A             ( SMC37c669_DEVICE_DRQ( 0x01 ) )
+#define SMC37c669_DEVICE_DRQ_B             ( SMC37c669_DEVICE_DRQ( 0x02 ) )
+#define SMC37c669_DEVICE_DRQ_C             ( SMC37c669_DEVICE_DRQ( 0x03 ) )
+
+/*
+** Configuration Register Index Definitions
+*/
+#define SMC37c669_CR00_INDEX       0x00
+#define SMC37c669_CR01_INDEX       0x01
+#define SMC37c669_CR02_INDEX       0x02
+#define SMC37c669_CR03_INDEX       0x03
+#define SMC37c669_CR04_INDEX       0x04
+#define SMC37c669_CR05_INDEX       0x05
+#define SMC37c669_CR06_INDEX       0x06
+#define SMC37c669_CR07_INDEX       0x07
+#define SMC37c669_CR08_INDEX       0x08
+#define SMC37c669_CR09_INDEX       0x09
+#define SMC37c669_CR0A_INDEX       0x0A
+#define SMC37c669_CR0B_INDEX       0x0B
+#define SMC37c669_CR0C_INDEX       0x0C
+#define SMC37c669_CR0D_INDEX       0x0D
+#define SMC37c669_CR0E_INDEX       0x0E
+#define SMC37c669_CR0F_INDEX       0x0F
+#define SMC37c669_CR10_INDEX       0x10
+#define SMC37c669_CR11_INDEX       0x11
+#define SMC37c669_CR12_INDEX       0x12
+#define SMC37c669_CR13_INDEX       0x13
+#define SMC37c669_CR14_INDEX       0x14
+#define SMC37c669_CR15_INDEX       0x15
+#define SMC37c669_CR16_INDEX       0x16
+#define SMC37c669_CR17_INDEX       0x17
+#define SMC37c669_CR18_INDEX       0x18
+#define SMC37c669_CR19_INDEX       0x19
+#define SMC37c669_CR1A_INDEX       0x1A
+#define SMC37c669_CR1B_INDEX       0x1B
+#define SMC37c669_CR1C_INDEX       0x1C
+#define SMC37c669_CR1D_INDEX       0x1D
+#define SMC37c669_CR1E_INDEX       0x1E
+#define SMC37c669_CR1F_INDEX       0x1F
+#define SMC37c669_CR20_INDEX       0x20
+#define SMC37c669_CR21_INDEX       0x21
+#define SMC37c669_CR22_INDEX       0x22
+#define SMC37c669_CR23_INDEX       0x23
+#define SMC37c669_CR24_INDEX       0x24
+#define SMC37c669_CR25_INDEX       0x25
+#define SMC37c669_CR26_INDEX       0x26
+#define SMC37c669_CR27_INDEX       0x27
+#define SMC37c669_CR28_INDEX       0x28
+#define SMC37c669_CR29_INDEX       0x29
+
+/*
+** Configuration Register Alias Definitions
+*/
+#define SMC37c669_DEVICE_ID_INDEX                  SMC37c669_CR0D_INDEX
+#define SMC37c669_DEVICE_REVISION_INDEX                    SMC37c669_CR0E_INDEX
+#define SMC37c669_FDC_BASE_ADDRESS_INDEX           SMC37c669_CR20_INDEX
+#define SMC37c669_IDE_BASE_ADDRESS_INDEX           SMC37c669_CR21_INDEX
+#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX      SMC37c669_CR22_INDEX
+#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX     SMC37c669_CR23_INDEX
+#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX       SMC37c669_CR24_INDEX
+#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX       SMC37c669_CR25_INDEX
+#define SMC37c669_PARALLEL_FDC_DRQ_INDEX           SMC37c669_CR26_INDEX
+#define SMC37c669_PARALLEL_FDC_IRQ_INDEX           SMC37c669_CR27_INDEX
+#define SMC37c669_SERIAL_IRQ_INDEX                 SMC37c669_CR28_INDEX
+
+/*
+** Configuration Register Definitions
+**
+** The INDEX (write only) and DATA (read/write) ports are effective 
+** only when the chip is in the Configuration State.
+*/
+typedef struct _SMC37c669_CONFIG_REGS {
+    unsigned char index_port;
+    unsigned char data_port;
+} SMC37c669_CONFIG_REGS;
+
+/*
+** CR00 - default value 0x28
+**
+**  IDE_EN (CR00<1:0>):
+**     0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1
+**     11 - IRQ_H available as IRQ output,
+**          IRRX2, IRTX2 available as alternate IR pins
+**     10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE
+**
+**  VALID (CR00<7>):
+**     A high level on this software controlled bit can
+**     be used to indicate that a valid configuration
+**     cycle has occurred.  The control software must
+**     take care to set this bit at the appropriate times.
+**     Set to zero after power up.  This bit has no
+**     effect on any other hardware in the chip.
+**
+*/
+typedef union _SMC37c669_CR00 {
+    unsigned char as_uchar;
+    struct {
+       unsigned ide_en : 2;        /* See note above           */
+       unsigned reserved1 : 1;     /* RAZ                      */
+       unsigned fdc_pwr : 1;       /* 1 = supply power to FDC  */
+       unsigned reserved2 : 3;     /* Read as 010b             */
+       unsigned valid : 1;         /* See note above           */
+    }  by_field;
+} SMC37c669_CR00;
+
+/*
+** CR01 - default value 0x9C
+*/
+typedef union _SMC37c669_CR01 {
+    unsigned char as_uchar;
+    struct {
+       unsigned reserved1 : 2;     /* RAZ                          */
+       unsigned ppt_pwr : 1;       /* 1 = supply power to PPT      */
+       unsigned ppt_mode : 1;      /* 1 = Printer mode, 0 = EPP    */
+       unsigned reserved2 : 1;     /* Read as 1                    */
+       unsigned reserved3 : 2;     /* RAZ                          */
+       unsigned lock_crx: 1;       /* Lock CR00 - CR18             */
+    }  by_field;
+} SMC37c669_CR01;
+
+/*
+** CR02 - default value 0x88
+*/
+typedef union _SMC37c669_CR02 {
+    unsigned char as_uchar;
+    struct {
+       unsigned reserved1 : 3;     /* RAZ                          */
+       unsigned uart1_pwr : 1;     /* 1 = supply power to UART1    */
+       unsigned reserved2 : 3;     /* RAZ                          */
+       unsigned uart2_pwr : 1;     /* 1 = supply power to UART2    */
+    }  by_field;
+} SMC37c669_CR02;
+
+/*
+** CR03 - default value 0x78
+**
+**  CR03<7>    CR03<2>     Pin 94
+**  -------    -------     ------
+**     0          X        DRV2 (input)
+**     1          0        ADRX
+**     1          1        IRQ_B
+**
+**  CR03<6>    CR03<5>     Op Mode
+**  -------    -------     -------
+**     0          0        Model 30
+**     0          1        PS/2
+**     1          0        Reserved
+**     1          1        AT Mode
+*/
+typedef union _SMC37c669_CR03 {
+    unsigned char as_uchar;
+    struct {
+       unsigned pwrgd_gamecs : 1;  /* 1 = PWRGD, 0 = GAMECS        */
+       unsigned fdc_mode2 : 1;     /* 1 = Enhanced Mode 2          */
+       unsigned pin94_0 : 1;       /* See note above               */
+       unsigned reserved1 : 1;     /* RAZ                          */
+       unsigned drvden : 1;        /* 1 = high, 0 - output         */
+       unsigned op_mode : 2;       /* See note above               */
+       unsigned pin94_1 : 1;       /* See note above               */
+    }  by_field;
+} SMC37c669_CR03;
+
+/*
+** CR04 - default value 0x00
+**
+**  PP_EXT_MODE:
+**     If CR01<PP_MODE> = 0 and PP_EXT_MODE =
+**         00 - Standard and Bidirectional
+**         01 - EPP mode and SPP
+**         10 - ECP mode
+**              In this mode, 2 drives can be supported
+**              directly, 3 or 4 drives must use external
+**              4 drive support.  SPP can be selected
+**              through the ECR register of ECP as mode 000.
+**         11 - ECP mode and EPP mode
+**              In this mode, 2 drives can be supported
+**              directly, 3 or 4 drives must use external
+**              4 drive support.  SPP can be selected
+**              through the ECR register of ECP as mode 000.
+**              In this mode, EPP can be selected through
+**              the ECR register of ECP as mode 100.
+**
+**  PP_FDC:
+**     00 - Normal
+**     01 - PPFD1
+**     10 - PPFD2
+**     11 - Reserved
+**
+**  MIDI1:
+**     Serial Clock Select: 
+**         A low level on this bit disables MIDI support,
+**         clock = divide by 13.  A high level on this 
+**         bit enables MIDI support, clock = divide by 12.
+**
+**     MIDI operates at 31.25 Kbps which can be derived 
+**     from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz)
+**
+**  ALT_IO:
+**     0 - Use pins IRRX, IRTX
+**     1 - Use pins IRRX2, IRTX2
+**
+**     If this bit is set, the IR receive and transmit
+**     functions will not be available on pins 25 and 26
+**     unless CR00<IDE_EN> = 11.
+*/
+typedef union _SMC37c669_CR04 {
+    unsigned char as_uchar;
+    struct {
+       unsigned ppt_ext_mode : 2;  /* See note above               */
+       unsigned ppt_fdc : 2;       /* See note above               */
+       unsigned midi1 : 1;         /* See note above               */
+       unsigned midi2 : 1;         /* See note above               */
+       unsigned epp_type : 1;      /* 0 = EPP 1.9, 1 = EPP 1.7     */
+       unsigned alt_io : 1;        /* See note above               */
+    }  by_field;
+} SMC37c669_CR04;
+
+/*
+** CR05 - default value 0x00
+**
+**  DEN_SEL:
+**     00 - Densel output normal
+**     01 - Reserved
+**     10 - Densel output 1
+**     11 - Densel output 0
+**
+*/
+typedef union _SMC37c669_CR05 {
+    unsigned char as_uchar;
+    struct {
+       unsigned reserved1 : 2;     /* RAZ                                      */
+       unsigned fdc_dma_mode : 1;  /* 0 = burst, 1 = non-burst                 */
+       unsigned den_sel : 2;       /* See note above                           */
+       unsigned swap_drv : 1;      /* Swap the FDC motor selects               */
+       unsigned extx4 : 1;         /* 0 = 2 drive, 1 = external 4 drive decode */
+       unsigned reserved2 : 1;     /* RAZ                                      */
+    }  by_field;
+} SMC37c669_CR05;
+
+/*
+** CR06 - default value 0xFF
+*/
+typedef union _SMC37c669_CR06 {
+    unsigned char as_uchar;
+    struct {
+       unsigned floppy_a : 2;      /* Type of floppy drive A       */
+       unsigned floppy_b : 2;      /* Type of floppy drive B       */
+       unsigned floppy_c : 2;      /* Type of floppy drive C       */
+       unsigned floppy_d : 2;      /* Type of floppy drive D       */
+    }  by_field;
+} SMC37c669_CR06;
+
+/*
+** CR07 - default value 0x00
+**
+**  Auto Power Management CR07<7:4>:
+**     0 - Auto Powerdown disabled (default)
+**     1 - Auto Powerdown enabled
+**
+**     This bit is reset to the default state by POR or
+**     a hardware reset.
+**
+*/
+typedef union _SMC37c669_CR07 {
+    unsigned char as_uchar;
+    struct {
+       unsigned floppy_boot : 2;   /* 0 = A:, 1 = B:               */
+       unsigned reserved1 : 2;     /* RAZ                          */
+       unsigned ppt_en : 1;        /* See note above               */
+       unsigned uart1_en : 1;      /* See note above               */
+       unsigned uart2_en : 1;      /* See note above               */
+       unsigned fdc_en : 1;        /* See note above               */
+    }  by_field;
+} SMC37c669_CR07;
+
+/*
+** CR08 - default value 0x00
+*/
+typedef union _SMC37c669_CR08 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 4;          /* 0                            */
+       unsigned addrx7_4 : 4;      /* ADR<7:3> for ADRx decode     */
+    }  by_field;
+} SMC37c669_CR08;
+
+/*
+** CR09 - default value 0x00
+**
+**  ADRx_CONFIG:
+**     00 - ADRx disabled
+**     01 - 1 byte decode A<3:0> = 0000b
+**     10 - 8 byte block decode A<3:0> = 0XXXb
+**     11 - 16 byte block decode A<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c669_CR09 {
+    unsigned char as_uchar;
+    struct {
+       unsigned adra8 : 3;         /* ADR<10:8> for ADRx decode    */
+       unsigned reserved1 : 3;
+       unsigned adrx_config : 2;   /* See note above               */
+    }  by_field;
+} SMC37c669_CR09;
+
+/*
+** CR0A - default value 0x00
+*/
+typedef union _SMC37c669_CR0A {
+    unsigned char as_uchar;
+    struct {
+       unsigned ecp_fifo_threshold : 4;
+       unsigned reserved1 : 4;
+    }  by_field;
+} SMC37c669_CR0A;
+
+/*
+** CR0B - default value 0x00
+*/
+typedef union _SMC37c669_CR0B {
+    unsigned char as_uchar;
+    struct {
+       unsigned fdd0_drtx : 2;     /* FDD0 Data Rate Table         */
+       unsigned fdd1_drtx : 2;     /* FDD1 Data Rate Table         */
+       unsigned fdd2_drtx : 2;     /* FDD2 Data Rate Table         */
+       unsigned fdd3_drtx : 2;     /* FDD3 Data Rate Table         */
+    }  by_field;
+} SMC37c669_CR0B;
+
+/*
+** CR0C - default value 0x00
+**
+**  UART2_MODE:
+**     000 - Standard (default)
+**     001 - IrDA (HPSIR)
+**     010 - Amplitude Shift Keyed IR @500 KHz
+**     011 - Reserved
+**     1xx - Reserved
+**
+*/
+typedef union _SMC37c669_CR0C {
+    unsigned char as_uchar;
+    struct {
+       unsigned uart2_rcv_polarity : 1;    /* 1 = invert RX            */
+       unsigned uart2_xmit_polarity : 1;   /* 1 = invert TX            */
+       unsigned uart2_duplex : 1;          /* 1 = full, 0 = half       */
+       unsigned uart2_mode : 3;            /* See note above           */
+       unsigned uart1_speed : 1;           /* 1 = high speed enabled   */
+       unsigned uart2_speed : 1;           /* 1 = high speed enabled   */
+    }  by_field;
+} SMC37c669_CR0C;
+
+/*
+** CR0D - default value 0x03
+**
+**  Device ID Register - read only
+*/
+typedef union _SMC37c669_CR0D {
+    unsigned char as_uchar;
+    struct {
+       unsigned device_id : 8;     /* Returns 0x3 in this field    */
+    }  by_field;
+} SMC37c669_CR0D;
+
+/*
+** CR0E - default value 0x02
+**
+**  Device Revision Register - read only
+*/
+typedef union _SMC37c669_CR0E {
+    unsigned char as_uchar;
+    struct {
+       unsigned device_rev : 8;    /* Returns 0x2 in this field    */
+    }  by_field;
+} SMC37c669_CR0E;
+
+/*
+** CR0F - default value 0x00
+*/
+typedef union _SMC37c669_CR0F {
+    unsigned char as_uchar;
+    struct {
+       unsigned test0 : 1;         /* Reserved - set to 0          */
+       unsigned test1 : 1;         /* Reserved - set to 0          */
+       unsigned test2 : 1;         /* Reserved - set to 0          */
+       unsigned test3 : 1;         /* Reserved - set t0 0          */
+       unsigned test4 : 1;         /* Reserved - set to 0          */
+       unsigned test5 : 1;         /* Reserved - set t0 0          */
+       unsigned test6 : 1;         /* Reserved - set t0 0          */
+       unsigned test7 : 1;         /* Reserved - set to 0          */
+    }  by_field;
+} SMC37c669_CR0F;
+
+/*
+** CR10 - default value 0x00
+*/
+typedef union _SMC37c669_CR10 {
+    unsigned char as_uchar;
+    struct {
+       unsigned reserved1 : 3;      /* RAZ                         */
+       unsigned pll_gain : 1;       /* 1 = 3V, 2 = 5V operation    */
+       unsigned pll_stop : 1;       /* 1 = stop PLLs               */
+       unsigned ace_stop : 1;       /* 1 = stop UART clocks        */
+       unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz  */
+       unsigned ir_test : 1;        /* Enable IR test mode         */
+    }  by_field;
+} SMC37c669_CR10;
+
+/*
+** CR11 - default value 0x00
+*/
+typedef union _SMC37c669_CR11 {
+    unsigned char as_uchar;
+    struct {
+       unsigned ir_loopback : 1;   /* Internal IR loop back                */
+       unsigned test_10ms : 1;     /* Test 10ms autopowerdown FDC timeout  */
+       unsigned reserved1 : 6;     /* RAZ                                  */
+    }  by_field;
+} SMC37c669_CR11;
+
+/*
+** CR12 - CR1D are reserved registers
+*/
+
+/*
+** CR1E - default value 0x80
+**
+**  GAMECS:
+**     00 - GAMECS disabled
+**     01 - 1 byte decode ADR<3:0> = 0001b
+**     10 - 8 byte block decode ADR<3:0> = 0XXXb
+**     11 - 16 byte block decode ADR<3:0> = XXXXb
+**
+*/
+typedef union _SMC37c66_CR1E {
+    unsigned char as_uchar;
+    struct {
+       unsigned gamecs_config: 2;   /* See note above              */
+       unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4>            */
+    }  by_field;
+} SMC37c669_CR1E;
+
+/*
+** CR1F - default value 0x00
+**
+**  DT0 DT1 DRVDEN0 DRVDEN1 Drive Type
+**  --- --- ------- ------- ----------
+**   0   0  DENSEL  DRATE0  4/2/1 MB 3.5"
+**                          2/1 MB 5.25"
+**                          2/1.6/1 MB 3.5" (3-mode)
+**   0   1  DRATE1  DRATE0
+**   1   0  nDENSEL DRATE0  PS/2
+**   1   1  DRATE0  DRATE1
+**
+**  Note: DENSEL, DRATE1, and DRATE0 map onto two output
+**       pins - DRVDEN0 and DRVDEN1.
+**
+*/
+typedef union _SMC37c669_CR1F {
+    unsigned char as_uchar;
+    struct {
+       unsigned fdd0_drive_type : 2;   /* FDD0 drive type          */
+       unsigned fdd1_drive_type : 2;   /* FDD1 drive type          */
+       unsigned fdd2_drive_type : 2;   /* FDD2 drive type          */
+       unsigned fdd3_drive_type : 2;   /* FDD3 drive type          */
+    }  by_field;
+} SMC37c669_CR1F;
+
+/*
+** CR20 - default value 0x3C
+**
+**  FDC Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR20 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 2;          /* 0                            */
+       unsigned addr9_4 : 6;       /* FDC Addr<9:4>                */
+    }  by_field;
+} SMC37c669_CR20;
+
+/*
+** CR21 - default value 0x3C
+**
+**  IDE Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0, A<3:0> = 0XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR21 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 2;          /* 0                            */
+       unsigned addr9_4 : 6;       /* IDE Addr<9:4>                */
+    }  by_field;
+} SMC37c669_CR21;
+
+/*
+** CR22 - default value 0x3D
+**
+**  IDE Alternate Status Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0, A<3:0> = 0110b to access.
+**
+*/
+typedef union _SMC37c669_CR22 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 2;          /* 0                            */
+       unsigned addr9_4 : 6;       /* IDE Alt Status Addr<9:4>     */
+    }  by_field;
+} SMC37c669_CR22;
+
+/*
+** CR23 - default value 0x00
+**
+**  Parallel Port Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0 to access.
+**     - If EPP is enabled, A<2:0> = XXXb to access.
+**       If EPP is NOT enabled, A<1:0> = XXb to access
+**
+*/
+typedef union _SMC37c669_CR23 {
+    unsigned char as_uchar;
+    struct {
+       unsigned addr9_2 : 8;       /* Parallel Port Addr<9:2>      */
+    }  by_field;
+} SMC37c669_CR23;
+
+/*
+** CR24 - default value 0x00
+**
+**  UART1 Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR24 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 1;          /* 0                            */
+       unsigned addr9_3 : 7;       /* UART1 Addr<9:3>              */
+    }  by_field;
+} SMC37c669_CR24;
+
+/*
+** CR25 - default value 0x00
+**
+**  UART2 Base Address Register
+**     - To disable this decode set Addr<9:8> = 0
+**     - A<10> = 0, A<2:0> = XXXb to access.
+**
+*/
+typedef union _SMC37c669_CR25 {
+    unsigned char as_uchar;
+    struct {
+       unsigned zero : 1;          /* 0                            */
+       unsigned addr9_3 : 7;       /* UART2 Addr<9:3>              */
+    }  by_field;
+} SMC37c669_CR25;
+
+/*
+** CR26 - default value 0x00
+**
+**  Parallel Port / FDC DMA Select Register
+**
+**  D3 - D0      DMA
+**  D7 - D4    Selected
+**  -------    --------
+**   0000       None
+**   0001       DMA_A
+**   0010       DMA_B
+**   0011       DMA_C
+**
+*/
+typedef union _SMC37c669_CR26 {
+    unsigned char as_uchar;
+    struct {
+       unsigned ppt_drq : 4;       /* See note above               */
+       unsigned fdc_drq : 4;       /* See note above               */
+    }  by_field;
+} SMC37c669_CR26;
+
+/*
+** CR27 - default value 0x00
+**
+**  Parallel Port / FDC IRQ Select Register
+**
+**  D3 - D0      IRQ
+**  D7 - D4    Selected
+**  -------    --------
+**   0000       None
+**   0001       IRQ_A
+**   0010       IRQ_B
+**   0011       IRQ_C
+**   0100       IRQ_D
+**   0101       IRQ_E
+**   0110       IRQ_F
+**   0111       Reserved
+**   1000       IRQ_H
+**
+**  Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR27 {
+    unsigned char as_uchar;
+    struct {
+       unsigned ppt_irq : 4;       /* See note above               */
+       unsigned fdc_irq : 4;       /* See note above               */
+    }  by_field;
+} SMC37c669_CR27;
+
+/*
+** CR28 - default value 0x00
+**
+**  UART IRQ Select Register
+**
+**  D3 - D0      IRQ
+**  D7 - D4    Selected
+**  -------    --------
+**   0000       None
+**   0001       IRQ_A
+**   0010       IRQ_B
+**   0011       IRQ_C
+**   0100       IRQ_D
+**   0101       IRQ_E
+**   0110       IRQ_F
+**   0111       Reserved
+**   1000       IRQ_H
+**   1111       share with UART1 (only for UART2)
+**
+**  Any unselected IRQ REQ is in tristate
+**
+**  To share an IRQ between UART1 and UART2, set
+**  UART1 to use the desired IRQ and set UART2 to
+**  0xF to enable sharing mechanism.
+**
+*/
+typedef union _SMC37c669_CR28 {
+    unsigned char as_uchar;
+    struct {
+       unsigned uart2_irq : 4;     /* See note above               */
+       unsigned uart1_irq : 4;     /* See note above               */
+    }  by_field;
+} SMC37c669_CR28;
+
+/*
+** CR29 - default value 0x00
+**
+**  IRQIN IRQ Select Register
+**
+**  D3 - D0      IRQ
+**  D7 - D4    Selected
+**  -------    --------
+**   0000       None
+**   0001       IRQ_A
+**   0010       IRQ_B
+**   0011       IRQ_C
+**   0100       IRQ_D
+**   0101       IRQ_E
+**   0110       IRQ_F
+**   0111       Reserved
+**   1000       IRQ_H
+**
+**  Any unselected IRQ REQ is in tristate
+**
+*/
+typedef union _SMC37c669_CR29 {
+    unsigned char as_uchar;
+    struct {
+       unsigned irqin_irq : 4;     /* See note above               */
+       unsigned reserved1 : 4;     /* RAZ                          */
+    }  by_field;
+} SMC37c669_CR29;
+
+/*
+** Aliases of Configuration Register formats (should match
+** the set of index aliases).
+**
+** Note that CR24 and CR25 have the same format and are the
+** base address registers for UART1 and UART2.  Because of
+** this we only define 1 alias here - for CR24 - as the serial
+** base address register.
+**
+** Note that CR21 and CR22 have the same format and are the
+** base address and alternate status address registers for
+** the IDE controller.  Because of this we only define 1 alias
+** here - for CR21 - as the IDE address register.
+**
+*/
+typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
+typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
+typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
+typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
+typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
+typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
+typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
+
+/*
+** ISA/Device IRQ Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY {
+    int device_irq;
+    int isa_irq;
+} SMC37c669_IRQ_TRANSLATION_ENTRY;
+
+/*
+** ISA/Device DMA Translation Table Entry Definition
+*/
+typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
+    int device_drq;
+    int isa_drq;
+} SMC37c669_DRQ_TRANSLATION_ENTRY;
+
+/*
+** External Interface Function Prototype Declarations
+*/
+
+SMC37c669_CONFIG_REGS *SMC37c669_detect( 
+    void 
+);
+
+unsigned int SMC37c669_enable_device( 
+    unsigned int func 
+);
+
+unsigned int SMC37c669_disable_device( 
+    unsigned int func 
+);
+
+unsigned int SMC37c669_configure_device( 
+    unsigned int func, 
+    int port, 
+    int irq, 
+    int drq 
+);
+
+void SMC37c669_display_device_info( 
+    void 
+);
+
+#endif /* __SMC37c669_H */
+
+/* file:       smcc669.c
+ *
+ * Copyright (C) 1997 by
+ * Digital Equipment Corporation, Maynard, Massachusetts.
+ * All rights reserved.
+ *
+ * This software is furnished under a license and may be used and copied
+ * only  in  accordance  of  the  terms  of  such  license  and with the
+ * inclusion of the above copyright notice. This software or  any  other
+ * copies thereof may not be provided or otherwise made available to any
+ * other person.  No title to and  ownership of the  software is  hereby
+ * transferred.
+ *
+ * The information in this software is  subject to change without notice
+ * and  should  not  be  construed  as a commitment by digital equipment
+ * corporation.
+ *
+ * Digital assumes no responsibility for the use  or  reliability of its
+ * software on equipment which is not supplied by digital.
+ */
+
+/*
+ *++
+ *  FACILITY:
+ *
+ *      Alpha SRM Console Firmware
+ *
+ *  MODULE DESCRIPTION:
+ *
+ *     SMC37c669 Super I/O controller configuration routines.
+ *
+ *  AUTHORS:
+ *
+ *     Eric Rasmussen
+ *
+ *  CREATION DATE:
+ *  
+ *     28-Jan-1997
+ *
+ *  MODIFICATION HISTORY:
+ *     
+ *     er      01-May-1997     Fixed pointer conversion errors in 
+ *                             SMC37c669_get_device_config().
+ *      er     28-Jan-1997     Initial version.
+ *
+ *--
+ */
+#if 0
+/* $INCLUDE_OPTIONS$ */
+#include    "cp$inc:platform_io.h"
+/* $INCLUDE_OPTIONS_END$ */
+#include    "cp$src:common.h"
+#include    "cp$inc:prototypes.h"
+#include    "cp$src:kernel_def.h"
+#include    "cp$src:msg_def.h"
+#include    "cp$src:smcc669_def.h"
+/* Platform-specific includes */
+#include    "cp$src:platform.h"
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define wb( _x_, _y_ ) outb( _y_, (unsigned int)((unsigned long)_x_) )
+#define rb( _x_ )      inb( (unsigned int)((unsigned long)_x_) )
+
+/*
+** Local storage for device configuration information.
+**
+** Since the SMC37c669 does not provide an explicit
+** mechanism for enabling/disabling individual device 
+** functions, other than unmapping the device, local 
+** storage for device configuration information is 
+** allocated here for use in implementing our own 
+** function enable/disable scheme.
+*/
+static struct DEVICE_CONFIG {
+    unsigned int port1;
+    unsigned int port2;
+    unsigned int irq;
+    unsigned int drq;
+} local_config [NUM_FUNCS];
+
+/*
+** List of all possible addresses for the Super I/O chip
+*/
+static unsigned long SMC37c669_Addresses[] =
+    {
+       0x3F0UL,            /* Primary address      */
+       0x370UL,            /* Secondary address    */
+       0UL                 /* End of list          */
+    };
+
+/*
+** Global Pointer to the Super I/O device
+*/
+static SMC37c669_CONFIG_REGS *SMC37c669 = NULL;
+
+/*
+** IRQ Translation Table
+**
+** The IRQ translation table is a list of SMC37c669 device 
+** and standard ISA IRQs.
+**
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table; 
+
+/*
+** The following definition is for the default IRQ 
+** translation table.
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[ ] = 
+    { 
+       { SMC37c669_DEVICE_IRQ_A, -1 }, 
+       { SMC37c669_DEVICE_IRQ_B, -1 }, 
+       { SMC37c669_DEVICE_IRQ_C, 7 }, 
+       { SMC37c669_DEVICE_IRQ_D, 6 }, 
+       { SMC37c669_DEVICE_IRQ_E, 4 }, 
+       { SMC37c669_DEVICE_IRQ_F, 3 }, 
+       { SMC37c669_DEVICE_IRQ_H, -1 }, 
+       { -1, -1 } /* End of table */
+    };
+
+/*
+** DRQ Translation Table
+**
+** The DRQ translation table is a list of SMC37c669 device and
+** ISA DMA channels.
+**
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table; 
+
+/*
+** The following definition is the default DRQ
+** translation table.
+*/
+static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[ ] = 
+    { 
+       { SMC37c669_DEVICE_DRQ_A, 2 }, 
+       { SMC37c669_DEVICE_DRQ_B, 3 }, 
+       { SMC37c669_DEVICE_DRQ_C, -1 }, 
+       { -1, -1 } /* End of table */
+    };
+
+/*
+** Local Function Prototype Declarations
+*/
+
+static unsigned int SMC37c669_is_device_enabled( 
+    unsigned int func 
+);
+
+#if 0
+static unsigned int SMC37c669_get_device_config( 
+    unsigned int func, 
+    int *port, 
+    int *irq, 
+    int *drq 
+);
+#endif
+
+static void SMC37c669_config_mode( 
+    unsigned int enable 
+);
+
+static unsigned char SMC37c669_read_config( 
+    unsigned char index 
+);
+
+static void SMC37c669_write_config( 
+    unsigned char index, 
+    unsigned char data 
+);
+
+static void SMC37c669_init_local_config( void );
+
+static struct DEVICE_CONFIG *SMC37c669_get_config(
+    unsigned int func
+);
+
+static int SMC37c669_xlate_irq(
+    unsigned int irq 
+);
+
+static int SMC37c669_xlate_drq(
+    unsigned int drq 
+);
+
+#if 0
+/*
+** External Data Declarations
+*/
+
+extern struct LOCK spl_atomic;
+
+/*
+** External Function Prototype Declarations
+*/
+
+/* From kernel_alpha.mar */
+extern spinlock( 
+    struct LOCK *spl 
+);
+
+extern spinunlock( 
+    struct LOCK *spl 
+);
+
+/* From filesys.c */
+int allocinode(
+    char *name, 
+    int can_create, 
+    struct INODE **ipp
+);
+
+extern int null_procedure( void );
+
+int smcc669_init( void );
+int smcc669_open( struct FILE *fp, char *info, char *next, char *mode );
+int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf );
+int smcc669_close( struct FILE *fp );
+
+struct DDB smc_ddb = {
+       "smc",                  /* how this routine wants to be called  */
+       smcc669_read,           /* read routine                         */
+       smcc669_write,          /* write routine                        */
+       smcc669_open,           /* open routine                         */
+       smcc669_close,          /* close routine                        */
+       null_procedure,         /* name expansion routine               */
+       null_procedure,         /* delete routine                       */
+       null_procedure,         /* create routine                       */
+       null_procedure,         /* setmode                              */
+       null_procedure,         /* validation routine                   */
+       0,                      /* class specific use                   */
+       1,                      /* allows information                   */
+       0,                      /* must be stacked                      */
+       0,                      /* is a flash update driver             */
+       0,                      /* is a block device                    */
+       0,                      /* not seekable                         */
+       0,                      /* is an ethernet device                */
+       0,                      /* is a filesystem driver               */
+};
+#endif
+
+#define spinlock(x)
+#define spinunlock(x)
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function detects the presence of an SMC37c669 Super I/O
+**     controller.
+**
+**  FORMAL PARAMETERS:
+**
+**     None
+**
+**  RETURN VALUE:
+**
+**      Returns a pointer to the device if found, otherwise,
+**     the NULL pointer is returned.
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+SMC37c669_CONFIG_REGS *SMC37c669_detect( void )
+{
+    int i;
+    SMC37c669_DEVICE_ID_REGISTER id;
+
+    for ( i = 0;  SMC37c669_Addresses[i] != 0;  i++ ) {
+/*
+** Initialize the device pointer even though we don't yet know if
+** the controller is at this address.  The support functions access
+** the controller through this device pointer so we need to set it
+** even when we are looking ...
+*/
+       SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
+/*
+** Enter configuration mode
+*/
+       SMC37c669_config_mode( TRUE );
+/*
+** Read the device id
+*/
+       id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
+/*
+** Exit configuration mode
+*/
+       SMC37c669_config_mode( FALSE );
+/*
+** Does the device id match?  If so, assume we have found an
+** SMC37c669 controller at this address.
+*/
+       if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
+/*
+** Initialize the IRQ and DRQ translation tables.
+*/
+           SMC37c669_irq_table = SMC37c669_default_irq_table;
+           SMC37c669_drq_table = SMC37c669_default_drq_table;
+/*
+** erfix
+**
+** If the platform can't use the IRQ and DRQ defaults set up in this 
+** file, it should call a platform-specific external routine at this 
+** point to reset the IRQ and DRQ translation table pointers to point 
+** at the appropriate tables for the platform.  If the defaults are 
+** acceptable, then the external routine should do nothing.
+*/
+
+/*
+** Put the chip back into configuration mode
+*/
+           SMC37c669_config_mode( TRUE );
+/*
+** Initialize local storage for configuration information
+*/
+           SMC37c669_init_local_config( );
+/*
+** Exit configuration mode
+*/
+           SMC37c669_config_mode( FALSE );
+/*
+** SMC37c669 controller found, break out of search loop
+*/
+           break;
+       }
+       else {
+/*
+** Otherwise, we did not find an SMC37c669 controller at this
+** address so set the device pointer to NULL.
+*/
+           SMC37c669 = NULL;
+       }
+    }
+    return SMC37c669;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function enables an SMC37c669 device function.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function to enable
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE is the device function was enabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      Enabling a device function in the SMC37c669 controller involves
+**     setting all of its mappings (port, irq, drq ...).  A local 
+**     "shadow" copy of the device configuration is kept so we can
+**     just set each mapping to what the local copy says.
+**
+**     This function ALWAYS updates the local shadow configuration of
+**     the device function being enabled, even if the device is always
+**     enabled.  To avoid replication of code, functions such as
+**     configure_device set up the local copy and then call this 
+**     function to the update the real device.
+**
+**--
+*/
+unsigned int SMC37c669_enable_device ( unsigned int func )
+{
+    unsigned int ret_val = FALSE;
+/*
+** Put the device into configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+    switch ( func ) {
+       case SERIAL_0:
+           {
+               SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 1 IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+               irq.by_field.uart1_irq =
+                   SMC37c669_RAW_DEVICE_IRQ(
+                       SMC37c669_xlate_irq( local_config[ func ].irq )
+                   );
+
+               SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 1 port base address mapping
+*/
+               base_addr.as_uchar = 0;
+               base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+               SMC37c669_write_config( 
+                   SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case SERIAL_1:
+           {
+               SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Enable the serial 2 IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+               irq.by_field.uart2_irq =
+                   SMC37c669_RAW_DEVICE_IRQ(
+                       SMC37c669_xlate_irq( local_config[ func ].irq )
+                   );
+
+               SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Enable the serial 2 port base address mapping
+*/
+               base_addr.as_uchar = 0;
+               base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
+
+               SMC37c669_write_config( 
+                   SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case PARALLEL_0:
+           {
+               SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+               SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the parallel port DMA channel mapping
+*/
+               drq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+               drq.by_field.ppt_drq = 
+                   SMC37c669_RAW_DEVICE_DRQ(
+                       SMC37c669_xlate_drq( local_config[ func ].drq )
+                   );
+
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+                   drq.as_uchar
+               );
+/*
+** Enable the parallel port IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+               irq.by_field.ppt_irq =
+                   SMC37c669_RAW_DEVICE_IRQ(
+                       SMC37c669_xlate_irq( local_config[ func ].irq )
+                   );
+
+               SMC37c669_write_config( 
+                   SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+                   irq.as_uchar
+               );
+/*
+** Enable the parallel port base address mapping
+*/
+               base_addr.as_uchar = 0;
+               base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
+
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case FLOPPY_0:
+           {
+               SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+               SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Enable the floppy controller DMA channel mapping
+*/
+               drq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+                
+               drq.by_field.fdc_drq =
+                   SMC37c669_RAW_DEVICE_DRQ(
+                       SMC37c669_xlate_drq( local_config[ func ].drq )
+                   );
+                
+               SMC37c669_write_config( 
+                   SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+                   drq.as_uchar
+               );
+/*
+** Enable the floppy controller IRQ mapping
+*/
+               irq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+                
+               irq.by_field.fdc_irq =
+                   SMC37c669_RAW_DEVICE_IRQ(
+                       SMC37c669_xlate_irq( local_config[ func ].irq )
+                   );
+                
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+                   irq.as_uchar
+               );
+/*
+** Enable the floppy controller base address mapping
+*/
+               base_addr.as_uchar = 0;
+               base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+                
+               SMC37c669_write_config(
+                   SMC37c669_FDC_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case IDE_0:
+           {
+               SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Enable the IDE alternate status base address mapping
+*/
+               ide_addr.as_uchar = 0;
+               ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
+                
+               SMC37c669_write_config(
+                   SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+                   ide_addr.as_uchar
+               );
+/*
+** Enable the IDE controller base address mapping
+*/
+               ide_addr.as_uchar = 0;
+               ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
+                
+               SMC37c669_write_config(
+                   SMC37c669_IDE_BASE_ADDRESS_INDEX,
+                   ide_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+    }
+/*
+** Exit configuration mode and return
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function disables a device function within the
+**     SMC37c669 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which function to disable
+**
+**  RETURN VALUE:
+**
+**      Return TRUE if the device function was disabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      Disabling a function in the SMC37c669 device involves
+**     disabling all the function's mappings (port, irq, drq ...).
+**     A shadow copy of the device configuration is maintained
+**     in local storage so we won't worry aboving saving the
+**     current configuration information.
+**
+**--
+*/
+unsigned int SMC37c669_disable_device ( unsigned int func )
+{
+    unsigned int ret_val = FALSE;
+
+/*
+** Put the device into configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+    switch ( func ) {
+       case SERIAL_0:
+           {
+               SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 1 IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+               irq.by_field.uart1_irq = 0;
+
+               SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 1 port base address mapping
+*/
+               base_addr.as_uchar = 0;
+               SMC37c669_write_config( 
+                   SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case SERIAL_1:
+           {
+               SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_SERIAL_IRQ_REGISTER irq;
+/*
+** Disable the serial 2 IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+
+               irq.by_field.uart2_irq = 0;
+
+               SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
+/*
+** Disable the serial 2 port base address mapping
+*/
+               base_addr.as_uchar = 0;
+
+               SMC37c669_write_config( 
+                   SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case PARALLEL_0:
+           {
+               SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+               SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the parallel port DMA channel mapping
+*/
+               drq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+
+               drq.by_field.ppt_drq = 0;
+
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+                   drq.as_uchar
+               );
+/*
+** Disable the parallel port IRQ mapping
+*/
+               irq.as_uchar = 
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+
+               irq.by_field.ppt_irq = 0;
+
+               SMC37c669_write_config( 
+                   SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+                   irq.as_uchar
+               );
+/*
+** Disable the parallel port base address mapping
+*/
+               base_addr.as_uchar = 0;
+
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case FLOPPY_0:
+           {
+               SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
+               SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
+               SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
+/*
+** Disable the floppy controller DMA channel mapping
+*/
+               drq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+                
+               drq.by_field.fdc_drq = 0;
+                
+               SMC37c669_write_config( 
+                   SMC37c669_PARALLEL_FDC_DRQ_INDEX,
+                   drq.as_uchar
+               );
+/*
+** Disable the floppy controller IRQ mapping
+*/
+               irq.as_uchar =
+                   SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+                
+               irq.by_field.fdc_irq = 0;
+                
+               SMC37c669_write_config(
+                   SMC37c669_PARALLEL_FDC_IRQ_INDEX,
+                   irq.as_uchar
+               );
+/*
+** Disable the floppy controller base address mapping
+*/
+               base_addr.as_uchar = 0;
+                
+               SMC37c669_write_config(
+                   SMC37c669_FDC_BASE_ADDRESS_INDEX,
+                   base_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+       case IDE_0:
+           {
+               SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
+/*
+** Disable the IDE alternate status base address mapping
+*/
+               ide_addr.as_uchar = 0;
+                
+               SMC37c669_write_config(
+                   SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
+                   ide_addr.as_uchar
+               );
+/*
+** Disable the IDE controller base address mapping
+*/
+               ide_addr.as_uchar = 0;
+                
+               SMC37c669_write_config(
+                   SMC37c669_IDE_BASE_ADDRESS_INDEX,
+                   ide_addr.as_uchar
+               );
+               ret_val = TRUE;
+               break;
+           }
+    }
+/*
+** Exit configuration mode and return
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function configures a device function within the 
+**     SMC37c669 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**       
+**      port:
+**          I/O port for the function to use
+**      
+**      irq:
+**          IRQ for the device function to use
+**      
+**      drq:
+**          DMA channel for the device function to use
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device function was configured, 
+**     otherwise, FALSE.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**     If this function returns TRUE, the local shadow copy of
+**     the configuration is also updated.  If the device function
+**     is currently disabled, only the local shadow copy is 
+**     updated and the actual device function will be updated
+**     if/when is is enabled.
+**
+**--
+*/
+unsigned int SMC37c669_configure_device (
+    unsigned int func,
+    int port,
+    int irq,
+    int drq )
+{
+    struct DEVICE_CONFIG *cp;
+
+/*
+** Check for a valid configuration
+*/
+    if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
+/*
+** Configuration is valid, update the local shadow copy
+*/
+       if ( ( drq & ~0xFF ) == 0 ) {
+           cp->drq = drq;
+       }
+       if ( ( irq & ~0xFF ) == 0 ) {
+           cp->irq = irq;
+       }
+       if ( ( port & ~0xFFFF ) == 0 ) {
+           cp->port1 = port;
+       }
+/*
+** If the device function is enabled, update the actual
+** device configuration.
+*/
+       if ( SMC37c669_is_device_enabled( func ) ) {
+           SMC37c669_enable_device( func );
+       }
+       return TRUE;
+    }
+    return FALSE;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function determines whether a device function
+**     within the SMC37c669 controller is enabled.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device function is enabled, otherwise, FALSE
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**  DESIGN:
+**
+**      To check whether a device is enabled we will only look at 
+**     the port base address mapping.  According to the SMC37c669
+**     specification, all of the port base address mappings are
+**     disabled if the addr<9:8> (bits <7:6> of the register) are
+**     zero.
+**
+**--
+*/
+static unsigned int SMC37c669_is_device_enabled ( unsigned int func )
+{
+    unsigned char base_addr = 0;
+    unsigned int dev_ok = FALSE;
+    unsigned int ret_val = FALSE;
+/*
+** Enter configuration mode
+*/
+    SMC37c669_config_mode( TRUE );
+     
+    switch ( func ) {
+       case SERIAL_0:
+           base_addr =
+               SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+           dev_ok = TRUE;
+           break;
+       case SERIAL_1:
+           base_addr =
+               SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+           dev_ok = TRUE;
+           break;
+       case PARALLEL_0:
+           base_addr =
+               SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+           dev_ok = TRUE;
+           break;
+       case FLOPPY_0:
+           base_addr =
+               SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+           dev_ok = TRUE;
+           break;
+       case IDE_0:
+           base_addr =
+               SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+           dev_ok = TRUE;
+           break;
+    }
+/*
+** If we have a valid device, check base_addr<7:6> to see if the
+** device is enabled (mapped).
+*/
+    if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
+/*
+** The mapping is not disabled, so assume that the function is 
+** enabled.
+*/
+       ret_val = TRUE;
+    }
+/*
+** Exit configuration mode 
+*/
+    SMC37c669_config_mode( FALSE );
+
+    return ret_val;
+}
+
+\f
+#if 0
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function retrieves the configuration information of a 
+**     device function within the SMC37c699 Super I/O controller.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**       
+**      port:
+**          I/O port returned
+**      
+**      irq:
+**          IRQ returned
+**      
+**      drq:
+**          DMA channel returned
+**
+**  RETURN VALUE:
+**
+**      Returns TRUE if the device configuration was successfully
+**     retrieved, otherwise, FALSE.
+**
+**  SIDE EFFECTS:
+**
+**      The data pointed to by the port, irq, and drq parameters
+**     my be modified even if the configuration is not successfully
+**     retrieved.
+**
+**  DESIGN:
+**
+**      The device configuration is fetched from the local shadow
+**     copy.  Any unused parameters will be set to -1.  Any
+**     parameter which is not desired can specify the NULL
+**     pointer.
+**
+**--
+*/
+static unsigned int SMC37c669_get_device_config (
+    unsigned int func,
+    int *port,
+    int *irq,
+    int *drq )
+{
+    struct DEVICE_CONFIG *cp;
+    unsigned int ret_val = FALSE;
+/*
+** Check for a valid device configuration
+*/
+    if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
+       if ( drq != NULL ) {
+           *drq = cp->drq;
+           ret_val = TRUE;
+       }
+       if ( irq != NULL ) {
+           *irq = cp->irq;
+           ret_val = TRUE;
+       }
+       if ( port != NULL ) {
+           *port = cp->port1;
+           ret_val = TRUE;
+       }
+    }
+    return ret_val;
+}
+#endif
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function displays the current state of the SMC37c699
+**     Super I/O controller's device functions.
+**
+**  FORMAL PARAMETERS:
+**
+**      None
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+void SMC37c669_display_device_info ( void )
+{
+    if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
+       printk( "  Serial 0:    Enabled [ Port 0x%x, IRQ %d ]\n",
+                local_config[ SERIAL_0 ].port1,
+                local_config[ SERIAL_0 ].irq
+       );
+    }
+    else {
+       printk( "  Serial 0:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
+       printk( "  Serial 1:    Enabled [ Port 0x%x, IRQ %d ]\n",
+                local_config[ SERIAL_1 ].port1,
+                local_config[ SERIAL_1 ].irq
+       );
+    }
+    else {
+       printk( "  Serial 1:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
+       printk( "  Parallel:    Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+                local_config[ PARALLEL_0 ].port1,
+                local_config[ PARALLEL_0 ].irq,
+                local_config[ PARALLEL_0 ].drq
+       );
+    }
+    else {
+       printk( "  Parallel:    Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
+       printk( "  Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
+                local_config[ FLOPPY_0 ].port1,
+                local_config[ FLOPPY_0 ].irq,
+                local_config[ FLOPPY_0 ].drq
+       );
+    }
+    else {
+       printk( "  Floppy Ctrl: Disabled\n" );
+    }
+
+    if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
+       printk( "  IDE 0:       Enabled [ Port 0x%x, IRQ %d ]\n",
+                local_config[ IDE_0 ].port1,
+                local_config[ IDE_0 ].irq
+       );
+    }
+    else {
+       printk( "  IDE 0:       Disabled\n" );
+    }
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function puts the SMC37c669 Super I/O controller into,
+**     and takes it out of, configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      enable:
+**          TRUE to enter configuration mode, FALSE to exit.
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      The SMC37c669 controller may be left in configuration mode.
+**
+**--
+*/
+static void SMC37c669_config_mode( 
+    unsigned int enable )
+{
+    if ( enable ) {
+/*
+** To enter configuration mode, two writes in succession to the index
+** port are required.  If a write to another address or port occurs
+** between these two writes, the chip does not enter configuration
+** mode.  Therefore, a spinlock is placed around the two writes to 
+** guarantee that they complete uninterrupted.
+*/
+       spinlock( &spl_atomic );
+       wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+       wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
+       spinunlock( &spl_atomic );
+    }
+    else {
+       wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
+    }
+}
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function reads an SMC37c669 Super I/O controller
+**     configuration register.  This function assumes that the
+**     device is already in configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      index:
+**          Index value of configuration register to read
+**
+**  RETURN VALUE:
+**
+**      Data read from configuration register
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+static unsigned char SMC37c669_read_config( 
+    unsigned char index )
+{
+    unsigned char data;
+
+    wb( &SMC37c669->index_port, index );
+    data = rb( &SMC37c669->data_port );
+    return data;
+}
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function writes an SMC37c669 Super I/O controller
+**     configuration register.  This function assumes that the
+**     device is already in configuration mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      index:
+**          Index of configuration register to write
+**       
+**      data:
+**          Data to be written
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      None
+**
+**--
+*/
+static void SMC37c669_write_config( 
+    unsigned char index, 
+    unsigned char data )
+{
+    wb( &SMC37c669->index_port, index );
+    wb( &SMC37c669->data_port, data );
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function initializes the local device
+**     configuration storage.  This function assumes
+**     that the device is already in configuration
+**     mode.
+**
+**  FORMAL PARAMETERS:
+**
+**      None
+**
+**  RETURN VALUE:
+**
+**      None
+**
+**  SIDE EFFECTS:
+**
+**      Local storage for device configuration information
+**     is initialized.
+**
+**--
+*/
+static void SMC37c669_init_local_config ( void )
+{
+    SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
+    SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
+    SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
+    SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
+    SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
+    SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
+    SMC37c669_IDE_ADDRESS_REGISTER ide_base;
+    SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
+
+/*
+** Get serial port 1 base address 
+*/
+    uart_base.as_uchar = 
+       SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for serial ports 1 & 2
+*/
+    uart_irqs.as_uchar = 
+       SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
+/*
+** Store local configuration information for serial port 1
+*/
+    local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
+    local_config[SERIAL_0].irq = 
+       SMC37c669_xlate_irq( 
+           SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq ) 
+       );
+/*
+** Get serial port 2 base address
+*/
+    uart_base.as_uchar = 
+       SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for serial port 2
+*/
+    local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
+    local_config[SERIAL_1].irq = 
+       SMC37c669_xlate_irq( 
+           SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq ) 
+       );
+/*
+** Get parallel port base address
+*/
+    ppt_base.as_uchar =
+       SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
+/*
+** Get IRQs for parallel port and floppy controller
+*/
+    ppt_fdc_irqs.as_uchar =
+       SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
+/*
+** Get DRQs for parallel port and floppy controller
+*/
+    ppt_fdc_drqs.as_uchar =
+       SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
+/*
+** Store local configuration information for parallel port
+*/
+    local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
+    local_config[PARALLEL_0].irq =
+       SMC37c669_xlate_irq(
+           SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
+       );
+    local_config[PARALLEL_0].drq =
+       SMC37c669_xlate_drq(
+           SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
+       );
+/*
+** Get floppy controller base address
+*/
+    fdc_base.as_uchar = 
+       SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
+/*
+** Store local configuration information for floppy controller
+*/
+    local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
+    local_config[FLOPPY_0].irq =
+       SMC37c669_xlate_irq(
+           SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
+       );
+    local_config[FLOPPY_0].drq =
+       SMC37c669_xlate_drq(
+           SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
+       );
+/*
+** Get IDE controller base address
+*/
+    ide_base.as_uchar =
+       SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
+/*
+** Get IDE alternate status base address
+*/
+    ide_alt.as_uchar =
+       SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
+/*
+** Store local configuration information for IDE controller
+*/
+    local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
+    local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
+    local_config[IDE_0].irq = 14;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function returns a pointer to the local shadow
+**     configuration of the requested device function.
+**
+**  FORMAL PARAMETERS:
+**
+**      func:
+**          Which device function
+**
+**  RETURN VALUE:
+**
+**      Returns a pointer to the DEVICE_CONFIG structure for the
+**     requested function, otherwise, NULL.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static struct DEVICE_CONFIG *SMC37c669_get_config( unsigned int func )
+{
+    struct DEVICE_CONFIG *cp = NULL;
+
+    switch ( func ) {
+       case SERIAL_0:
+           cp = &local_config[ SERIAL_0 ];
+           break;
+       case SERIAL_1:
+           cp = &local_config[ SERIAL_1 ];
+           break;
+       case PARALLEL_0:
+           cp = &local_config[ PARALLEL_0 ];
+           break;
+       case FLOPPY_0:
+           cp = &local_config[ FLOPPY_0 ];
+           break;
+       case IDE_0:
+           cp = &local_config[ IDE_0 ];
+           break;
+    }
+    return cp;
+}
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function translates IRQs back and forth between ISA
+**     IRQs and SMC37c669 device IRQs.
+**
+**  FORMAL PARAMETERS:
+**
+**      irq:
+**          The IRQ to translate
+**
+**  RETURN VALUE:
+**
+**      Returns the translated IRQ, otherwise, returns -1.
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static int SMC37c669_xlate_irq ( unsigned int irq )
+{
+    int i, translated_irq = -1;
+
+    if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
+/*
+** We are translating a device IRQ to an ISA IRQ
+*/
+       for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
+           if ( irq == SMC37c669_irq_table[i].device_irq ) {
+               translated_irq = SMC37c669_irq_table[i].isa_irq;
+               break;
+           }
+       }
+    }
+    else {
+/*
+** We are translating an ISA IRQ to a device IRQ
+*/
+       for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
+           if ( irq == SMC37c669_irq_table[i].isa_irq ) {
+               translated_irq = SMC37c669_irq_table[i].device_irq;
+               break;
+           }
+       }
+    }
+    return translated_irq;
+}
+
+\f
+/*
+**++
+**  FUNCTIONAL DESCRIPTION:
+**
+**      This function translates DMA channels back and forth between
+**     ISA DMA channels and SMC37c669 device DMA channels.
+**
+**  FORMAL PARAMETERS:
+**
+**      drq:
+**          The DMA channel to translate
+**
+**  RETURN VALUE:
+**
+**      Returns the translated DMA channel, otherwise, returns -1
+**
+**  SIDE EFFECTS:
+**
+**      {@description or none@}
+**
+**--
+*/
+static int SMC37c669_xlate_drq ( unsigned int drq )
+{
+    int i, translated_drq = -1;
+
+    if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
+/*
+** We are translating a device DMA channel to an ISA DMA channel
+*/
+       for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
+           if ( drq == SMC37c669_drq_table[i].device_drq ) {
+               translated_drq = SMC37c669_drq_table[i].isa_drq;
+               break;
+           }
+       }
+    }
+    else {
+/*
+** We are translating an ISA DMA channel to a device DMA channel
+*/
+       for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
+           if ( drq == SMC37c669_drq_table[i].isa_drq ) {
+               translated_drq = SMC37c669_drq_table[i].device_drq;
+               break;
+           }
+       }
+    }
+    return translated_drq;
+}
+\f
+#if 0
+int smcc669_init ( void )
+{
+    struct INODE *ip;
+
+    allocinode( smc_ddb.name, 1, &ip );
+    ip->dva = &smc_ddb;
+    ip->attr = ATTR$M_WRITE | ATTR$M_READ;
+    ip->len[0] = 0x30;
+    ip->misc = 0;
+    INODE_UNLOCK( ip );
+
+    return msg_success;
+}
+\f
+int smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
+{
+    struct INODE *ip;
+/*
+** Allow multiple readers but only one writer.  ip->misc keeps track
+** of the number of writers
+*/
+    ip = fp->ip;
+    INODE_LOCK( ip );
+    if ( fp->mode & ATTR$M_WRITE ) {
+       if ( ip->misc ) {
+           INODE_UNLOCK( ip );
+           return msg_failure;     /* too many writers */
+       }
+       ip->misc++;
+    }
+/*
+** Treat the information field as a byte offset
+*/
+    *fp->offset = xtoi( info );
+    INODE_UNLOCK( ip );
+
+    return msg_success;
+}
+\f
+int smcc669_close( struct FILE *fp )
+{
+    struct INODE *ip;
+
+    ip = fp->ip;
+    if ( fp->mode & ATTR$M_WRITE ) {
+       INODE_LOCK( ip );
+       ip->misc--;
+       INODE_UNLOCK( ip );
+    }
+    return msg_success;
+}
+\f
+int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+    int i;
+    int length;
+    int nbytes;
+    struct INODE *ip;
+
+/*
+** Always access a byte at a time
+*/
+    ip = fp->ip;
+    length = size * number;
+    nbytes = 0;
+
+    SMC37c669_config_mode( TRUE );
+    for ( i = 0; i < length; i++ ) {
+       if ( !inrange( *fp->offset, 0, ip->len[0] ) ) 
+           break;
+       *buf++ = SMC37c669_read_config( *fp->offset );
+       *fp->offset += 1;
+       nbytes++;
+    }
+    SMC37c669_config_mode( FALSE );
+    return nbytes;
+}
+\f
+int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
+{
+    int i;
+    int length;
+    int nbytes;
+    struct INODE *ip;
+/*
+** Always access a byte at a time
+*/
+    ip = fp->ip;
+    length = size * number;
+    nbytes = 0;
+
+    SMC37c669_config_mode( TRUE );
+    for ( i = 0; i < length; i++ ) {
+       if ( !inrange( *fp->offset, 0, ip->len[0] ) ) 
+           break;
+       SMC37c669_write_config( *fp->offset, *buf );
+       *fp->offset += 1;
+       buf++;
+       nbytes++;
+    }
+    SMC37c669_config_mode( FALSE );
+    return nbytes;
+}
+#endif
+
+void
+SMC37c669_dump_registers(void)
+{
+  int i;
+  for (i = 0; i <= 0x29; i++)
+    printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
+}
+/*+
+ * ============================================================================
+ * = SMC_init - SMC37c669 Super I/O controller initialization                 =
+ * ============================================================================
+ *
+ * OVERVIEW:
+ *
+ *      This routine configures and enables device functions on the
+ *      SMC37c669 Super I/O controller.
+ *
+ * FORM OF CALL:
+ *
+ *      SMC_init( );
+ *
+ * RETURNS:
+ *
+ *      Nothing
+ *
+ * ARGUMENTS:
+ *
+ *      None
+ *
+ * SIDE EFFECTS:
+ *
+ *      None
+ *
+-*/
+void SMC669_Init ( void )
+{
+    SMC37c669_CONFIG_REGS *SMC_base;
+
+    if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) {
+        printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n",
+               (unsigned long) SMC_base );
+#if SMC_DEBUG
+       SMC37c669_config_mode( TRUE );
+       SMC37c669_dump_registers( );
+       SMC37c669_config_mode( FALSE );
+        SMC37c669_display_device_info( );
+#endif
+        SMC37c669_disable_device( SERIAL_0 );
+        SMC37c669_configure_device(
+            SERIAL_0,
+            COM1_BASE,
+            COM1_IRQ,
+            -1
+        );
+        SMC37c669_enable_device( SERIAL_0 );
+
+        SMC37c669_disable_device( SERIAL_1 );
+        SMC37c669_configure_device(
+            SERIAL_1,
+            COM2_BASE,
+            COM2_IRQ,
+            -1
+        );
+        SMC37c669_enable_device( SERIAL_1 );
+
+        SMC37c669_disable_device( PARALLEL_0 );
+        SMC37c669_configure_device(
+            PARALLEL_0,
+            PARP_BASE,
+            PARP_IRQ,
+            PARP_DRQ
+        );
+        SMC37c669_enable_device( PARALLEL_0 );
+
+        SMC37c669_disable_device( FLOPPY_0 );
+        SMC37c669_configure_device(
+            FLOPPY_0,
+            FDC_BASE,
+            FDC_IRQ,
+            FDC_DRQ
+        );
+        SMC37c669_enable_device( FLOPPY_0 );
+          
+        SMC37c669_disable_device( IDE_0 );
+
+#if SMC_DEBUG
+       SMC37c669_config_mode( TRUE );
+       SMC37c669_dump_registers( );
+       SMC37c669_config_mode( FALSE );
+        SMC37c669_display_device_info( );
+#endif
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC37c669 Super I/O Controller found\n" );
+#endif
+    }
+}
+
+#endif /* SX164 */
diff --git a/arch/alpha/kernel/t2.c b/arch/alpha/kernel/t2.c
new file mode 100644 (file)
index 0000000..dbcc5b6
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Code common to all T2 chips.
+ *
+ * Written by Jay A Estabrook (jestabro@amt.tay1.dec.com).
+ * December 1996.
+ *
+ * based on CIA code by David A Rusling (david.rusling@reo.mts.dec.com)
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+extern asmlinkage unsigned long whami(void);
+
+#define CPUID whami()
+
+/*
+ * Machine check reasons.  Defined according to PALcode sources
+ * (osf.h and platform.h).
+ */
+#define MCHK_K_TPERR           0x0080
+#define MCHK_K_TCPERR          0x0082
+#define MCHK_K_HERR            0x0084
+#define MCHK_K_ECC_C           0x0086
+#define MCHK_K_ECC_NC          0x0088
+#define MCHK_K_OS_BUGCHECK     0x008A
+#define MCHK_K_PAL_BUGCHECK    0x0090
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_T2
+
+#ifdef DEBUG_CONF
+# define DBG(args)     printk args
+#else
+# define DBG(args)
+#endif
+
+#ifdef DEBUG_MCHECK
+# define DBGMC(args)   printk args
+#else
+# define DBGMC(args)
+#endif
+
+#define vulp   volatile unsigned long *
+#define vuip   volatile unsigned int  *
+
+static volatile unsigned int T2_mcheck_expected = 0;
+static volatile unsigned int T2_mcheck_taken = 0;
+static unsigned long T2_jd;
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT;
+unsigned int T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT;
+unsigned long t2_sm_base;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the T2_HAXR2 register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:11   Device select bit.
+ *     10:8    Function number
+ *      7:2    Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:24   reserved
+ *     23:16   bus number (8 bits = 128 possible buses)
+ *     15:11   Device number (5 bits)
+ *     10:8    function number
+ *      7:2    register number
+ *  
+ * Notes:
+ *     The function number selects which function of a multi-function device 
+ *     (e.g., scsi and ethernet).
+ * 
+ *     The register selects a DWORD (32 bit) register offset.  Hence it
+ *     doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *     bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+                       unsigned char where, unsigned long *pci_addr,
+                       unsigned char *type1)
+{
+       unsigned long addr;
+
+       DBG(("mk_conf_addr(bus=%d,dfn=0x%x,where=0x%x,addr=0x%lx,type1=0x%x)\n",
+            bus, device_fn, where, pci_addr, type1));
+
+       if (bus == 0) {
+               int device = device_fn >> 3;
+
+               /* type 0 configuration cycle: */
+
+               if (device > 8) {
+                       DBG(("mk_conf_addr: device (%d)>20, returning -1\n",
+                            device));
+                       return -1;
+               }
+
+               *type1 = 0;
+#if 0
+               addr = (device_fn << 8) | (where);
+#else
+               addr = (0x0800L << device) | ((device_fn & 7) << 8) | (where);
+#endif
+       } else {
+               /* type 1 configuration cycle: */
+               *type1 = 1;
+               addr = (bus << 16) | (device_fn << 8) | (where);
+       }
+       *pci_addr = addr;
+       DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+       return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr, unsigned char type1)
+{
+       unsigned long flags;
+       unsigned int stat0, value;
+       unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+       save_flags(flags);      /* avoid getting hit by machine check */
+       cli();
+
+       DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+
+#if 0
+       /* reset status register to avoid losing errors: */
+       stat0 = *((volatile unsigned int *)T2_IOCSR);
+       *((volatile unsigned int *)T2_IOCSR) = stat0;
+       mb();
+       DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0));
+       /* if Type1 access, must set T2 CFG */
+       if (type1) {
+               t2_cfg = *((unsigned int *)T2_IOC_CFG);
+               mb();
+               *((unsigned int *)T2_IOC_CFG) = t2_cfg | 1;
+               DBG(("conf_read: TYPE1 access\n"));
+       }
+       mb();
+       draina();
+#endif
+       T2_mcheck_expected = 1;
+       T2_mcheck_taken = 0;
+       mb();
+       /* access configuration space: */
+       value = *((volatile unsigned int *)addr);
+       mb();
+       mb();
+       if (T2_mcheck_taken) {
+               T2_mcheck_taken = 0;
+               value = 0xffffffffU;
+               mb();
+       }
+       T2_mcheck_expected = 0;
+       mb();
+
+#if 0
+       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       if (type1) {
+               *((unsigned int *)T2_IOC_CFG) = t2_cfg & ~1;
+               mb();
+       }
+#endif
+       DBG(("conf_read(): finished\n"));
+
+       restore_flags(flags);
+       return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value,
+                      unsigned char type1)
+{
+       unsigned long flags;
+       unsigned int stat0;
+       unsigned int t2_cfg = 0; /* to keep gcc quiet */
+
+       save_flags(flags);      /* avoid getting hit by machine check */
+       cli();
+
+#if 0
+       /* reset status register to avoid losing errors: */
+       stat0 = *((volatile unsigned int *)T2_IOCSR);
+       *((volatile unsigned int *)T2_IOCSR) = stat0;
+       mb();
+       DBG(("conf_write: T2 ERR was 0x%x\n", stat0));
+       /* if Type1 access, must set T2 CFG */
+       if (type1) {
+               t2_cfg = *((unsigned int *)T2_IOC_CFG);
+               mb();
+               *((unsigned int *)T2_IOC_CFG) = t2_cfg | 1;
+               DBG(("conf_write: TYPE1 access\n"));
+       }
+       draina();
+#endif
+       T2_mcheck_expected = 1;
+       mb();
+       /* access configuration space: */
+       *((volatile unsigned int *)addr) = value;
+       mb();
+       mb();
+       T2_mcheck_expected = 0;
+       mb();
+
+#if 0
+       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       if (type1) {
+               *((unsigned int *)T2_IOC_CFG) = t2_cfg & ~1;
+               mb();
+       }
+#endif
+       DBG(("conf_write(): finished\n"));
+       restore_flags(flags);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned char *value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xff;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= (pci_addr << 5) + 0x00;
+
+       *value = conf_read(addr, type1) >> ((where & 3) * 8);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned short *value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xffff;
+
+       if (where & 0x1) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= (pci_addr << 5) + 0x08;
+
+       *value = conf_read(addr, type1) >> ((where & 3) * 8);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned int *value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       *value = 0xffffffff;
+       if (where & 0x3) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x18;
+       *value = conf_read(addr, type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned char value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x00;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned short value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x08;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+                               unsigned char where, unsigned int value)
+{
+       unsigned long addr = T2_CONF;
+       unsigned long pci_addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= (pci_addr << 5) + 0x18;
+       conf_write(addr, value << ((where & 3) * 8), type1);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
+{
+        unsigned int t2_err;
+       struct percpu_struct *cpu;
+       int i;
+
+#if 0
+        /* 
+        * Set up error reporting.
+        */
+       t2_err = *(vuip)T2_IOCSR ;
+       t2_err |= (0x1 << 7) ;   /* master abort */
+       *(vuip)T2_IOC_T2_ERR = t2_err ;
+       mb() ;
+#endif
+
+       printk("t2_init: HBASE was 0x%lx\n", *((unsigned long *)T2_HBASE));
+#if 0
+       printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+              *((vulp)T2_WBASE1),
+              *((vulp)T2_WMASK1),
+              *((vulp)T2_TBASE1));
+       printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+              *((vulp)T2_WBASE2),
+              *((vulp)T2_WMASK2),
+              *((vulp)T2_TBASE2));
+#endif
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 1 for enabled and mapped to 0 */
+       if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) &&
+            (*(vuip)T2_TBASE1 == 0))
+       {
+         T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 2!! ?? */
+#if 1
+         printk("t2_init: using Window 1 settings\n");
+         printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)T2_WBASE1,
+                *(vulp)T2_WMASK1,
+                *(vulp)T2_TBASE1);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) &&
+            (*(vuip)T2_TBASE2 == 0))
+       {
+         T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 1!! ?? */
+#if 1
+         printk("t2_init: using Window 2 settings\n");
+         printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)T2_WBASE2,
+                *(vulp)T2_WMASK2,
+                *(vulp)T2_TBASE2);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
+       /*
+        * Set up the PCI->physical memory translation windows.
+        * For now, window 2 is  disabled.  In the future, we may
+        * want to use it to do scatter/gather DMA.  Window 1
+        * goes at 1 GB and is 1 GB large.
+        */
+
+       /* WARNING!! must correspond to the DMA_WIN params!!! */
+       *(vuip)T2_WBASE1 = 0x400807ffU;
+       *(vuip)T2_WMASK1 = 0x3ff00000U;
+       *(vuip)T2_TBASE1 = 0;
+
+       *(vuip)T2_WBASE2 = 0x0;
+       *(vuip)T2_HBASE = 0x0;
+       }
+
+
+       /*
+        * check ASN in HWRPB for validity, report if bad
+        */
+       if (hwrpb->max_asn != MAX_ASN) {
+               printk("T2_init: max ASN from HWRPB is bad (0x%lx)\n",
+                       hwrpb->max_asn);
+               hwrpb->max_asn = MAX_ASN;
+       }
+
+        /*
+         * Finally, clear the T2_HAE_3 register, which gets used
+         *  for PCI Config Space accesses. That is the way
+         *  we want to use it, and we do not want to depend on
+         *  what ARC or SRM might have left behind...
+         */
+        {
+         unsigned long t2_hae_1 = *((unsigned long *)T2_HAE_1);
+         unsigned long t2_hae_2 = *((unsigned long *)T2_HAE_2);
+         unsigned long t2_hae_3 = *((unsigned long *)T2_HAE_3);
+         unsigned long t2_hae_4 = *((unsigned long *)T2_HAE_4);
+#if 1
+          printk("T2_init: HAE1 was 0x%lx\n", t2_hae_1);
+          printk("T2_init: HAE2 was 0x%lx\n", t2_hae_2);
+          printk("T2_init: HAE3 was 0x%lx\n", t2_hae_3);
+          printk("T2_init: HAE4 was 0x%lx\n", t2_hae_4);
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+           sigh... For the SRM setup, unless we know apriori what the HAE
+           contents will be, we need to setup the arbitrary region bases
+           so we can test against the range of addresses and tailor the
+           region chosen for the SPARSE memory access.
+
+           see include/asm-alpha/t2.h for the SPARSE mem read/write
+         */
+         t2_sm_base = (t2_hae_1 << 27) & 0xf8000000UL;
+#else /* SRM_SETUP */
+          *((unsigned int *)T2_HAE_1) = 0; mb();
+          *((unsigned int *)T2_HAE_2) = 0; mb();
+          *((unsigned int *)T2_HAE_3) = 0; mb();
+#if 0
+          *((unsigned int *)T2_HAE_4) = 0; mb();
+#endif
+#endif /* SRM_SETUP */
+        }
+#if 1
+       if (hwrpb->nr_processors > 1) {
+            printk("T2_init: nr_processors 0x%lx\n",
+                  hwrpb->nr_processors);
+            printk("T2_init: processor_size 0x%lx\n",
+                  hwrpb->processor_size);
+            printk("T2_init: processor_offset 0x%lx\n",
+                  hwrpb->processor_offset);
+
+           cpu = (struct percpu_struct *)
+                       ((char*)hwrpb + hwrpb->processor_offset);
+
+           for (i = 0; i < hwrpb->nr_processors; i++ ) {
+               printk("T2_init: CPU 0x%x: flags 0x%lx type 0x%lx\n",
+                      i, cpu->flags, cpu->type);
+               cpu = (struct percpu_struct *)
+                       ((char *)cpu + hwrpb->processor_size);
+           }
+       }
+#endif
+
+       return mem_start;
+}
+
+#define SIC_SEIC (1UL << 33)    /* System Event Clear */
+
+struct sable_cpu_csr *sable_cpu_regs[4] = {
+       (struct sable_cpu_csr *)CPU0_BASE,
+       (struct sable_cpu_csr *)CPU1_BASE,
+       (struct sable_cpu_csr *)CPU2_BASE,
+       (struct sable_cpu_csr *)CPU3_BASE,
+};
+int t2_clear_errors(void)
+{
+       DBGMC(("???????? t2_clear_errors\n"));
+
+       sable_cpu_regs[CPUID]->sic &= ~SIC_SEIC;
+
+       /* 
+        * clear cpu errors
+        */
+       sable_cpu_regs[CPUID]->bcce |= sable_cpu_regs[CPUID]->bcce;
+       sable_cpu_regs[CPUID]->cbe  |= sable_cpu_regs[CPUID]->cbe;
+       sable_cpu_regs[CPUID]->bcue |= sable_cpu_regs[CPUID]->bcue;
+       sable_cpu_regs[CPUID]->dter |= sable_cpu_regs[CPUID]->dter;
+
+       *(unsigned long *)T2_CERR1 |= *(unsigned long *)T2_CERR1;
+       *(unsigned long *)T2_PERR1 |= *(unsigned long *)T2_PERR1;
+
+       mb();
+       mb();
+       return 0;
+}
+
+void t2_machine_check(unsigned long vector, unsigned long la_ptr,
+                      struct pt_regs * regs)
+{
+       struct el_t2_logout_header *mchk_header;
+       struct el_t2_procdata_mcheck *mchk_procdata;
+       struct el_t2_sysdata_mcheck *mchk_sysdata;
+       unsigned long * ptr;
+       const char * reason;
+       char buf[128];
+       long i;
+
+       DBGMC(("t2_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+              vector, la_ptr));
+
+       mchk_header = (struct el_t2_logout_header *)la_ptr;
+
+       DBGMC(("t2_machine_check: susoffset=0x%lx procoffset=0x%lx\n",
+              mchk_header->elfl_sysoffset, mchk_header->elfl_procoffset));
+
+       mchk_sysdata = (struct el_t2_sysdata_mcheck *)
+         (la_ptr + mchk_header->elfl_sysoffset);
+       mchk_procdata = (struct el_t2_procdata_mcheck *)
+         (la_ptr + mchk_header->elfl_procoffset - sizeof(unsigned long)*32);
+
+       DBGMC(("         pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset,
+            mchk_header->elfl_sysoffset));
+       DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected));
+#ifdef DEBUG_DUMP
+       {
+               unsigned long *ptr;
+               int i;
+
+               ptr = (unsigned long *)la_ptr;
+               for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) {
+                       printk(" +%lx %lx %lx\n", i*sizeof(long),
+                              ptr[i], ptr[i+1]);
+               }
+       }
+#endif /* DEBUG_DUMP */
+       /*
+        * Check if machine check is due to a badaddr() and if so,
+        * ignore the machine check.
+        */
+       mb();
+       mb();
+       if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+               DBGMC(("T2 machine check expected\n"));
+               T2_mcheck_taken = 1;
+               t2_clear_errors();
+               T2_mcheck_expected = 0;
+               mb();
+               mb();
+               wrmces(rdmces()|1);/* ??? */
+               draina();
+               return;
+       }
+
+       switch ((unsigned int) mchk_header->elfl_error_type) {
+             case MCHK_K_TPERR:        reason = "tag parity error"; break;
+             case MCHK_K_TCPERR:       reason = "tag control parity error"; break;
+             case MCHK_K_HERR:         reason = "generic hard error"; break;
+             case MCHK_K_ECC_C:        reason = "correctable ECC error"; break;
+             case MCHK_K_ECC_NC:       reason = "uncorrectable ECC error"; break;
+             case MCHK_K_OS_BUGCHECK:  reason = "OS-specific PAL bugcheck"; break;
+             case MCHK_K_PAL_BUGCHECK: reason = "callsys in kernel mode"; break;
+             case 0x96: reason = "i-cache read retryable error"; break;
+             case 0x98: reason = "processor detected hard error"; break;
+
+               /* system specific (these are for Alcor, at least): */
+             case 0x203: reason = "system detected uncorrectable ECC error"; break;
+             case 0x205: reason = "parity error detected by T2"; break;
+             case 0x207: reason = "non-existent memory error"; break;
+             case 0x209: reason = "PCI SERR detected"; break;
+             case 0x20b: reason = "PCI data parity error detected"; break;
+             case 0x20d: reason = "PCI address parity error detected"; break;
+             case 0x20f: reason = "PCI master abort error"; break;
+             case 0x211: reason = "PCI target abort error"; break;
+             case 0x213: reason = "scatter/gather PTE invalid error"; break;
+             case 0x215: reason = "flash ROM write error"; break;
+             case 0x217: reason = "IOA timeout detected"; break;
+             case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
+             case 0x21b: reason = "EISA fail-safe timer timeout"; break;
+             case 0x21d: reason = "EISA bus time-out"; break;
+             case 0x21f: reason = "EISA software generated NMI"; break;
+             case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
+             default:
+               sprintf(buf, "reason for machine-check unknown (0x%x)",
+                       (unsigned int) mchk_header->elfl_error_type);
+               reason = buf;
+               break;
+       }
+       wrmces(rdmces()|1);     /* reset machine check pending flag */
+       mb();
+
+       printk(KERN_CRIT "  T2 machine check: %s%s\n",
+              reason, mchk_header->elfl_retry ? " (retryable)" : "");
+
+       /* dump the the logout area to give all info: */
+
+       ptr = (unsigned long *)la_ptr;
+       for (i = 0; i < mchk_header->elfl_size / sizeof(long); i += 2) {
+           printk(KERN_CRIT " +%8lx %016lx %016lx\n",
+                  i*sizeof(long), ptr[i], ptr[i+1]);
+       }
+}
+
+#endif /* CONFIG_ALPHA_T2 */
index 694820c96edee99751ec2e71732928e0cb997396..6dd3c129b1f09648c91b80be5652c7b89dd2bd4f 100644 (file)
@@ -286,7 +286,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
        extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
        extern unsigned long alpha_read_fp_reg (unsigned long reg);
 
-       pc_addr = frame + 7 + 20 + 1;                   /* pc in PAL frame */
+       pc_addr = frame + 7 + 20 + 3 /* em86 */ + 1;    /* pc in PAL frame */
 
        if (cnt >= 5 && jiffies - last_time > 5*HZ) {
                cnt = 0;
@@ -336,7 +336,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
 
                      case 16: case 17: case 18: 
                        /* a0-a2 in PAL frame */
-                       reg_addr += 7 + 20 + 3 + (reg - 16);
+                       reg_addr += 7 + 20 + 3 /* em86 */ + 3 + (reg - 16);
                        break;
 
                      case 19: case 20: case 21: case 22: case 23: 
@@ -347,7 +347,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
 
                      case 29:
                        /* gp in PAL frame */
-                       reg_addr += 7 + 20 + 2;
+                       reg_addr += 7 + 20 + 3 /* em86 */ + 2;
                        break;
 
                      case 30:
index f45b7069b60d8d49802e9d2bc9768c9e35d004b5..43a5b1fa0c6565142708fd73d0345cf959f6fd4d 100644 (file)
@@ -13,9 +13,9 @@
 #define OPC_INTL       0x11
 #define OPC_INTS       0x12
 #define OPC_INTM       0x13
-#define OPC_FLTV       0x14
-#define OPC_FLTI       0x15
-#define OPC_FLTL       0x16
+#define OPC_FLTV       0x15
+#define OPC_FLTI       0x16
+#define OPC_FLTL       0x17
 
 #define OPC_MISC       0x18
 
index 12676f1aa55febcf7442c78d7c220ef364499dee..e550774d94bf54e6fbbc7a4430c713ce46673769 100644 (file)
@@ -26,6 +26,8 @@
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
+struct thread_struct * original_pcb_ptr;
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -81,15 +83,19 @@ void show_mem(void)
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
-static void load_PCB(struct thread_struct * pcb)
+static struct thread_struct * load_PCB(struct thread_struct * pcb)
 {
+       struct thread_struct *old_pcb;
+
        __asm__ __volatile__(
-               "stq $30,0(%0)\n\t"
-               "bis %0,%0,$16\n\t"
-               "call_pal %1"
-               : /* no outputs */
+               "stq $30,0(%1)\n\t"
+               "bis %1,%1,$16\n\t"
+               "call_pal %2\n\t"
+               "bis $0,$0,%0"
+               : "=r" (old_pcb)
                : "r" (pcb), "i" (PAL_swpctx)
                : "$0", "$1", "$16", "$22", "$23", "$24", "$25");
+       return old_pcb;
 }
 
 /*
@@ -107,10 +113,15 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        start_mem = free_area_init(start_mem, end_mem);
 
        /* find free clusters, update mem_map[] accordingly */
-       memdesc = (struct memdesc_struct *) (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+       memdesc = (struct memdesc_struct *)
+               (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
        cluster = memdesc->cluster;
        for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
                unsigned long pfn, nr;
+#if 0
+printk("paging_init: cluster %d usage %ld start %ld size %ld\n",
+       i, cluster->usage, cluster->start_pfn, cluster->numpages);
+#endif
                if (cluster->usage & 1)
                        continue;
                pfn = cluster->start_pfn;
@@ -134,7 +145,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        init_task.tss.pal_flags = 1;    /* set FEN, clear everything else */
        init_task.tss.flags = 0;
        init_task.kernel_stack_page = INIT_STACK;
-       load_PCB(&init_task.tss);
+       original_pcb_ptr = load_PCB(&init_task.tss);
 
        flush_tlb_all();
        return start_mem;
index ee34abdda3c27d8e4459a8846a48fbd191889f51..12ae5a5b38f06f331324903e096e7718d720735e 100644 (file)
@@ -326,7 +326,7 @@ ENTRY(system_call)
        ALIGN
 1:     call SYMBOL_NAME(syscall_trace)
        movl ORIG_EAX(%esp),%eax
-       call SYMBOL_NAME(sys_call_table)(,%eax,4)
+       call *SYMBOL_NAME(sys_call_table)(,%eax,4)
        movl %eax,EAX(%esp)             # save the return value
 #ifdef __SMP__
        GET_PROCESSOR_OFFSET(%eax)
index c1d7390564d0a4fbc4e7dc03bf73861fa5eab80f..be1f46467de23ca048674d80194ea68161f47fe7 100644 (file)
@@ -689,3 +689,9 @@ asmlinkage void syscall_trace(void)
                current->signal |= (1 << (current->exit_code - 1));
        current->exit_code = 0;
 }
+
+void get_pt_regs_for_task(struct pt_regs *regs, struct task_struct *task)
+{
+        *regs = *(struct pt_regs *) (((unsigned char *) task->tss.esp0) - MAGICNUMBER);
+}
+
index 5fa9d4ba3367127a975d6ba6256ab37ab93e1ea3..4682a178c61d499703625d68faba955f445a75a9 100644 (file)
@@ -1025,7 +1025,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         */
         
        if(ct==1000)
-               printk("CPU #%d: previous IPI still not cleared after 10mS", smp_processor_id());
+               printk("CPU #%d: previous IPI still not cleared after 10ms\n", smp_processor_id());
                
        /*
         *      Program the APIC to deliver the IPI
index 9215efbb0cb225581033474931959cf0c9220d42..ebee7ff589cbee657c090b00735058c2be9bb17f 100644 (file)
@@ -102,6 +102,7 @@ static void add_partition (struct gendisk *hd, int minor, int start, int size)
 static inline int is_extended_partition(struct partition *p)
 {
        return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
+               SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
                SYS_IND(p) == LINUX_EXTENDED_PARTITION);
 }
 
index 9d9432d0a515e4892d0dff59c1e6c9832aa459a0..2cd4efd27afd03c46d48ba56a097190829a430bd 100644 (file)
@@ -2634,11 +2634,12 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
 {
        int hd_status, rc;
        unsigned long timeout;
-       int irqs = 0;
+       unsigned long irqs_on = 0;
+       int irq_off;
 
        if (!HWIF(drive)->irq) {                /* already got an IRQ? */
                probe_irq_off(probe_irq_on());  /* clear dangling irqs */
-               irqs = probe_irq_on();          /* start monitoring irqs */
+               irqs_on = probe_irq_on();       /* start monitoring irqs */
                OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
        }
 
@@ -2652,8 +2653,8 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
 #if CONFIG_BLK_DEV_PROMISE
        if (IS_PROMISE_DRIVE) {
                if (promise_cmd(drive,PROMISE_IDENTIFY)) {
-                       if (irqs)
-                               (void) probe_irq_off(irqs);
+                       if (irqs_on)
+                               (void) probe_irq_off(irqs_on);
                        return 1;
                }
        } else
@@ -2663,8 +2664,8 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
        timeout += jiffies;
        do {
                if (jiffies > timeout) {
-                       if (irqs)
-                               (void) probe_irq_off(irqs);
+                       if (irqs_on)
+                               (void) probe_irq_off(irqs_on);
                        return 1;       /* drive timed-out */
                }
                delay_50ms();           /* give drive a breather */
@@ -2682,18 +2683,18 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
        } else
                rc = 2;                 /* drive refused ID */
        if (!HWIF(drive)->irq) {
-               irqs = probe_irq_off(irqs);     /* get our irq number */
-               if (irqs > 0) {
-                       HWIF(drive)->irq = irqs; /* save it for later */
-                       irqs = probe_irq_on();
+               irq_off = probe_irq_off(irqs_on);       /* get our irq number */
+               if (irq_off > 0) {
+                       HWIF(drive)->irq = irq_off; /* save it for later */
+                       irqs_on = probe_irq_on();
                        OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
                        udelay(5);
-                       (void) probe_irq_off(irqs);
+                       (void) probe_irq_off(irqs_on);
                        (void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */
                        (void) GET_STAT();      /* clear drive IRQ */
 
                } else {        /* Mmmm.. multiple IRQs.. don't know which was ours */
-                       printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
+                       printk("%s: IRQ probe failed (%d)\n", drive->name, irq_off);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
                        if (HWIF(drive)->chipset == ide_cmd640) {
index d064929601ebbbb7fafcb614d89af8036298ca0c..0376f64243d40dd41f47e9b187f8505dca9d82d1 100644 (file)
@@ -422,7 +422,7 @@ done:
 /*
  * This routine loads in the ramdisk image.
  */
-static void rd_load_image(kdev_t device,int offset)
+static void rd_load_image(kdev_t device,int offset, int unit)
 {
        struct inode inode, out_inode;
        struct file infile, outfile;
@@ -433,7 +433,7 @@ static void rd_load_image(kdev_t device,int offset)
        unsigned short rotate = 0;
        char rotator[4] = { '|' , '/' , '-' , '\\' };
 
-       ram_device = MKDEV(MAJOR_NR, 0);
+       ram_device = MKDEV(MAJOR_NR, unit);
 
        memset(&infile, 0, sizeof(infile));
        memset(&inode, 0, sizeof(inode));
@@ -500,7 +500,7 @@ static void rd_load_image(kdev_t device,int offset)
 
 successful_load:
        invalidate_buffers(device);
-       ROOT_DEV = MKDEV(MAJOR_NR,0);
+       ROOT_DEV = MKDEV(MAJOR_NR,unit);
 
 done:
        if (infile.f_op->release)
@@ -509,12 +509,21 @@ done:
 }
 
 
-void rd_load()
+static void rd_load_disk(int n)
 {
+#ifdef CONFIG_BLK_DEV_INITRD
+       extern kdev_t real_root_dev;
+#endif 
+       
        if (rd_doload == 0)
                return;
        
-       if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
+       if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR
+#ifdef CONFIG_BLK_DEV_INITRD   
+               && MAJOR(real_root_dev) != FLOPPY_MAJOR
+#endif         
+       )
+                       return;
 
        if (rd_prompt) {
 #ifdef CONFIG_BLK_DEV_FD
@@ -525,15 +534,24 @@ void rd_load()
                wait_for_keypress();
        }
 
-       rd_load_image(ROOT_DEV,rd_image_start);
+       rd_load_image(ROOT_DEV,rd_image_start,n);
+
+}
 
+void rd_load(void)
+{
+       rd_load_disk(0);
 }
 
+void rd_load_secondary(void)
+{
+       rd_load_disk(1);
+}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void initrd_load(void)
 {
-       rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
+       rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
 }
 #endif
 
@@ -658,6 +676,13 @@ static int
 crd_load(struct file * fp, struct file *outfp)
 {
        int result;
+
+       insize = 0;  /* valid bytes in inbuf */
+       inptr = 0;   /* index of next byte to be processed in inbuf */
+       outcnt = 0;  /* bytes in output buffer */
+       exit_code = 0;
+       bytes_out = 0;
+       crc = 0xFFFFFFFF;
        
        crd_infp = fp;
        crd_outfp = outfp;
index a6e3464c4f44546d2ada9c35b58443b60081eb3c..256bec07904976f0e2f8da1212d361d9082fe00b 100644 (file)
@@ -59,6 +59,9 @@ if [ "$CONFIG_APM" = "y" ]; then
   bool '   Power off on shutdown' CONFIG_APM_POWER_OFF
   bool '   Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 fi
+if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
+  bool 'Tadpole ANA H8 Support'        CONFIG_H8
+fi
 bool 'Watchdog Timer Support'  CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
index 205a78428bdbee6a547db9db3b2f8b0c27b65911..49f68af0511fb41bf86ef76cbffccb986bd9f516 100644 (file)
@@ -196,6 +196,11 @@ LX_OBJS += apm_bios.o
 M = y
 endif
 
+ifdef CONFIG_H8
+LX_OBJS += h8.o
+M = y
+endif
+
 ifdef M
 LX_OBJS += misc.o
 else
@@ -222,6 +227,9 @@ endif
 
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
+  ifdef CONFIG_VGA_CONSOLE
+    L_OBJS += vga.o vesa_blank.o
+  endif
 else
  ifndef CONFIG_SUN_CONSOLE
  L_OBJS += vga.o vesa_blank.o
diff --git a/drivers/char/h8.c b/drivers/char/h8.c
new file mode 100644 (file)
index 0000000..73941a0
--- /dev/null
@@ -0,0 +1,1272 @@
+/*
+ */
+/*
+ * Hitachi H8/337 Microcontroller driver
+ *
+ * The H8 is used to deal with the power and thermal environment
+ * of a system.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/lists.h>
+#include <linux/ioport.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+
+#include "h8.h"
+
+#define DEBUG_H8
+
+#ifdef DEBUG_H8
+#define Dprintk                printk
+#else
+#define Dprintk
+#endif
+
+#define XDprintk if(h8_debug==-1)printk
+
+/*
+ * The h8 device is one of the misc char devices.
+ */
+#define H8_MINOR_DEV   140
+
+/*
+ * Forward declarations.
+ */
+int          h8_init(void);
+int          h8_display_blank(void);
+int          h8_display_unblank(void);
+
+static int   h8_open(struct inode *, struct file *);
+static void  h8_release(struct inode *, struct file *);
+static long  h8_read(struct inode *, struct file *, char *, u_long);
+static int   h8_select(struct inode *, struct file *, int, select_table *);
+static int   h8_ioctl(struct inode *, struct file *, u_int, u_long);
+
+static void  h8_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+#ifdef CONFIG_PROC_FS
+static int   h8_get_info(char *, char **, off_t, int, int);
+#endif
+
+/*
+ * Support Routines.
+ */
+static void h8_hw_init(void);
+static void h8_start_new_cmd(void);
+static void h8_send_next_cmd_byte(void);
+static void h8_read_event_status(void);
+static void h8_sync(void);
+static void h8_q_cmd(u_char *, int, int);
+static void h8_cmd_done(h8_cmd_q_t *qp);
+static int  h8_alloc_queues(void);
+
+static u_long h8_get_cpu_speed(void);
+static int h8_get_curr_temp(u_char curr_temp[]);
+static void h8_get_max_temp(void);
+static void h8_get_upper_therm_thold(void);
+static void h8_set_upper_therm_thold(int);
+static int h8_get_ext_status(u_char stat_word[]);
+
+static int h8_monitor_thread(void *);
+
+static int h8_manage_therm(void);
+static void h8_set_cpu_speed(int speed_divisor);
+
+static void h8_start_monitor_timer(unsigned long secs);
+static void h8_activate_monitor(unsigned long unused);
+
+/* in arch/alpha/kernel/lca.c */
+extern void lca_clock_print(void);
+extern int  lca_get_clock(void);
+extern void lca_clock_fiddle(int);
+
+static void h8_set_event_mask(int);
+static void h8_clear_event_mask(int);
+
+/*
+ * Driver structures
+ */
+
+static struct timer_list h8_monitor_timer;
+static int h8_monitor_timer_active = 0;
+
+static char  driver_version[] = "X0.0";/* no spaces */
+
+static struct file_operations h8_fops = {
+        NULL,           /* lseek */
+        h8_read,
+        NULL,           /* write */
+        NULL,           /* readdir */
+        h8_select,
+        h8_ioctl,
+        NULL,           /* mmap */
+        h8_open,
+        h8_release,
+        NULL,           /* fsync */
+        NULL            /* fasync */
+};
+
+static struct miscdevice h8_device = {
+        H8_MINOR_DEV,
+        "h8",
+        &h8_fops
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry    h8_proc_entry = {
+        0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info
+};
+#endif
+
+union  intr_buf intrbuf;
+int    intr_buf_ptr;
+union   intr_buf xx;   
+u_char  last_temp;
+
+/*
+ * I/O Macros for register reads and writes.
+ */
+#define H8_READ(a)     inb((a))
+#define H8_WRITE(d,a)  outb((d),(a))
+
+#define        H8_GET_STATUS   H8_READ((h8_base) + H8_STATUS_REG_OFF)
+#define H8_READ_DATA   H8_READ((h8_base) + H8_DATA_REG_OFF)
+#define WRITE_DATA(d)  H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
+#define WRITE_CMD(d)   H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
+
+unsigned int h8_base = H8_BASE_ADDR;
+unsigned int h8_irq = H8_IRQ;
+unsigned int h8_state = H8_IDLE;
+unsigned int h8_index = -1;
+unsigned int h8_enabled = 0;
+
+queue_head_t h8_actq, h8_cmdq, h8_freeq;
+
+/* 
+ * Globals used in thermal control of Alphabook1.
+ */
+int cpu_speed_divisor = -1;                    
+int h8_event_mask = 0;                 
+struct wait_queue *h8_monitor_wait = NULL;
+unsigned int h8_command_mask = 0;
+int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
+int h8_uthermal_window = UTH_HYSTERESIS;                     
+int h8_debug = 0xfffffdfc;
+int h8_ldamp = MHZ_115;
+int h8_udamp = MHZ_57;
+u_char h8_current_temp = 0;
+u_char h8_system_temp = 0;
+int h8_sync_channel = 0;
+struct wait_queue *h8_sync_wait = NULL;
+int h8_init_performed;
+
+/* CPU speeds and clock divisor values */
+int speed_tab[6] = {230, 153, 115, 57, 28, 14};
+  
+/*
+ * H8 interrupt handler
+ */
+static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+       u_char  stat_reg, data_reg;
+       h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+
+       stat_reg = H8_GET_STATUS;
+       data_reg = H8_READ_DATA;
+
+       XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
+
+       switch (h8_state) {
+         /* Response to an asynchronous event. */
+       case H8_IDLE: { /* H8_IDLE */
+           if (stat_reg & H8_OFULL) {
+               if (data_reg == H8_INTR) {
+                   h8_state = H8_INTR_MODE;
+                   /* Executing a command to determine what happened. */
+                   WRITE_CMD(H8_RD_EVENT_STATUS);
+                   intr_buf_ptr = 1;
+                   WRITE_CMD(H8_RD_EVENT_STATUS);
+               } else {
+                   Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
+                           stat_reg, data_reg);
+               }
+           } else {
+               Dprintk("h8_intr: bogus interrupt\n");
+           }
+           break;
+       }
+       case H8_INTR_MODE: { /* H8_INTR_MODE */
+           XDprintk("H8 intr/intr_mode\n");
+           if (data_reg == H8_BYTE_LEVEL_ACK) {
+               return;
+           } else if (data_reg == H8_CMD_ACK) {
+               return;
+           } else {
+               intrbuf.byte[intr_buf_ptr] = data_reg;
+               if(!intr_buf_ptr) {
+                   h8_state = H8_IDLE;
+                   h8_read_event_status();
+               }
+               intr_buf_ptr--;
+           }
+           break;
+       }
+       /* Placed in this state by h8_start_new_cmd(). */
+       case H8_XMIT: { /* H8_XMIT */
+           XDprintk("H8 intr/xmit\n");
+           /* If a byte level acknowledgement has been received */
+           if (data_reg == H8_BYTE_LEVEL_ACK) {
+               XDprintk("H8 intr/xmit BYTE ACK\n");
+               qp->nacks++;
+               if (qp->nacks > qp->ncmd)
+                   if(h8_debug & 0x1)
+                       Dprintk("h8intr: bogus # of acks!\n");
+               /* 
+                * If the number of bytes sent is less than the total 
+                * number of bytes in the command.
+                */ 
+               if (qp->cnt < qp->ncmd) {
+                   h8_send_next_cmd_byte();
+               }
+               return;
+               /* If the complete command has produced an acknowledgement. */
+           } else if (data_reg == H8_CMD_ACK) {
+               XDprintk("H8 intr/xmit CMD ACK\n");
+               /* If there are response bytes */
+               if (qp->nrsp)
+                   h8_state = H8_RCV;
+               else
+                   h8_state = H8_IDLE;
+               qp->cnt = 0;
+               return;
+               /* Error, need to start over with a clean slate. */
+           } else if (data_reg == H8_NACK) {
+               XDprintk("h8_intr: NACK received restarting command\n");
+               qp->nacks = 0;
+               qp->cnt = 0;
+               h8_state = H8_IDLE;
+               WRITE_CMD(H8_SYNC);
+               return;
+           } else {
+               Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
+               return;
+           }
+           break;
+       }
+       case H8_RESYNC: { /* H8_RESYNC */
+           XDprintk("H8 intr/resync\n");
+           if (data_reg == H8_BYTE_LEVEL_ACK) {
+               return;
+           } else if (data_reg == H8_SYNC_BYTE) {
+               h8_state = H8_IDLE;
+               if (!QUEUE_EMPTY(&h8_actq, link))
+                   h8_send_next_cmd_byte();
+           } else {
+               Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
+               return;
+           }
+           break;
+       } 
+       case H8_RCV: { /* H8_RCV */
+           XDprintk("H8 intr/rcv\n");
+           if (qp->cnt < qp->nrsp) {
+               qp->rcvbuf[qp->cnt] = data_reg;
+               qp->cnt++;
+               /* If command reception finished. */
+               if (qp->cnt == qp->nrsp) {
+                   h8_state = H8_IDLE;
+                   QUEUE_REMOVE(&h8_actq, qp, link);
+                   h8_cmd_done (qp);
+                   /* More commands to send over? */
+                   if (!QUEUE_EMPTY(&h8_cmdq, link))
+                       h8_start_new_cmd();
+               }
+               return;
+           } else {
+               Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
+           }
+           break;
+       }
+       default: /* default */
+           Dprintk("H8 intr/unknown\n");
+           break;
+       }
+       return;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        printk("H8 module at %X(Interrupt %d)\n", h8_base, h8_irq);
+        if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+        {
+                printk("H8: error: IRQ %d is not free.\n", h8_irq);
+                return -EIO;
+        }
+
+        misc_register(&h8_device);
+        request_region(h8_base, 8, "h8");
+
+#ifdef CONFIG_PROC_FS
+        proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+       QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+       QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+       QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+       h8_alloc_queues();
+
+       h8_hw_init();
+
+       kernel_thread(h8_monitor_thread, NULL, 0);
+
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        misc_deregister(&h8_device);
+        release_region(h8_base, 8);
+        free_irq(h8_irq, NULL);
+}
+
+#else /* MODULE */
+
+int h8_init(void)
+{
+        if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+        {
+                printk("H8: error: IRQ %d is not free\n", h8_irq);
+                return -EIO;
+        }
+        printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
+
+#ifdef CONFIG_PROC_FS
+        proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+        misc_register(&h8_device);
+        request_region(h8_base, 8, "h8");
+
+       QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+       QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+       QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+       h8_alloc_queues();
+
+       h8_hw_init();
+
+       kernel_thread(h8_monitor_thread, NULL, 0);
+
+        return 0;
+}
+#endif /* MODULE */
+
+void h8_hw_init(void)
+{
+       u_char  buf[H8_MAX_CMD_SIZE];
+
+       /* set CPU speed to max for booting */
+       h8_set_cpu_speed(MHZ_230);
+
+       /*
+        * Initialize the H8
+        */
+       h8_sync();  /* activate interrupts */
+
+       /* To clear conditions left by console */
+       h8_read_event_status(); 
+
+       /* Perform a conditioning read */
+       buf[0] = H8_DEVICE_CONTROL;
+       buf[1] = 0xff;
+       buf[2] = 0x0;
+       h8_q_cmd(buf, 3, 1);
+
+       /* Turn on built-in and external mice, capture power switch */
+       buf[0] = H8_DEVICE_CONTROL;
+       buf[1] = 0x0;
+       buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
+              /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
+       h8_q_cmd(buf, 3, 1);
+
+        h8_enabled = 1;
+       return;
+}
+
+#ifdef CONFIG_PROC_FS
+int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
+{
+        char *p;
+
+        if (!h8_enabled)
+                return 0;
+        p = buf;
+
+
+        /*
+           0) Linux driver version (this will change if format changes)
+           1) 
+           2) 
+           3)
+           4)
+       */
+            
+        p += sprintf(p, "%s \n",
+                     driver_version
+                    );
+
+        return p - buf;
+}
+#endif
+
+static long h8_read(struct inode *inode, struct file *fp, char *buf,
+                   u_long count)
+{
+       printk("h8_read: IMPDEL\n");
+       return 0;
+}
+
+static int h8_select(struct inode *inode, struct file *fp, int sel_type,
+                     select_table * wait)
+{
+       printk("h8_select: IMPDEL\n");
+       return 0;
+}
+
+static int h8_ioctl(struct inode * inode, struct file *filp,
+                    u_int cmd, u_long arg)
+{
+       printk("h8_ioctl: IMPDEL\n");
+       return 0;
+}
+
+static void h8_release(struct inode * inode, struct file * filp)
+{
+       printk("h8_release: IMPDEL\n");
+}
+
+static int h8_open(struct inode * inode, struct file * filp)
+{
+       printk("h8_open: IMPDEL\n");
+       return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_blank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+        int     error;
+
+        if (!h8_enabled)
+                return 0;
+        error = h8_set_display_power_state(H8_STATE_STANDBY);
+        if (error == H8_SUCCESS)
+                return 1;
+        h8_error("set display standby", error);
+#endif
+        return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_unblank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+        int error;
+
+        if (!h8_enabled)
+                return 0;
+        error = h8_set_display_power_state(H8_STATE_READY);
+        if (error == H8_SUCCESS)
+                return 1;
+        h8_error("set display ready", error);
+#endif
+        return 0;
+}
+
+int
+h8_alloc_queues(void)
+{
+        h8_cmd_q_t *qp;
+       unsigned long flags;
+        int i;
+
+        qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
+                                  GFP_KERNEL);
+
+        if (!qp) {
+                printk("H8: could not allocate memory for command queue\n");
+                return(0);
+        }
+        /* add to the free queue */
+        save_flags(flags); cli();
+        for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
+                /* place each at front of freeq */
+                QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *);
+        }
+        restore_flags(flags);
+        return (1);
+}
+
+/* 
+ * Basic means by which commands are sent to the H8.
+ */
+void
+h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
+{
+        h8_cmd_q_t      *qp;
+       unsigned long flags;
+        int             i;
+
+        /* get cmd buf */
+       save_flags(flags); cli();
+        while (QUEUE_EMPTY(&h8_freeq, link)) {
+                Dprintk("H8: need to allocate more cmd buffers\n");
+                restore_flags(flags);
+                h8_alloc_queues();
+                save_flags(flags); cli();
+        }
+        /* get first element from queue */
+        qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link);
+        QUEUE_REMOVE(&h8_freeq, qp, link);
+
+        restore_flags(flags);
+
+        /* fill it in */
+        for (i = 0; i < cmd_size; i++)
+            qp->cmdbuf[i] = cmd[i];
+        qp->ncmd = cmd_size;
+        qp->nrsp = resp_size;
+
+        /* queue it at the end of the cmd queue */
+        save_flags(flags); cli();
+
+        QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *);
+
+        restore_flags(flags);
+
+        h8_start_new_cmd();
+}
+
+void
+h8_start_new_cmd(void)
+{
+        unsigned long flags;
+        h8_cmd_q_t *qp;
+
+       save_flags(flags); cli();
+        if (h8_state != H8_IDLE) {
+                if (h8_debug & 0x1)
+                        Dprintk("h8_start_new_cmd: not idle\n");
+                restore_flags(flags);
+                return;
+        }
+
+        if (!QUEUE_EMPTY(&h8_actq, link)) {
+                Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
+                restore_flags(flags);
+                return;
+        }
+
+        if (QUEUE_EMPTY(&h8_cmdq, link)) {
+                Dprintk("h8_start_new_cmd: no command to dequeue\n");
+                restore_flags(flags);
+                return;
+        }
+        /*
+         * Take first command off of the command queue and put
+         * it on the active queue.
+         */
+        qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link);
+        QUEUE_REMOVE(&h8_cmdq, qp, link);
+        QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *);
+        h8_state = H8_XMIT;
+        if (h8_debug & 0x1)
+                Dprintk("h8_start_new_cmd: Starting a command\n");
+
+        qp->cnt = 1;
+        WRITE_CMD(qp->cmdbuf[0]);               /* Kick it off */
+
+        restore_flags(flags);
+        return;
+}
+
+void
+h8_send_next_cmd_byte(void)
+{
+        h8_cmd_q_t      *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+        int cnt;
+
+        cnt = qp->cnt;
+        qp->cnt++;
+
+        if (h8_debug & 0x1)
+                Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
+                       cnt, qp->cmdbuf[cnt]);
+
+        if (cnt) {
+                WRITE_DATA(qp->cmdbuf[cnt]);
+        } else {
+                WRITE_CMD(qp->cmdbuf[cnt]);
+        }
+        return;
+}
+
+/*
+ * Synchronize H8 communications channel for command transmission.
+ */
+void
+h8_sync(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_SYNC;
+        buf[1] = H8_SYNC_BYTE;
+        h8_q_cmd(buf, 2, 1);
+}
+
+/*
+ * Responds to external interrupt. Reads event status word and 
+ * decodes type of interrupt. 
+ */
+void
+h8_read_event_status(void)
+{
+
+        if(h8_debug & 0x200)
+                printk("h8_read_event_status: value 0x%x\n", intrbuf.word);
+
+        /*
+         * Power related items
+         */
+        if (intrbuf.word & H8_DC_CHANGE) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: DC_CHANGE\n");
+                /* see if dc added or removed, set batt/dc flag, send event */
+
+                h8_set_event_mask(H8_MANAGE_BATTERY);
+                wake_up(&h8_monitor_wait);
+        }
+
+        if (intrbuf.word & H8_POWER_BUTTON) {
+                printk("Power switch pressed - please wait - preparing to power 
+off\n");
+                h8_set_event_mask(H8_POWER_BUTTON);
+                wake_up(&h8_monitor_wait);
+        }
+
+        /*
+         * Thermal related items
+         */
+        if (intrbuf.word & H8_THERMAL_THRESHOLD) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: THERMAL_THRESHOLD\n");
+                h8_set_event_mask(H8_MANAGE_UTHERM);
+                wake_up(&h8_monitor_wait);
+        }
+
+        /*
+         * nops -for now
+         */
+        if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: DOCKING_STATION_STATUS\n");
+                /* read_ext_status */
+        }
+        if (intrbuf.word & H8_EXT_BATT_STATUS) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: EXT_BATT_STATUS\n");
+
+        }
+        if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
+
+        }
+        if (intrbuf.word & H8_BATT_CHANGE_OVER) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: BATT_CHANGE_OVER\n");
+
+        }
+        if (intrbuf.word & H8_WATCHDOG) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: WATCHDOG\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_SHUTDOWN) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: SHUTDOWN\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_KEYBOARD) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: KEYBOARD\n");
+                /* nop */
+        }
+        if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
+                /* read_ext_status*/
+        }
+        if (intrbuf.word & H8_INT_BATT_LOW) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: INT_BATT_LOW\n");
+                /* post event, warn user */
+        }
+        if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n");
+                /* nop - happens often */
+        }
+        if (intrbuf.word & H8_INT_BATT_STATUS) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: INT_BATT_STATUS\n");
+
+        }
+        if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
+                /* nop - happens often */
+        }
+        if (intrbuf.word & H8_EXT_BATT_LOW) {
+               if(h8_debug & 0x4)
+                   printk("h8_read_event_status: EXT_BATT_LOW\n");
+                /*if no internal, post event, warn user */
+                /* else nop */
+        }
+
+        return;
+}
+
+/*
+ * Function called when H8 has performed requested command.
+ */
+void
+h8_cmd_done(h8_cmd_q_t *qp)
+{
+
+        /* what to do */
+        switch (qp->cmdbuf[0]) {
+       case H8_SYNC:
+           if (h8_debug & 0x40000) 
+               printk("H8: Sync command done - byte returned was 0x%x\n", 
+                      qp->rcvbuf[0]);
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_RD_SN:
+       case H8_RD_ENET_ADDR:
+           printk("H8: Read ethernet addr - command done - address: %x - %x - %x - %x - %x - %x \n", 
+                  qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
+                  qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_RD_HW_VER:
+       case H8_RD_MIC_VER:
+       case H8_RD_MAX_TEMP:
+           printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
+                  qp->rcvbuf[0], qp->rcvbuf[1]);
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_RD_MIN_TEMP:
+           printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
+                  qp->rcvbuf[0], qp->rcvbuf[1]);
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_RD_CURR_TEMP:
+           h8_sync_channel |= H8_RD_CURR_TEMP;
+           xx.byte[0] = qp->rcvbuf[0];
+           xx.byte[1] = qp->rcvbuf[1];
+           wake_up(&h8_sync_wait); 
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); 
+           break;
+
+       case H8_RD_SYS_VARIENT:
+       case H8_RD_PWR_ON_CYCLES:
+           printk(" H8: RD_PWR_ON_CYCLES command done\n");
+           break;
+
+       case H8_RD_PWR_ON_SECS:
+           printk("H8: RD_PWR_ON_SECS command done\n");
+           break;
+
+       case H8_RD_RESET_STATUS:
+       case H8_RD_PWR_DN_STATUS:
+       case H8_RD_EVENT_STATUS:
+       case H8_RD_ROM_CKSM:
+       case H8_RD_EXT_STATUS:
+           xx.byte[1] = qp->rcvbuf[0];
+           xx.byte[0] = qp->rcvbuf[1];
+           h8_sync_channel |= H8_GET_EXT_STATUS;
+           wake_up(&h8_sync_wait); 
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); 
+           break;
+
+       case H8_RD_USER_CFG:
+       case H8_RD_INT_BATT_VOLT:
+       case H8_RD_DC_INPUT_VOLT:
+       case H8_RD_HORIZ_PTR_VOLT:
+       case H8_RD_VERT_PTR_VOLT:
+       case H8_RD_EEPROM_STATUS:
+       case H8_RD_ERR_STATUS:
+       case H8_RD_NEW_BUSY_SPEED:
+       case H8_RD_CONFIG_INTERFACE:
+       case H8_RD_INT_BATT_STATUS:
+           printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
+                  qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_RD_EXT_BATT_STATUS:
+       case H8_RD_PWR_UP_STATUS:
+       case H8_RD_EVENT_STATUS_MASK:
+       case H8_CTL_EMU_BITPORT:
+       case H8_DEVICE_CONTROL:
+           if(h8_debug & 0x20000) {
+               printk("H8: Device control cmd done - byte returned was 0x%x\n",
+                      qp->rcvbuf[0]);
+           }
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_CTL_TFT_BRT_DC:
+       case H8_CTL_WATCHDOG:
+       case H8_CTL_MIC_PROT:
+       case H8_CTL_INT_BATT_CHG:
+       case H8_CTL_EXT_BATT_CHG:
+       case H8_CTL_MARK_SPACE:
+       case H8_CTL_MOUSE_SENSITIVITY:
+       case H8_CTL_DIAG_MODE:
+       case H8_CTL_IDLE_AND_BUSY_SPDS:
+           printk("H8: Idle and busy speed command done\n");
+           break;
+
+       case H8_CTL_TFT_BRT_BATT:
+       case H8_CTL_UPPER_TEMP:
+           if(h8_debug & 0x10) {
+               XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
+                      qp->rcvbuf[0]);
+           }
+           QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+           break;
+
+       case H8_CTL_LOWER_TEMP:
+       case H8_CTL_TEMP_CUTOUT:
+       case H8_CTL_WAKEUP:
+       case H8_CTL_CHG_THRESHOLD:
+       case H8_CTL_TURBO_MODE:
+       case H8_SET_DIAG_STATUS:
+       case H8_SOFTWARE_RESET:
+       case H8_RECAL_PTR:
+       case H8_SET_INT_BATT_PERCENT:
+       case H8_WRT_CFG_INTERFACE_REG:
+       case H8_WRT_EVENT_STATUS_MASK:
+       case H8_ENTER_POST_MODE:
+       case H8_EXIT_POST_MODE:
+       case H8_RD_EEPROM:
+       case H8_WRT_EEPROM:
+       case H8_WRT_TO_STATUS_DISP:
+           printk("H8: Write IO status display command done\n");
+           break;
+
+       case H8_DEFINE_SPC_CHAR:
+       case H8_DEFINE_TABLE_STRING_ENTRY:
+       case H8_PERFORM_EMU_CMD:
+       case H8_EMU_RD_REG:
+       case H8_EMU_WRT_REG:
+       case H8_EMU_RD_RAM:
+       case H8_EMU_WRT_RAM:
+       case H8_BQ_RD_REG:
+       case H8_BQ_WRT_REG:
+       case H8_PWR_OFF:
+           printk ("H8: misc command completed\n");
+           break;
+        }
+        return;
+}
+
+/*
+ * Retrieve the current cpu temperature and case temperature.  Provides
+ * the feedback for the thermal control algorithm.  Synchcronized via 
+ * sleep() for priority so that no other actions in the process will take
+ * place before the data becomes available.
+ */
+int
+h8_get_curr_temp(u_char curr_temp[])
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+        unsigned long flags;
+
+        memset(buf, 0, H8_MAX_CMD_SIZE); 
+        buf[0] = H8_RD_CURR_TEMP;
+
+        h8_q_cmd(buf, 1, 2);
+
+       save_flags(flags); cli();
+
+        while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
+                sleep_on(&h8_sync_wait); 
+
+        restore_flags(flags);
+
+        h8_sync_channel &= ~H8_RD_CURR_TEMP;
+        curr_temp[0] = xx.byte[0];
+        curr_temp[1] = xx.byte[1];
+        xx.word = 0;
+
+        if(h8_debug & 0x8) 
+                printk("H8: curr CPU temp %d, Sys temp %d\n",
+                      curr_temp[0], curr_temp[1]);
+        return 0;
+}
+
+static void
+h8_get_max_temp(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_RD_MAX_TEMP;
+        h8_q_cmd(buf, 1, 2);
+}
+
+/*
+ * Assigns an upper limit to the value of the H8 thermal interrupt.
+ * As an example setting a value of 115 F here will cause the 
+ * interrupt to trigger when the cpu temperature reaches 115 F.
+ */
+static void
+h8_set_upper_therm_thold(int thold)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        /* write 0 to reinitialize interrupt */
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0x0;
+        buf[2] = 0x0;
+        h8_q_cmd(buf, 3, 1); 
+
+        /* Do it for real */
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0x0;
+        buf[2] = thold;
+        h8_q_cmd(buf, 3, 1); 
+}
+
+static void
+h8_get_upper_therm_thold(void)
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+
+        buf[0] = H8_CTL_UPPER_TEMP;
+        buf[1] = 0xff;
+        buf[2] = 0;
+        h8_q_cmd(buf, 3, 1); 
+}
+
+/*
+ * The external status word contains information on keyboard controller,
+ * power button, changes in external batt status, change in DC state,
+ * docking station, etc. General purpose querying use.
+ */
+int
+h8_get_ext_status(u_char stat_word[])
+{
+        u_char  buf[H8_MAX_CMD_SIZE];
+       unsigned long flags;
+
+        memset(buf, 0, H8_MAX_CMD_SIZE); 
+        buf[0] = H8_RD_EXT_STATUS;
+
+        h8_q_cmd(buf, 1, 2);
+
+       save_flags(flags); cli();
+
+        while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
+                sleep_on(&h8_sync_wait); 
+
+        restore_flags(flags);
+
+        h8_sync_channel &= ~H8_GET_EXT_STATUS;
+        stat_word[0] = xx.byte[0];
+        stat_word[1] = xx.byte[1];
+        xx.word = 0;
+
+        if(h8_debug & 0x8) 
+                printk("H8: curr ext status %x,  %x\n",
+                      stat_word[0], stat_word[1]);
+
+        return 0;
+}
+
+/*
+ * Thread attached to task 0 manages thermal/physcial state of Alphabook. 
+ * When a condition is detected by the interrupt service routine, the
+ * isr does a wakeup() on h8_monitor_wait.  The mask value is then
+ * screened for the appropriate action.
+ */
+
+int
+h8_monitor_thread(void * unused)
+{
+        u_char curr_temp[2];
+
+        /*
+         * Need a logic based safety valve here. During boot when this thread is
+         * started and the thermal interrupt is not yet initialized this logic 
+         * checks the temperature and acts accordingly.  When this path is acted
+         * upon system boot is painfully slow, however, the priority associated 
+         * with overheating is high enough to warrant this action.
+         */
+        h8_get_curr_temp(curr_temp);
+
+        printk("H8: Initial CPU temp: %d\n", curr_temp[0]);
+
+        if(curr_temp[0] >= h8_uthermal_threshold) {
+                h8_set_event_mask(H8_MANAGE_UTHERM);
+                h8_manage_therm();
+        } else {
+                /*
+                 * Arm the upper thermal limit of the H8 so that any temp in
+                 * excess will trigger the thermal control mechanism.
+                 */
+                h8_set_upper_therm_thold(h8_uthermal_threshold);
+        }
+
+        for(;;) {
+               sleep_on(&h8_monitor_wait);
+
+                if(h8_debug & 0x2)
+                        printk("h8_monitor_thread awakened, mask:%x\n",
+                                h8_event_mask);
+
+                if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
+                        h8_manage_therm();
+                }
+
+#if 0
+                if (h8_event_mask & H8_POWER_BUTTON) {
+                        h8_system_down();
+                }
+
+               /*
+                * If an external DC supply is removed or added make 
+                * appropriate cpu speed adjustments.
+                */
+                if (h8_event_mask & H8_MANAGE_BATTERY) {
+                          h8_run_level_3_manage(H8_RUN); 
+                          h8_clear_event_mask(H8_MANAGE_BATTERY);
+                }
+#endif
+        }
+}
+
+/* 
+ * Function implements the following policy. When the machine is booted
+ * the system is set to run at full clock speed. When the upper thermal
+ * threshold is reached as a result of full clock a damping factor is 
+ * applied to cool off the cpu.  The default value is one quarter clock
+ * (57 Mhz).  When as a result of this cooling a temperature lower by
+ * hmc_uthermal_window is reached, the machine is reset to a higher 
+ * speed, one half clock (115 Mhz).  One half clock is maintained until
+ * the upper thermal threshold is again reached restarting the cycle.
+ */
+
+int
+h8_manage_therm(void)
+{
+        u_char curr_temp[2];
+
+        if(h8_event_mask & H8_MANAGE_UTHERM) {
+               /* Upper thermal interrupt received, need to cool down. */
+               if(h8_debug & 0x10)
+                        printk("H8: Thermal threshold %d F reached\n",
+                              h8_uthermal_threshold);
+               h8_set_cpu_speed(h8_udamp); 
+                h8_clear_event_mask(H8_MANAGE_UTHERM);
+                h8_set_event_mask(H8_MANAGE_LTHERM);
+                /* Check again in 30 seconds for cpu temperature */
+                h8_start_monitor_timer(H8_TIMEOUT_INTERVAL); 
+        } else if (h8_event_mask & H8_MANAGE_LTHERM) {
+               /* See how cool the system has become as a result
+                  of the reduction in speed. */
+                h8_get_curr_temp(curr_temp);
+                last_temp = curr_temp[0];
+                if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
+               {
+                       /* System cooling has progressed to a point
+                          that the cpu may be speeded up. */
+                        h8_set_upper_therm_thold(h8_uthermal_threshold);
+                        h8_set_cpu_speed(h8_ldamp); /* adjustable */ 
+                        if(h8_debug & 0x10)
+                            printk("H8: CPU cool, applying cpu_divisor: %d \n",
+                                  h8_ldamp);
+                        h8_clear_event_mask(H8_MANAGE_LTHERM);
+                }
+               else /* Not cool enough yet, check again in 30 seconds. */
+                        h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
+        } else {
+                
+        }
+       return 0;
+}
+
+/* 
+ * Function conditions the value of global_rpb_counter before
+ * calling the primitive which causes the actual speed change.
+ */
+void
+h8_set_cpu_speed(int speed_divisor)
+{
+
+#ifdef NOT_YET
+/*
+ * global_rpb_counter is consumed by alpha_delay() in determining just
+ * how much time to delay.  It is necessary that the number of microseconds
+ * in DELAY(n) be kept consistent over a variety of cpu clock speeds.
+ * To that end global_rpb_counter is here adjusted.
+ */ 
+        
+        switch (speed_divisor) {
+                case 0:
+                        global_rpb_counter = rpb->rpb_counter * 2L;
+                        break;
+                case 1:
+                        global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
+                        break;
+                case 3:
+                        global_rpb_counter = rpb->rpb_counter / 2L;
+                        break;
+                case 4:
+                        global_rpb_counter = rpb->rpb_counter / 4L;
+                        break;
+                case 5:
+                        global_rpb_counter = rpb->rpb_counter / 8L;
+                        break;
+                /* 
+                 * This case most commonly needed for cpu_speed_divisor 
+                 * of 2 which is the value assigned by the firmware. 
+                 */
+                default:
+                        global_rpb_counter = rpb->rpb_counter;
+                break;
+        }
+#endif /* NOT_YET */
+
+        if(h8_debug & 0x8)
+                printk("H8: Setting CPU speed to %d MHz\n",
+                      speed_tab[speed_divisor]); 
+
+         /* Make the actual speed change */
+        lca_clock_fiddle(speed_divisor);
+}
+
+/*
+ * Gets value stored in rpb representing cpu clock speed and adjusts this
+ * value based on the current clock speed divisor.
+ */
+u_long
+h8_get_cpu_speed(void)
+{
+        u_long speed = 0;
+        u_long counter;
+
+#ifdef NOT_YET
+        counter = rpb->rpb_counter / 1000000L;
+
+        switch (alphabook_get_clock()) {
+                case 0:
+                        speed = counter * 2L;
+                        break;
+                case 1:
+                        speed = counter * 4L / 3L ;
+                        break;
+                case 2:
+                        speed = counter;
+                        break;
+                case 3:
+                        speed = counter / 2L;
+                        break;
+                case 4:
+                        speed = counter / 4L;
+                        break;
+                case 5:
+                        speed = counter / 8L;
+                        break;
+                default:
+                break;
+        }
+        if(h8_debug & 0x8)
+                printk("H8: CPU speed current setting: %d MHz\n", speed); 
+#endif  /* NOT_YET */
+       return speed;
+}
+
+static void
+h8_activate_monitor(unsigned long unused)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       h8_monitor_timer_active = 0;
+       restore_flags(flags);
+
+       wake_up(&h8_monitor_wait);
+}
+
+static void
+h8_start_monitor_timer(unsigned long secs)
+{
+       unsigned long flags;
+
+       if (h8_monitor_timer_active)
+           return;
+
+       save_flags(flags); cli();
+       h8_monitor_timer_active = 1;
+       restore_flags(flags);
+
+        init_timer(&h8_monitor_timer);
+        h8_monitor_timer.function = h8_activate_monitor;
+        h8_monitor_timer.expires = secs * HZ + jiffies;
+        add_timer(&h8_monitor_timer);
+}
+
+static void h8_set_event_mask(int mask)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       h8_event_mask |= mask;
+       restore_flags(flags);
+}
+
+static void h8_clear_event_mask(int mask)
+{
+       unsigned long flags;
+
+       save_flags(flags); cli();
+       h8_event_mask &= (~mask);
+       restore_flags(flags);
+}
diff --git a/drivers/char/h8.h b/drivers/char/h8.h
new file mode 100644 (file)
index 0000000..533c4ec
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ */
+
+#ifndef __H8_H__
+#define __H8_H__
+
+/*
+ * Register address and offsets
+ */
+#define H8_BASE_ADDR                   0x170            /* default */
+#define H8_IRQ                        9                /* default */
+#define H8_STATUS_REG_OFF              0x4              
+#define H8_CMD_REG_OFF                 0x4
+#define H8_DATA_REG_OFF                0x0
+
+
+/* H8 register bit definitions */
+/* status register */
+#define H8_OFULL                       0x1              /* output data register full */
+#define H8_IFULL                       0x2              /* input data register full */
+#define H8_CMD                         0x8              /* command / not data */
+
+#define H8_INTR                        0xfa
+#define H8_NACK                        0xfc
+#define H8_BYTE_LEVEL_ACK              0xfd
+#define H8_CMD_ACK                     0xfe
+#define H8_SYNC_BYTE                   0x99
+
+/*
+ * H8 command definitions
+ */
+/* System info commands */
+#define H8_SYNC                         0x0
+#define H8_RD_SN                        0x1
+#define H8_RD_ENET_ADDR                 0x2
+#define H8_RD_HW_VER                    0x3
+#define H8_RD_MIC_VER                   0x4
+#define H8_RD_MAX_TEMP                  0x5
+#define H8_RD_MIN_TEMP                  0x6
+#define H8_RD_CURR_TEMP                 0x7
+#define H8_RD_SYS_VARIENT               0x8
+#define H8_RD_PWR_ON_CYCLES             0x9
+#define H8_RD_PWR_ON_SECS               0xa
+#define H8_RD_RESET_STATUS              0xb
+#define H8_RD_PWR_DN_STATUS             0xc
+#define H8_RD_EVENT_STATUS              0xd
+#define H8_RD_ROM_CKSM                  0xe
+#define H8_RD_EXT_STATUS                0xf
+#define H8_RD_USER_CFG                  0x10
+#define H8_RD_INT_BATT_VOLT             0x11
+#define H8_RD_DC_INPUT_VOLT             0x12
+#define H8_RD_HORIZ_PTR_VOLT            0x13
+#define H8_RD_VERT_PTR_VOLT             0x14
+#define H8_RD_EEPROM_STATUS             0x15
+#define H8_RD_ERR_STATUS                0x16
+#define H8_RD_NEW_BUSY_SPEED            0x17
+#define H8_RD_CONFIG_INTERFACE          0x18
+#define H8_RD_INT_BATT_STATUS           0x19
+#define H8_RD_EXT_BATT_STATUS           0x1a
+#define H8_RD_PWR_UP_STATUS             0x1b
+#define H8_RD_EVENT_STATUS_MASK         0x56
+
+/* Read/write/modify commands */
+#define H8_CTL_EMU_BITPORT              0x32
+#define H8_DEVICE_CONTROL               0x21
+#define H8_CTL_TFT_BRT_DC               0x22
+#define H8_CTL_WATCHDOG                 0x23
+#define H8_CTL_MIC_PROT                 0x24
+#define H8_CTL_INT_BATT_CHG             0x25
+#define H8_CTL_EXT_BATT_CHG             0x26
+#define H8_CTL_MARK_SPACE               0x27
+#define H8_CTL_MOUSE_SENSITIVITY        0x28
+#define H8_CTL_DIAG_MODE                0x29
+#define H8_CTL_IDLE_AND_BUSY_SPDS       0x2a
+#define H8_CTL_TFT_BRT_BATT             0x2b
+#define H8_CTL_UPPER_TEMP               0x2c
+#define H8_CTL_LOWER_TEMP               0x2d
+#define H8_CTL_TEMP_CUTOUT              0x2e
+#define H8_CTL_WAKEUP                   0x2f
+#define H8_CTL_CHG_THRESHOLD            0x30
+#define H8_CTL_TURBO_MODE               0x31
+#define H8_SET_DIAG_STATUS              0x40
+#define H8_SOFTWARE_RESET               0x41
+#define H8_RECAL_PTR                    0x42
+#define H8_SET_INT_BATT_PERCENT         0x43
+#define H8_WRT_CFG_INTERFACE_REG        0x45
+#define H8_WRT_EVENT_STATUS_MASK        0x57
+#define H8_ENTER_POST_MODE              0x46
+#define H8_EXIT_POST_MODE               0x47
+
+/* Block transfer commands */
+#define H8_RD_EEPROM                    0x50
+#define H8_WRT_EEPROM                   0x51
+#define H8_WRT_TO_STATUS_DISP           0x52
+#define H8_DEFINE_SPC_CHAR              0x53
+/* Generic commands */
+#define H8_DEFINE_TABLE_STRING_ENTRY    0x60
+
+/* Battery control commands */
+#define H8_PERFORM_EMU_CMD              0x70
+#define H8_EMU_RD_REG                   0x71
+#define H8_EMU_WRT_REG                  0x72
+#define H8_EMU_RD_RAM                   0x73
+#define H8_EMU_WRT_RAM                  0x74
+#define H8_BQ_RD_REG                    0x75
+#define H8_BQ_WRT_REG                   0x76
+
+/* System admin commands */
+#define H8_PWR_OFF                      0x80
+
+/*
+ * H8 command related definitions
+ */
+
+/* device control argument bits */
+#define H8_ENAB_EXTSMI                  0x1
+#define H8_DISAB_IRQ                    0x2
+#define H8_ENAB_FLASH_WRT               0x4
+#define H8_ENAB_THERM                   0x8
+#define H8_ENAB_INT_PTR                 0x10
+#define H8_ENAB_LOW_SPD_IND             0x20
+#define H8_ENAB_EXT_PTR                 0x40
+#define H8_DISAB_PWR_OFF_SW             0x80
+#define H8_POWER_OFF                   0x80
+
+/* H8 read event status bits */
+#define H8_DC_CHANGE                    0x1
+#define H8_INT_BATT_LOW                 0x2
+#define H8_INT_BATT_CHARGE_THRESHOLD    0x4
+#define H8_INT_BATT_CHARGE_STATE        0x8
+#define H8_INT_BATT_STATUS              0x10
+#define H8_EXT_BATT_CHARGE_STATE        0x20
+#define H8_EXT_BATT_LOW                 0x40
+#define H8_EXT_BATT_STATUS              0x80
+#define H8_THERMAL_THRESHOLD            0x100
+#define H8_WATCHDOG                     0x200
+#define H8_DOCKING_STATION_STATUS       0x400
+#define H8_EXT_MOUSE_OR_CASE_SWITCH     0x800
+#define H8_KEYBOARD                     0x1000
+#define H8_BATT_CHANGE_OVER             0x2000
+#define H8_POWER_BUTTON                 0x4000
+#define H8_SHUTDOWN                     0x8000
+
+/* H8 control idle and busy speeds */
+#define H8_SPEED_LOW                    0x1
+#define H8_SPEED_MED                    0x2
+#define H8_SPEED_HI                     0x3
+#define H8_SPEED_LOCKED                 0x80
+
+#define H8_MAX_CMD_SIZE                 18      
+#define H8_Q_ALLOC_AMOUNT               10      
+
+/* H8 state field values */
+#define H8_IDLE                         1
+#define H8_XMIT                         2
+#define H8_RCV                          3
+#define H8_RESYNC                       4
+#define H8_INTR_MODE                    5
+
+/* Mask values for control functions */
+#define UTH_HYSTERESIS                  5
+#define DEFAULT_UTHERMAL_THRESHOLD      115
+#define H8_TIMEOUT_INTERVAL            30
+#define H8_RUN                          4
+
+#define H8_GET_MAX_TEMP                 0x1
+#define H8_GET_CURR_TEMP                0x2
+#define H8_GET_UPPR_THRMAL_THOLD        0x4
+#define H8_GET_ETHERNET_ADDR            0x8
+#define H8_SYNC_OP                      0x10 
+#define H8_SET_UPPR_THRMAL_THOLD        0x20
+#define H8_GET_INT_BATT_STAT            0x40
+#define H8_GET_CPU_SPD                  0x80
+#define H8_MANAGE_UTHERM                0x100 
+#define H8_MANAGE_LTHERM                0x200 
+#define H8_HALT                         0x400 
+#define H8_CRASH                        0x800 
+#define H8_GET_EXT_STATUS               0x10000
+#define H8_MANAGE_QUIET                 0x20000
+#define H8_MANAGE_SPEEDUP               0x40000
+#define H8_MANAGE_BATTERY               0x80000
+#define H8_SYSTEM_DELAY_TEST            0x100000
+#define H8_POWER_SWITCH_TEST            0x200000
+
+/* cpu speeds and clock divisor values */
+#define MHZ_14                           5
+#define MHZ_28                           4
+#define MHZ_57                           3
+#define MHZ_115                          2
+#define MHZ_230                          0 
+
+/*
+ * H8 data
+ */
+struct h8_data {
+        u_int           ser_num;
+        u_char          ether_add[6];
+        u_short         hw_ver;
+        u_short         mic_ver;
+        u_short         max_tmp;
+        u_short         min_tmp;
+        u_short         cur_tmp;
+        u_int           sys_var;
+        u_int           pow_on;
+        u_int           pow_on_secs;
+        u_char          reset_status;
+        u_char          pwr_dn_status;
+        u_short         event_status;
+        u_short         rom_cksm;
+        u_short         ext_status;
+        u_short         u_cfg;
+        u_char          ibatt_volt;
+        u_char          dc_volt;
+        u_char          ptr_horiz;
+        u_char          ptr_vert;
+        u_char          eeprom_status;
+        u_char          error_status;
+        u_char          new_busy_speed;
+        u_char          cfg_interface;
+        u_short         int_batt_status;
+        u_short         ext_batt_status;
+        u_char          pow_up_status;
+        u_char          event_status_mask;
+};
+
+
+/*
+ * H8 command buffers
+ */
+typedef struct h8_cmd_q {
+        DLNODE(struct h8_cmd_q) link; /* double linked list */
+        int             ncmd;           /* number of bytes in command */
+        int             nrsp;           /* number of bytes in response */
+        int             cnt;            /* number of bytes sent/received */
+        int             nacks;          /* number of byte level acks */
+        u_char          cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */
+        u_char          rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */
+} h8_cmd_q_t;
+
+typedef struct __queue_head {
+       DLNODE(struct h8_cmd_q) link;
+} queue_head_t;
+
+union   intr_buf {
+        u_char  byte[2];
+        u_int   word;
+};
+
+#endif /* __H8_H_ */
index f69b8ea28e4e2f92548f52f40cdb31b8f5f5abf6..79387fbd1badbf2800b09f8b15e2ce28d624c60d 100644 (file)
@@ -400,7 +400,7 @@ int chr_dev_init(void)
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_PCWATCHDOG) || \
+    defined (CONFIG_PCWATCHDOG) || defined (CONFIG_H8) || \
     defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
        misc_init();
 #endif
index dc91564f164b0788858ed734e2273d7608a632db..7d94147f9ac8cbb35bc0e1f7fe995d9d0e97a594 100644 (file)
@@ -232,6 +232,9 @@ int misc_init(void)
 #ifdef CONFIG_APM
        apm_bios_init();
 #endif
+#ifdef CONFIG_H8
+       h8_init();
+#endif
 #ifdef CONFIG_RTC
        rtc_init();
 #endif
index 4a6ab6f9b8f2ad07d41ec9fa4dca52f893e750f0..7964348432a04a5ddef64b1f8cca40f5e9bb96ac 100644 (file)
  *     Based on other minimal char device drivers, like Alan's
  *     watchdog, Ted's random, etc. etc.
  *
+ *     1.07    Paul Gortmaker.
+ *     1.08    Miquel van Smoorenburg: disallow certain things on the
+ *             DEC Alpha as the CMOS clock is also used for other things.
+ *     1.09    Nikita Schmidt: epoch support and some Alpha cleanup.
+ *
  */
 
-#define RTC_VERSION            "1.07"
+#define RTC_VERSION            "1.09"
 
 #define RTC_IRQ        8       /* Can't see this changing soon.        */
 #define RTC_IO_EXTENT  0x10    /* Only really two ports, but...        */
@@ -98,6 +103,13 @@ unsigned char rtc_status = 0;               /* bitmapped status byte.       */
 unsigned long rtc_freq = 0;            /* Current periodic IRQ rate    */
 unsigned long rtc_irq_data = 0;                /* our output to the world      */
 
+/*
+ *     If this driver ever becomes modularised, it will be really nice
+ *     to make the epoch retain its value across module reload...
+ */
+
+static unsigned long epoch = 1900;     /* year corresponding to 0x00   */
+
 unsigned char days_in_mo[] = 
                {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
@@ -106,8 +118,12 @@ unsigned char days_in_mo[] =
  *     so that there is no possibility of conflicting with the
  *     set_rtc_mmss() call that happens during some timer interrupts.
  *     (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ *
+ *     On Alpha we won't get any interrupts anyway, as they all end up
+ *     in the system timer code.
  */
 
+#ifndef __alpha__
 static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        /*
@@ -128,9 +144,11 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                add_timer(&rtc_irq_timer);
        }
 }
+#endif
 
 /*
  *     Now all the various file operations that we export.
+ *     They are all useless on Alpha...  *sigh*.
  */
 
 static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
@@ -141,6 +159,9 @@ static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
 
 static int rtc_read(struct inode *inode, struct file *file, char *buf, int count)
 {
+#ifdef __alpha__
+       return -EIO;
+#else
        struct wait_queue wait = { current, NULL };
        int retval;
        
@@ -182,6 +203,7 @@ static int rtc_read(struct inode *inode, struct file *file, char *buf, int count
        remove_wait_queue(&rtc_wait, &wait);
 
        return retval;
+#endif
 }
 
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -191,6 +213,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        unsigned long flags;
 
        switch (cmd) {
+#ifndef __alpha__
                case RTC_AIE_OFF:       /* Mask alarm int. enab. bit    */
                {
                        mask_rtc_irq_bit(RTC_AIE);
@@ -238,6 +261,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        set_rtc_irq_bit(RTC_UIE);
                        return 0;
                }
+#endif
                case RTC_ALM_READ:      /* Read the present alarm time */
                {
                        /*
@@ -342,7 +366,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        min = rtc_tm.tm_min;
                        sec = rtc_tm.tm_sec;
 
-                       if ((yrs < 1970) || (yrs > 2069))
+                       if (yrs < 1970)
                                return -EINVAL;
 
                        leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
@@ -356,16 +380,19 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        if ((hrs >= 24) || (min >= 60) || (sec >= 60))
                                return -EINVAL;
 
-                       if (yrs >= 2000)
-                               yrs -= 2000;    /* RTC (0, 1, ... 69) */
-                       else
-                               yrs -= 1900;    /* RTC (70, 71, ... 99) */
+                       if ((yrs -= epoch) > 255)    /* They are unsigned */
+                               return -EINVAL;
 
                        save_flags(flags);
                        cli();
-                       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
-                                                       RTC_ALWAYS_BCD)
-                       {
+                       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+                               if (yrs > 169) {
+                                       restore_flags(flags);
+                                       return -EINVAL;
+                               }
+                               if (yrs >= 100)
+                                       yrs -= 100;
+
                                BIN_TO_BCD(sec);
                                BIN_TO_BCD(min);
                                BIN_TO_BCD(hrs);
@@ -403,6 +430,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        memcpy_tofs((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
                        return 0;
                }
+#ifndef __alpha__
                case RTC_IRQP_SET:      /* Set periodic IRQ rate.       */
                {
                        int tmp = 0;
@@ -439,6 +467,34 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        restore_flags(flags);
                        return 0;
                }
+#endif
+#ifdef __alpha__
+               case RTC_EPOCH_READ:    /* Read the epoch.      */
+               {
+                       int retval;
+
+                       retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
+                       if (retval != 0)
+                               return retval;
+
+                       memcpy_tofs((unsigned long*)arg, &epoch, sizeof(unsigned long));
+                       return 0;
+               }
+               case RTC_EPOCH_SET:     /* Set the epoch.       */
+               {
+                       /* 
+                        * There were no RTC clocks before 1900.
+                        */
+                       if (arg < 1900)
+                               return -EINVAL;
+
+                       if (!suser())
+                               return -EACCES;
+
+                       epoch = arg;
+                       return 0;
+               }
+#endif
                default:
                        return -EINVAL;
        }
@@ -448,16 +504,18 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  *     We enforce only one user at a time here with the open/close.
  *     Also clear the previous interrupt data on an open, and clean
  *     up things on a close.
+ *     On Alpha we just open, for we don't mess with interrups anyway.
  */
 
 static int rtc_open(struct inode *inode, struct file *file)
 {
-
+#ifndef __alpha__
        if(rtc_status & RTC_IS_OPEN)
                return -EBUSY;
 
        rtc_status |= RTC_IS_OPEN;
        rtc_irq_data = 0;
+#endif
        return 0;
 }
 
@@ -469,6 +527,7 @@ static void rtc_release(struct inode *inode, struct file *file)
         * in use, and clear the data.
         */
 
+#ifndef __alpha__
        unsigned char tmp;
        unsigned long flags;
 
@@ -489,8 +548,10 @@ static void rtc_release(struct inode *inode, struct file *file)
 
        rtc_irq_data = 0;
        rtc_status &= ~RTC_IS_OPEN;
+#endif
 }
 
+#ifndef __alpha__
 static int rtc_select(struct inode *inode, struct file *file,
                        int sel_type, select_table *wait)
 {
@@ -501,6 +562,7 @@ static int rtc_select(struct inode *inode, struct file *file,
        }
        return 0;
 }
+#endif
 
 /*
  *     The various file operations we support.
@@ -511,7 +573,11 @@ static struct file_operations rtc_fops = {
        rtc_read,
        NULL,           /* No write */
        NULL,           /* No readdir */
+#ifdef __alpha__
+       NULL,           /* No select on Alpha */
+#else
        rtc_select,
+#endif
        rtc_ioctl,
        NULL,           /* No mmap */
        rtc_open,
@@ -528,17 +594,54 @@ static struct miscdevice rtc_dev=
 int rtc_init(void)
 {
        unsigned long flags;
+#ifdef __alpha__
+       unsigned int year, ctrl;
+       unsigned long uip_watchdog;
+       char *guess = NULL;
+#endif
 
        printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+#ifndef __alpha__
        if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
        {
                /* Yeah right, seeing as irq 8 doesn't even hit the bus. */
                printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
                return -EIO;
        }
+#endif
        misc_register(&rtc_dev);
        /* Check region? Naaah! Just snarf it up. */
        request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+#ifdef __alpha__
+       rtc_freq = HZ;
+
+       /* Each operating system on an Alpha uses its own epoch.
+          Let's try to guess which one we are using now. */
+
+       uip_watchdog = jiffies;
+       if (rtc_is_updating() != 0)
+               while (jiffies - uip_watchdog < 2*HZ/100)
+                       barrier();
+
+       save_flags(flags);
+       cli();
+       year = CMOS_READ(RTC_YEAR);
+       ctrl = CMOS_READ(RTC_CONTROL);
+       restore_flags(flags);
+
+       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+               BCD_TO_BIN(year);       /* This should never happen... */
+
+       if (year > 10 && year < 44) {
+               epoch = 1980;
+               guess = "ARC console";
+       } else if (year < 96) {
+               epoch = 1952;
+               guess = "Digital UNIX";
+       }
+       if (guess)
+               printk("rtc: %s epoch (%ld) detected\n", guess, epoch);
+#else
        init_timer(&rtc_irq_timer);
        rtc_irq_timer.function = rtc_dropped_irq;
        rtc_wait = NULL;
@@ -548,6 +651,7 @@ int rtc_init(void)
        CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
        restore_flags(flags);
        rtc_freq = 1024;
+#endif
        return 0;
 }
 
@@ -563,6 +667,7 @@ int rtc_init(void)
  *     for something that requires a steady > 1KHz signal anyways.)
  */
 
+#ifndef __alpha__
 void rtc_dropped_irq(unsigned long data)
 {
        unsigned long flags;
@@ -579,6 +684,7 @@ void rtc_dropped_irq(unsigned long data)
        rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);     /* restart */
        restore_flags(flags);
 }
+#endif
 
 /*
  *     Info exported via "/proc/rtc".
@@ -723,7 +829,7 @@ void get_rtc_time(struct rtc_time *rtc_tm)
         * Account for differences between how the RTC uses the values
         * and how they are defined in a struct rtc_time;
         */
-       if (rtc_tm->tm_year <= 69)
+       if ((rtc_tm->tm_year += epoch - 1900) <= 69)
                rtc_tm->tm_year += 100;
 
        rtc_tm->tm_mon--;
@@ -763,6 +869,8 @@ void get_rtc_alm_time(struct rtc_time *alm_tm)
  * We also clear out any old irq data after an ioctl() that
  * meddles with the interrupt enable/disable bits.
  */
+
+#ifndef __alpha__
 void mask_rtc_irq_bit(unsigned char bit)
 {
        unsigned char val;
@@ -792,4 +900,4 @@ void set_rtc_irq_bit(unsigned char bit)
        rtc_irq_data = 0;
        restore_flags(flags);
 }
-
+#endif
index 7310f63083bd0015aced8fd2def5df49ae594d6b..41e4c11d0bff259be2905df346c81c89d7de8c4e 100644 (file)
@@ -61,10 +61,15 @@ extern void putconsxy(int currcons, char *p);
 /* how to access screen memory */
 
 #include <linux/config.h>
+#include <asm/io.h> 
 
 #ifdef CONFIG_TGA_CONSOLE
 
-extern int tga_blitc(unsigned int, unsigned long);
+# ifdef CONFIG_VGA_CONSOLE
+extern int curr_cons;
+extern const struct console_desc cons_devices[];
+# endif
+
 extern unsigned long video_mem_term;
 
 /*
@@ -83,24 +88,57 @@ extern unsigned long video_mem_term;
  *
  * NOTE also: there's only *TWO* operations: to put/get a character/attribute.
  *  All the others needed by VGA support go away, as Not Applicable for TGA.
+ *
+ * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
+ *  indicates a VC's backing store; otherwise, it's a bus memory address, for
+ *  the VGA's screen memory, so we do the Alpha "swizzle"... :-)
  */
+#define IS_VIDEO_MEMORY(a) \
+        ((unsigned long)(a) - video_mem_base < video_mem_term - video_mem_base)
+
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
+        if ((long) addr < 0) {
        /*
-        * always deposit the char/attr, then see if it was to "screen" mem.
+                * always deposit the char/attr, then see if it was to
+                * "screen" mem.
         * if so, then render the char/attr onto the real screen.
         */
         *addr = val;
-        if ((unsigned long)addr < video_mem_term &&
-           (unsigned long)addr >= video_mem_base) {
-                tga_blitc(val, (unsigned long) addr);
-        }
+
+                /*
+                * TGA might need the char blitted to the screen,
+                * but check first, we could be running on a VGA.
+                */
+                if (con_blitc && IS_VIDEO_MEMORY(addr))
+                       con_blitc(val, (unsigned long) addr);
+        } else
+                writew(val, (unsigned long) addr);
 }
 
 static inline unsigned short scr_readw(unsigned short * addr)
 {
+       if ((long) addr < 0)
        return *addr;
+       return readw((unsigned long) addr);
+}
+
+/* scr_writeb and scr_readb are not expected to be called with a TGA */
+static inline void scr_writeb(unsigned char val, unsigned char * addr)
+{
+       if ((long) addr < 0)
+               *addr = val;
+       else
+               writeb(val, (unsigned long) addr);
+}
+
+static inline unsigned char scr_readb(unsigned char * addr)
+{
+       if ((long) addr < 0)
+               return *addr;
+       return readb((unsigned long) addr);
 }
+
 #else /* CONFIG_TGA_CONSOLE */
 
 /*
@@ -110,8 +148,6 @@ static inline unsigned short scr_readw(unsigned short * addr)
 
 #ifdef __alpha__
 
-#include <asm/io.h> 
-
 /*
  * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
  *  indicates a VC's backing store; otherwise, it's a bus memory address, for
index a992029641a4b36d4669190f5f114a5d827a4965..dc6ebb67c7d4ced5e594d80c2a466aa146d48f25 100644 (file)
@@ -201,7 +201,7 @@ void tga_init_video(void);
 void tga_clear_screen(void);
 
 void
-set_palette (void)
+tga_set_palette (void)
 {
   int i, j;
 
@@ -233,7 +233,7 @@ set_palette (void)
 }
 
 void
-__set_origin(unsigned short offset)
+tga_set_origin(unsigned short offset)
 {
   /*
    * should not be called, but if so, do nothing...
@@ -244,7 +244,7 @@ __set_origin(unsigned short offset)
  * Hide the cursor from view, during blanking, usually...
  */
 void
-hide_cursor(void)
+tga_hide_cursor(void)
 {
        unsigned long flags;
        save_flags(flags); cli();
@@ -259,7 +259,7 @@ hide_cursor(void)
 }
 
 void
-set_cursor(int currcons)
+tga_set_cursor(int currcons)
 {
   unsigned int idx, xt, yt, row, col;
   unsigned long flags;
@@ -267,8 +267,10 @@ set_cursor(int currcons)
   if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
     return;
 
+#if 0
   if (__real_origin != __origin)
-    __set_origin(__real_origin);
+    tga_set_origin(__real_origin);
+#endif
 
   save_flags(flags); cli();
 
@@ -300,12 +302,12 @@ set_cursor(int currcons)
     }
 
   } else
-    hide_cursor();
+    tga_hide_cursor();
   restore_flags(flags);
 }
 
 unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+tga_init(unsigned long kmem_start, const char **display_desc)
 {
         can_do_color = 1;
 
@@ -328,7 +330,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc)
  * the VGA version of set_scrmem() has some direct VGA references.
  */
 void
-get_scrmem(int currcons)
+tga_get_scrmem(int currcons)
 {
        memcpyw((unsigned short *)vc_scrbuf[currcons],
                (unsigned short *)origin, video_screen_size);
@@ -338,7 +340,7 @@ get_scrmem(int currcons)
 }
 
 void
-set_scrmem(int currcons, long offset)
+tga_set_scrmem(int currcons, long offset)
 {
        if (video_mem_term - video_mem_base < offset + video_screen_size)
          offset = 0;   /* strange ... */
@@ -357,7 +359,7 @@ set_scrmem(int currcons, long offset)
  * for now, we will use/allow *only* our built-in font...
  */
 int
-set_get_font(char * arg, int set, int ch512)
+tga_set_get_font(char * arg, int set, int ch512)
 {
        return -EINVAL;
 }
@@ -371,7 +373,7 @@ set_get_font(char * arg, int set, int ch512)
  * for now, we only support the built-in font...
  */
 int
-con_adjust_height(unsigned long fontheight)
+tga_adjust_height(unsigned long fontheight)
 {
        return -EINVAL;
 }
@@ -386,7 +388,7 @@ con_adjust_height(unsigned long fontheight)
  */
 
 int
-set_get_cmap(unsigned char * arg, int set) {
+tga_set_get_cmap(unsigned char * arg, int set) {
        int i;
 
        i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
@@ -424,16 +426,16 @@ set_get_cmap(unsigned char * arg, int set) {
  * dummy routines for the VESA blanking code, which is VGA only,
  * so we don't have to carry that stuff around for the TGA...
  */
-void vesa_powerdown(void)
+void tga_vesa_powerdown(void)
 {
 }
-void vesa_blank(void)
+void tga_vesa_blank(void)
 {
 }
-void vesa_unblank(void)
+void tga_vesa_unblank(void)
 {
 }
-void set_vesa_blanking(const unsigned long arg)
+void tga_set_vesa_blanking(const unsigned long arg)
 {
 }
 
@@ -441,9 +443,13 @@ void set_vesa_blanking(const unsigned long arg)
  * video init code, called from within the PCI bus probing code;
  * when TGA console is configured, at the end of the probing code,
  * we call here to look for a TGA device, and proceed...
+ *
+ * note that this code MUST be called BEFORE console_init/con_init,
+ * so that either VGA or TGA are set up but not both. we had to move
+ * console_init to after pci_init in start_kernel to assure this.
  */
 void
-tga_console_init(void)
+tga_console_find(void)
 {
        unsigned char pci_bus, pci_devfn;
        int status;
@@ -477,10 +483,11 @@ tga_console_init(void)
        tga_init_video();
        tga_clear_screen();
 
-       /*
-        * FINALLY, we can register TGA as console (whew!)
-        */
-       register_console(console_print);
+#ifdef CONFIG_VGA_CONSOLE
+       /* if both are configured, we are using a dispatch table,
+          so we must set the index */
+       curr_cons = 1;
+#endif
 }
 
 unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
index 81b3122609f6f4a6844af67c4c991af83da9b331..90051a4396da8f3aba0f90229361ff53e2b589e9 100644 (file)
@@ -1163,6 +1163,10 @@ static void release_dev(struct file * filp)
                }
        }
 #endif
+
+       if (tty->driver.close)
+               tty->driver.close(tty, filp);
+
        /*
         * Sanity check: if tty->count is going to zero, there shouldn't be
         * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1220,9 +1224,6 @@ static void release_dev(struct file * filp)
         * block, so it's safe to proceed with closing.
         */
 
-       if (tty->driver.close)
-               tty->driver.close(tty, filp);
-
        if (pty_master) {
                if (--o_tty->count < 0) {
                        printk("release_dev: bad pty slave count (%d) for %s\n",
index 7c9013390939b7ab15b18f866dd3d86a820d96ee..52f0fae1814443582417076735476076f2974fdd 100644 (file)
@@ -689,13 +689,13 @@ el3_rx(struct device *dev)
                                lp->stats.rx_packets++;
                                continue;
                        } else if (el3_debug)
-                               printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+                               printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n",
                                           dev->name, pkt_len);
                }
                lp->stats.rx_dropped++;
                outw(RxDiscard, ioaddr + EL3_CMD);
                while (inw(ioaddr + EL3_STATUS) & 0x1000)
-                       printk("        Waiting for 3c509 to discard packet, status %x.\n",
+                       printk(KERN_DEBUG "        Waiting for 3c509 to discard packet, status %x.\n",
                                   inw(ioaddr + EL3_STATUS) );
        }
 
index d8fa645abda70c2b3d13801e3ed355f809dee166..8f98bf9184dc3d42aaf6b46ed0bc9a3ab21f1346 100644 (file)
@@ -15,7 +15,7 @@
 */
 
 static char *version =
-"3c59x.c:v0.99 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -35,7 +35,7 @@ static int vortex_debug = 1;
 
 /* Some values here only for performance evaluation and path-coverage
    debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 
 /* Enable the automatic media selection code -- usually set. */
 #define AUTOMEDIA 1
@@ -44,7 +44,9 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
    programmed-I/O for Vortex cards.  Full-bus-master transfers are always
    enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
    the feature may be turned on using 'options'. */
+#if YOU_ARE_BRAVER_THAN_ME
 #define VORTEX_BUS_MASTER
+#endif
 
 /* A few values that may be tweaked. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -105,6 +107,11 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0;
 #define RUN_AT(x) (jiffies + (x))
 #define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
 #endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else  /* Grrr, unneeded incompatible change. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+#endif
 
 #ifdef SA_SHIRQ
 #define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
@@ -329,7 +336,7 @@ union wn3_config {
        struct w3_config_fields {
                unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
                int pad8:8;
-               unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+               unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
                int pad24:7;
        } u;
 };
@@ -366,6 +373,8 @@ struct boom_rx_desc {
 enum rx_desc_status {
        RxDComplete=0x00008000, RxDError=0x4000,
        /* See boomerang_rx() for actual error bits */
+       IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
+       IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
 };
 
 struct boom_tx_desc {
@@ -378,6 +387,7 @@ struct boom_tx_desc {
 /* Values for the Tx status entry. */
 enum tx_desc_status {
        CRCDisable=0x2000, TxDComplete=0x8000,
+       AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
        TxIntrUploaded=0x80000000,              /* IRQ when in FIFO, but maybe not sent. */
 };
 
@@ -413,6 +423,7 @@ struct vortex_private {
          full_duplex:1, autoselect:1,
          bus_master:1,                         /* Vortex can only do a fragment bus-m. */
          full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
+         hw_csums:1,                           /* Has hardware checksums. */
       tx_full:1;
        u16 status_enable;
        u16 available_media;                            /* From Wn3_Options. */
@@ -426,7 +437,7 @@ struct vortex_private {
  */
 enum xcvr_types {
        XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
-       XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8,
+       XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
 };
 
 static struct media_table {
@@ -444,6 +455,8 @@ static struct media_table {
   { "100baseFX", Media_Lnk, 0x04, XCVR_MII,            (14*HZ)/10},
   { "MII",              0,                     0x41, XCVR_10baseT, 3*HZ },
   { "undefined", 0,                    0x01, XCVR_10baseT, 10000},
+  { "Autonegotiate", 0,                0x41, XCVR_10baseT, 3*HZ},
+  { "MII-External",     0,             0x41, XCVR_10baseT, 3*HZ },
   { "Default",  0,                     0xFF, XCVR_10baseT, 10000},
 };
 
@@ -612,9 +625,10 @@ static int vortex_scan(struct device *dev)
                unsigned char pci_bus, pci_device_fn;
 
                for (;pci_index < 0xff; pci_index++) {
-                       u8 pci_irq_line, pci_latency;
+                       u8 pci_latency;
                        u16 pci_command, new_command, vendor, device;
-                       u32 pci_ioaddr;
+                       int irq;
+                       long ioaddr;
 
                        if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
                                                                        pci_index, &pci_bus, &pci_device_fn)
@@ -624,19 +638,39 @@ static int vortex_scan(struct device *dev)
                                                                         PCI_VENDOR_ID, &vendor);
                        pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                         PCI_DEVICE_ID, &device);
-                       pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                                                        PCI_INTERRUPT_LINE, &pci_irq_line);
-                       pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
                        pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                         PCI_COMMAND, &pci_command);
+                       {
+#if LINUX_VERSION_CODE >= 0x20155
+                               struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+                               ioaddr = pdev->base_address[0];
+                               irq = pdev->irq;
+#else
+                               u32 pci_ioaddr;
+                               u8 pci_irq_line;
+                               pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                                                                PCI_INTERRUPT_LINE, &pci_irq_line);
+                               pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                                                                 PCI_BASE_ADDRESS_0, &pci_ioaddr);
+                               ioaddr = pci_ioaddr;
+                               irq = pci_irq_line;
+#endif
+                       }
                        /* Remove I/O space marker in bit 0. */
-                       pci_ioaddr &= ~3;
+                       ioaddr &= ~3;
 
                        if (vendor != TCOM_VENDOR_ID)
                                continue;
 
-                       if (check_region(pci_ioaddr, VORTEX_TOTAL_SIZE))
+                       if (ioaddr == 0) {
+                               printk(KERN_WARNING "  A 3Com network adapter has been found, "
+                                          "however it has not been assigned an I/O address.\n"
+                                          "  You may need to power-cycle the machine for this "
+                                          "device to work!\n");
+                               continue;
+                       }
+
+                       if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
                                continue;
 
                        /* Activate the card. */
@@ -649,7 +683,7 @@ static int vortex_scan(struct device *dev)
                                                                                  PCI_COMMAND, new_command);
                        }
 
-                       dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line,
+                       dev = vortex_found_device(dev, ioaddr, irq,
                                                                          device, dev && dev->mem_start
                                                                          ? dev->mem_start : options[cards_found],
                                                                          cards_found);
@@ -886,6 +920,7 @@ static int vortex_probe1(struct device *dev)
                           config.u.ram_width ? "word" : "byte",
                           ram_split[config.u.ram_split],
                           config.u.autoselect ? "autoselect/" : "",
+                          config.u.xcvr ? "NWay Autonegotiation" :
                           media_tbl[config.u.xcvr].name);
                vp->default_media = config.u.xcvr;
                vp->autoselect = config.u.autoselect;
@@ -905,7 +940,7 @@ static int vortex_probe1(struct device *dev)
                        int mii_status;
                        mdio_sync(ioaddr, 32);
                        mii_status = mdio_read(ioaddr, phy, 1);
-                       if (mii_status != 0xffff) {
+                       if (mii_status  &&  mii_status != 0xffff) {
                                vp->phys[phy_idx++] = phy;
                                printk(KERN_INFO "  MII transceiver found at address %d, status %4x.\n",
                                           phy, mii_status);
@@ -996,8 +1031,6 @@ vortex_open(struct device *dev)
 
        if (dev->if_port == XCVR_MII) {
                int mii_reg1, mii_reg5;
-               /* We cheat here: we know that we are using the 83840 transceiver
-                  which summarizes the FD status in an extended register. */
                EL3WINDOW(4);
                /* Read BMSR (reg1) only to clear old status. */
                mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
@@ -1024,13 +1057,13 @@ vortex_open(struct device *dev)
        }
 
        outw(TxReset, ioaddr + EL3_CMD);
-       for (i = 20; i >= 0 ; i--)
+       for (i = 2000; i >= 0 ; i--)
                if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                        break;
 
        outw(RxReset, ioaddr + EL3_CMD);
        /* Wait a few ticks for the RxReset command to complete. */
-       for (i = 20; i >= 0 ; i--)
+       for (i = 2000; i >= 0 ; i--)
                if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                        break;
 
@@ -1038,8 +1071,7 @@ vortex_open(struct device *dev)
 
 #ifdef SA_SHIRQ
        /* Use the now-standard shared IRQ implementation. */
-       if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
-                                       vp->product_name, dev)) {
+       if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
                return -EAGAIN;
        }
 #else
@@ -1263,7 +1295,7 @@ static void vortex_tx_timeout(struct device *dev)
                vortex_interrupt IRQ(dev->irq, dev, 0);
        }
        outw(TxReset, ioaddr + EL3_CMD);
-       for (j = 20; j >= 0 ; j--)
+       for (j = 200; j >= 0 ; j--)
                if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                        break;
 
@@ -1292,6 +1324,10 @@ static void vortex_tx_timeout(struct device *dev)
                if (vp->cur_tx - vp->dirty_tx > 0  &&  inl(ioaddr + DownListPtr) == 0)
                        outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
                                 ioaddr + DownListPtr);
+               if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
+                       vp->tx_full = 0;
+                       clear_bit(0, (void*)&dev->tbusy);
+               }
                outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
                outw(DownUnstall, ioaddr + EL3_CMD);
        } else
@@ -1315,6 +1351,7 @@ vortex_error(struct device *dev, int status)
        struct vortex_private *vp = (struct vortex_private *)dev->priv;
        int ioaddr = dev->base_addr;
        int do_tx_reset = 0;
+       int i;
 
        if (status & TxComplete) {                      /* Really "TxError" for us. */
                unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1363,9 +1400,8 @@ vortex_error(struct device *dev, int status)
                                   dev->name, fifo_diag);
                /* Adapter failure requires Tx/Rx reset and reinit. */
                if (vp->full_bus_master_tx) {
-                       int j;
                        outw(TotalReset | 0xff, ioaddr + EL3_CMD);
-                       for (j = 200; j >= 0 ; j--)
+                       for (i = 2000; i >= 0 ; i--)
                                if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                        break;
                        /* Re-enable the receiver. */
@@ -1373,8 +1409,11 @@ vortex_error(struct device *dev, int status)
                        outw(TxEnable, ioaddr + EL3_CMD);
                } else if (fifo_diag & 0x0400)
                        do_tx_reset = 1;
-               if (fifo_diag & 0x2000) {
+               if (fifo_diag & 0x3000) {
                        outw(RxReset, ioaddr + EL3_CMD);
+                       for (i = 2000; i >= 0 ; i--)
+                               if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+                                       break;
                        /* Set the Rx filter to the current state. */
                        set_rx_mode(dev);
                        outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1384,7 +1423,7 @@ vortex_error(struct device *dev, int status)
        if (do_tx_reset) {
                int j;
                outw(TxReset, ioaddr + EL3_CMD);
-               for (j = 20; j >= 0 ; j--)
+               for (j = 200; j >= 0 ; j--)
                        if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                break;
                outw(TxEnable, ioaddr + EL3_CMD);
@@ -1418,7 +1457,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
        } else {
                /* ... and the packet rounded to a doubleword. */
                outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-               dev_kfree_skb (skb, FREE_WRITE);
+               DEV_FREE_SKB(skb);
                if (inw(ioaddr + TxFree) > 1536) {
                        clear_bit(0, (void*)&dev->tbusy);
                } else
@@ -1428,7 +1467,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
 #else
        /* ... and the packet rounded to a doubleword. */
        outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-       dev_kfree_skb (skb, FREE_WRITE);
+       DEV_FREE_SKB(skb);
        if (inw(ioaddr + TxFree) > 1536) {
                clear_bit(0, (void*)&dev->tbusy);
        } else
@@ -1453,7 +1492,7 @@ vortex_start_xmit(struct sk_buff *skb, struct device *dev)
                                if (tx_status & 0x30) {
                                        int j;
                                        outw(TxReset, ioaddr + EL3_CMD);
-                                       for (j = 20; j >= 0 ; j--)
+                                       for (j = 200; j >= 0 ; j--)
                                                if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
                                                        break;
                                }
@@ -1503,7 +1542,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
                cli();
                outw(DownStall, ioaddr + EL3_CMD);
                /* Wait for the stall to complete. */
-               for (i = 60; i >= 0 ; i--)
+               for (i = 600; i >= 0 ; i--)
                        if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
                                break;
                prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
@@ -1535,13 +1574,13 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
 #else
        struct device *dev = (struct device *)(irq2dev_map[irq]);
 #endif
-       struct vortex_private *lp;
+       struct vortex_private *vp;
        int ioaddr, status;
        int latency;
        int work_done = max_interrupt_work;
 
-       lp = (struct vortex_private *)dev->priv;
-       if (test_and_set_bit(0, (void*)&lp->in_interrupt)) {
+       vp = (struct vortex_private *)dev->priv;
+       if (test_and_set_bit(0, (void*)&vp->in_interrupt)) {
                printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
                return;
        }
@@ -1576,24 +1615,24 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                }
 
                if (status & DownComplete) {
-                       unsigned int dirty_tx = lp->dirty_tx;
+                       unsigned int dirty_tx = vp->dirty_tx;
 
-                       while (lp->cur_tx - dirty_tx > 0) {
+                       while (vp->cur_tx - dirty_tx > 0) {
                                int entry = dirty_tx % TX_RING_SIZE;
                                if (inl(ioaddr + DownListPtr) ==
-                                       virt_to_bus(&lp->tx_ring[entry]))
+                                       virt_to_bus(&vp->tx_ring[entry]))
                                        break;                  /* It still hasn't been processed. */
-                               if (lp->tx_skbuff[entry]) {
-                                       dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
-                                       lp->tx_skbuff[entry] = 0;
+                               if (vp->tx_skbuff[entry]) {
+                                       DEV_FREE_SKB(vp->tx_skbuff[entry]);
+                                       vp->tx_skbuff[entry] = 0;
                                }
-                               /* lp->stats.tx_packets++;  Counted below. */
+                               /* vp->stats.tx_packets++;  Counted below. */
                                dirty_tx++;
                        }
-                       lp->dirty_tx = dirty_tx;
+                       vp->dirty_tx = dirty_tx;
                        outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
-                       if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-                               lp->tx_full= 0;
+                       if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+                               vp->tx_full= 0;
                                clear_bit(0, (void*)&dev->tbusy);
                                mark_bh(NET_BH);
                        }
@@ -1602,7 +1641,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                if (status & DMADone) {
                        outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
                        clear_bit(0, (void*)&dev->tbusy);
-                       dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
+                       DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
                        mark_bh(NET_BH);
                }
 #endif
@@ -1636,7 +1675,7 @@ static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
                           dev->name, status);
 
        dev->interrupt = 0;
-       clear_bit(0, (void*)&lp->in_interrupt);
+       clear_bit(0, (void*)&vp->in_interrupt);
        return;
 }
 
@@ -1777,6 +1816,15 @@ boomerang_rx(struct device *dev)
                        }
 #if LINUX_VERSION_CODE > 0x10300
                        skb->protocol = eth_type_trans(skb, dev);
+                       {                                       /* Use hardware checksum info. */
+                               int csum_bits = rx_status & 0xee000000;
+                               if (csum_bits &&
+                                       (csum_bits == (IPChksumValid | TCPChksumValid) ||
+                                        csum_bits == (IPChksumValid | UDPChksumValid))) {
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                                       rx_csumhits++;
+                               }
+                       }
 #else
                        skb->len = pkt_len;
 #endif
@@ -1825,13 +1873,13 @@ vortex_close(struct device *dev)
                printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
                           dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
                printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
-                          " tx_queued %d.\n",
-                          dev->name, rx_nocopy, rx_copy, queued_packet);
+                          " tx_queued %d Rx pre-checksummed %d.\n",
+                          dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
        }
 
        del_timer(&vp->timer);
 
-       /* Turn off statistics ASAP.  We update lp->stats below. */
+       /* Turn off statistics ASAP.  We update vp->stats below. */
        outw(StatsDisable, ioaddr + EL3_CMD);
 
        /* Disable the receiver and transmitter. */
@@ -1859,7 +1907,7 @@ vortex_close(struct device *dev)
 #if LINUX_VERSION_CODE < 0x20100
                                vp->rx_skbuff[i]->free = 1;
 #endif
-                               dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE);
+                               DEV_FREE_SKB(vp->rx_skbuff[i]);
                                vp->rx_skbuff[i] = 0;
                        }
        }
@@ -1867,7 +1915,7 @@ vortex_close(struct device *dev)
                outl(0, ioaddr + DownListPtr);
                for (i = 0; i < TX_RING_SIZE; i++)
                        if (vp->tx_skbuff[i]) {
-                               dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE);
+                               DEV_FREE_SKB(vp->tx_skbuff[i]);
                                vp->tx_skbuff[i] = 0;
                        }
        }
index 6ac1531ea7a190cb206c76c43c021c87404824fb..82bc7b1ca3496c5e8ab4e80596076c9d6b817086 100644 (file)
@@ -39,7 +39,7 @@ static const char *version=
 #include <asm/irq.h>
 #include <linux/netdevice.h>
 
-struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */};
+struct device *irq2dev_map[NR_IRQS] = {0, 0, /* ... zeroed */};
 
 unsigned long irqs_busy = 0x2147;              /* The set of fixed IRQs (keyboard, timer, etc) */
 unsigned long irqs_used = 0x0001;              /* The set of fixed IRQs sometimes enabled. */
@@ -65,8 +65,8 @@ static void autoirq_probe(int irq, void *dev_id, struct pt_regs * regs)
 int autoirq_setup(int waittime)
 {
        int i;
-       int timeout = jiffies + waittime;
-       int boguscount = (waittime*loops_per_sec) / 100;
+       unsigned long timeout = jiffies + waittime;
+       unsigned long boguscount = (waittime*loops_per_sec) / 100;
 
        irq_handled = 0;
        irq_bitmap = 0;
@@ -93,8 +93,8 @@ int autoirq_setup(int waittime)
 int autoirq_report(int waittime)
 {
        int i;
-       int timeout = jiffies+waittime;
-       int boguscount = (waittime*loops_per_sec) / 100;
+       unsigned long timeout = jiffies+waittime;
+       unsigned long boguscount = (waittime*loops_per_sec) / 100;
 
        /* Hang out at least <waittime> jiffies waiting for the IRQ. */
 
index 83b889d0588279e2c83ccfb3bf2dbd759ed1bbd6..d33808c1dc2a6f642fd138893f67e69b7ba55e8b 100644 (file)
@@ -76,7 +76,7 @@ static const char *version = "lance.c:v1.14 2/3/1998 dplatt@3do.com, becker@cesd
 
 static unsigned int lance_portlist[] = { 0x300, 0x320, 0x340, 0x360, 0};
 int lance_probe(struct device *dev);
-void lance_probe1(struct device *dev, int ioaddr, int irq, int options);
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options);
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry lance_drv =
@@ -374,7 +374,7 @@ cleanup_module(void)
    */
 int lance_probe(struct device *dev)
 {
-       int *port;
+       int *port, result;
 
        if (high_memory <= 16*1024*1024)
                lance_need_isa_bounce_buffers = 0;
@@ -413,8 +413,9 @@ int lance_probe(struct device *dev)
                        }
                        printk("Found PCnet/PCI at %#x, irq %d.\n",
                                   pci_ioaddr, pci_irq_line);
-                       lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
+                       result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
                        pci_irq_line = 0;
+                       if (!result) return 0;
                }
        }
 #endif  /* defined(CONFIG_PCI) */
@@ -428,14 +429,16 @@ int lance_probe(struct device *dev)
                        char offset15, offset14 = inb(ioaddr + 14);
                        
                        if ((offset14 == 0x52 || offset14 == 0x57) &&
-                               ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
-                               lance_probe1(dev, ioaddr, 0, 0);
+                               ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+                               result = lance_probe1(dev, ioaddr, 0, 0);
+                               if ( !result ) return 0;
+                       }
                }
        }
-       return 0;
+       return -ENODEV;
 }
 
-void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
+int lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 {
        struct lance_private *lp;
        short dma_channels;                                     /* Mark spuriously-busy DMA channels */
@@ -473,7 +476,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 
        outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
        if (inw(ioaddr+LANCE_DATA) != 0x0004)
-               return;
+               return -ENODEV;
 
        /* Get the version of the chip. */
        outw(88, ioaddr+LANCE_ADDR);
@@ -486,7 +489,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
                if (lance_debug > 2)
                        printk("  LANCE chip version is %#x.\n", chip_version);
                if ((chip_version & 0xfff) != 0x003)
-                       return;
+                       return -ENODEV;
                chip_version = (chip_version >> 12) & 0xffff;
                for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
                        if (chip_table[lance_version].id_number == chip_version)
@@ -512,10 +515,9 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
 #ifdef CONFIG_LANCE32
        /* look if it's a PCI or VLB chip */
        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
-           extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
+           extern int lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
            
-           lance32_probe1 (dev, chipname, pci_irq_line);
-           return;
+           return lance32_probe1 (dev, chipname, pci_irq_line);
        }
 #endif    
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
@@ -604,7 +606,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
                        printk(", probed IRQ %d", dev->irq);
                else {
                        printk(", failed to detect IRQ line.\n");
-                       return;
+                       return -ENODEV;
                }
 
                /* Check for the initialization done bit, 0x0100, which means
@@ -618,7 +620,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
        } else if (dev->dma) {
                if (request_dma(dev->dma, chipname)) {
                        printk("DMA %d allocation failed.\n", dev->dma);
-                       return;
+                       return -ENODEV;
                } else
                        printk(", assigned DMA %d.\n", dev->dma);
        } else {                        /* OK, we have to auto-DMA. */
@@ -653,7 +655,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
                }
                if (i == 4) {                   /* Failure: bail. */
                        printk("DMA detection failed.\n");
-                       return;
+                       return -ENODEV;
                }
        }
 
@@ -666,7 +668,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
                dev->irq = autoirq_report(4);
                if (dev->irq == 0) {
                        printk("  Failed to detect the 7990 IRQ line.\n");
-                       return;
+                       return -ENODEV;
                }
                printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
        }
@@ -689,7 +691,7 @@ void lance_probe1(struct device *dev, int ioaddr, int irq, int options)
        dev->get_stats = lance_get_stats;
        dev->set_multicast_list = set_multicast_list;
 
-       return;
+       return 0;
 }
 
 static int
index 791c44a9cc63e8ed7074538a6f460769ca6bc39a..ed2efbb0bdd551278e56e712df5cacb3deceb446 100644 (file)
@@ -793,7 +793,7 @@ cleanup_module(void)
                if (dev->priv != NULL) {
                        kfree(dev->priv);
                        dev->priv = NULL;
-                       free_irq(dev->irq, NULL);
+                       free_irq(dev->irq, dev);
                        irq2dev_map[dev->irq] = NULL;
                        release_region(dev->base_addr, NE_IO_EXTENT);
                        unregister_netdev(dev);
index 632afa094ca8e16d7cfd943a2f20da2c833aa059..d78146d5faf34c3cb49675248f08e46da52b6061 100644 (file)
@@ -5,8 +5,9 @@
  *
  *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *  Fixed (I hope) the wait_queue trashing bug. Alan Cox <alan@redhat.com>
  *
- *  ==FILEVERSION 970703==
+ *  ==FILEVERSION 980512==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -448,8 +449,13 @@ ppp_init_ctrl_blk (register struct ppp *ppp)
        ppp->ubuf       = NULL;
        ppp->cbuf       = NULL;
        ppp->slcomp     = NULL;
+#if 0
+       /* AC - We don't want to initialise this as the wait queue may still
+          be live. Having someone waiting on the old and the new queue is fine
+          the old people will unhook themselves so just set this up in ppp_alloc */
        ppp->read_wait  = NULL;
        ppp->write_wait = NULL;
+#endif 
        ppp->last_xmit  = jiffies - flag_time;
 
        /* clear statistics */
@@ -798,9 +804,7 @@ ppp_tty_open (struct tty_struct *tty)
         }
 
        if (ppp == NULL) {
-               if (ppp->flags & SC_DEBUG)
-                       printk (KERN_ERR
-                       "ppp_tty_open: couldn't allocate ppp channel\n");
+               printk (KERN_WARNING "ppp_tty_open: couldn't allocate ppp channel\n");
                return -ENFILE;
        }
 /*
index 0574de0ced9c29b1b9c1c11c9a151d94aad39bd6..d35569dafa555f0520b0fe05a35e7a24f0d0eb27 100644 (file)
@@ -740,6 +740,7 @@ const char *pci_strvendor(unsigned int vendor)
              case PCI_VENDOR_ID_MATROX:        return "Matrox";
              case PCI_VENDOR_ID_CT:            return "Chips & Technologies";
              case PCI_VENDOR_ID_MIRO:          return "Miro";
+             case PCI_VENDOR_ID_NEC:           return "NEC";
              case PCI_VENDOR_ID_FD:            return "Future Domain";
              case PCI_VENDOR_ID_SI:            return "Silicon Integrated Systems";
              case PCI_VENDOR_ID_HP:            return "Hewlett Packard";
@@ -892,15 +893,16 @@ static void burst_bridge(unsigned char bus, unsigned char devfn,
 static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
 {
        unsigned long base;
-       unsigned int l, class_rev, bus, devfn;
+       unsigned int l, class_rev, bus, devfn, last_reg;
        unsigned short vendor, device, status;
-       unsigned char bist, latency, min_gnt, max_lat;
+       unsigned char bist, latency, min_gnt, max_lat, hdr_type;
        int reg, len = 0;
        const char *str;
 
        bus   = dev->bus->number;
        devfn = dev->devfn;
 
+       pcibios_read_config_byte (bus, devfn, PCI_HEADER_TYPE, &hdr_type);
        pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev);
        pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor);
        pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device);
@@ -979,7 +981,17 @@ static int sprint_dev_config(struct pci_dev *dev, char *buf, int size)
                  len += sprintf(buf + len, "Max Lat=%d.", max_lat);
        }
 
-       for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+       switch (hdr_type & 0x7f) {
+               case 0:
+                       last_reg = PCI_BASE_ADDRESS_5;
+                       break;
+               case 1:
+                       last_reg = PCI_BASE_ADDRESS_1;
+                       break;
+               default:
+                       last_reg = 0;
+       }
+       for (reg = PCI_BASE_ADDRESS_0; reg <= last_reg; reg += 4) {
                if (len + 40 > size) {
                        return -1;
                }
@@ -1072,7 +1084,7 @@ static void *pci_malloc(long size, unsigned long *mem_startp)
 static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 {
        unsigned int devfn, l, max;
-       unsigned char cmd, tmp, hdr_type, is_multi = 0;
+       unsigned char cmd, tmp, hdr_type, ht, is_multi = 0;
        struct pci_dev_info *info;
        struct pci_dev *dev;
        struct pci_bus *child;
@@ -1146,10 +1158,20 @@ static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
 
                /*
                 * Check if the header type is known and consistent with
-                * device type. Bridges should have hdr_type 1, all other
-                * devices 0.
+                * device type. PCI-to-PCI Bridges should have hdr_type 1,
+                * CardBus Bridges 2, all other devices 0.
                 */
-               if ((dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) != (hdr_type & 0x7f)) {
+               switch (dev->class >> 8) {
+                       case PCI_CLASS_BRIDGE_PCI:
+                               ht = 1;
+                               break;
+                       case PCI_CLASS_BRIDGE_CARDBUS:
+                               ht = 2;
+                               break;
+                       default:
+                               ht = 0;
+               }
+               if (ht != (hdr_type & 0x7f)) {
                        printk(KERN_WARNING "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
                                bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type);
                        continue;
index 89b129f9d6cc09b1ddff57b3be424e47f701f272..a8418e7b33dc6817341de580e22e85ae006f281b 100644 (file)
@@ -26,8 +26,8 @@
 */
 
 
-#define BusLogic_DriverVersion         "2.0.13"
-#define BusLogic_DriverDate            "17 April 1998"
+#define BusLogic_DriverVersion         "2.0.14"
+#define BusLogic_DriverDate            "29 April 1998"
 
 
 #include <linux/version.h>
@@ -1217,10 +1217,13 @@ static boolean BusLogic_Failure(BusLogic_HostAdapter_T *HostAdapter,
 {
   BusLogic_AnnounceDriver(HostAdapter);
   if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus)
-    BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n"
-                  "Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
-                  HostAdapter, HostAdapter->Bus, HostAdapter->Device,
-                  HostAdapter->IO_Address, HostAdapter->PCI_Address);
+    {
+      BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n",
+                    HostAdapter);
+      BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n",
+                    HostAdapter, HostAdapter->Bus, HostAdapter->Device,
+                    HostAdapter->IO_Address, HostAdapter->PCI_Address);
+    }
   else BusLogic_Error("While configuring BusLogic Host Adapter at "
                      "I/O Address 0x%X:\n", HostAdapter,
                      HostAdapter->IO_Address);
index c6bac228efee1a247d88e51ca528ab8a653d0105..d9f93971975d3f300e0061274c57d1e34ca0592a 100644 (file)
@@ -77,6 +77,9 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
   fi
 fi
 dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
+if [ "$CONFIG_SCSI_PPA" != "n" ]; then
+    bool '  Buggy EPP chipset support' CONFIG_SCSI_PPA_HAVE_PEDANTIC
+fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
index 46c5e42f270678adec39912c512d775858275503..e6fc75c9952fc21c92a2ed2f06c4f1f31f9e7d03 100644 (file)
@@ -491,11 +491,11 @@ static __inline__ void run_main(void) {
  */
 #ifndef USLEEP_SLEEP
 /* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP 2
+#define USLEEP_SLEEP (20*HZ/1000)
 #endif
 /* 300 RPM (floppy speed) */
 #ifndef USLEEP_POLL
-#define USLEEP_POLL 20
+#define USLEEP_POLL (200*HZ/1000)
 #endif
 
 static struct Scsi_Host * expires_first = NULL;
@@ -643,7 +643,7 @@ static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) {
            == 0)) 
            trying_irqs |= mask;
 
-    timeout = jiffies + 25;
+    timeout = jiffies + 250*HZ/1000;
     probe_irq = IRQ_NONE;
 
 /*
@@ -819,7 +819,7 @@ int NCR5380_proc_info (
 SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
 #endif
 
-   SPRINTF("\nBase Addr: 0x%05X    ", (int)instance->base);
+   SPRINTF("\nBase Addr: 0x%05lX    ", (long)instance->base);
    SPRINTF("io_port: %04x      ", (int)instance->io_port);
    if (instance->irq == IRQ_NONE)
       SPRINTF("IRQ: None.\n");
@@ -1002,7 +1002,7 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags) {
        case 5:
            printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
                instance->host_no);
-           timeout = jiffies + 500;
+           timeout = jiffies + 5*HZ;
            while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
            break;
        case 2:
@@ -1618,7 +1618,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
      * selection.
      */
 
-    timeout = jiffies + 25
+    timeout = jiffies + 250*HZ/1000;
 
     /* 
      * XXX very interesting - we're seeing a bounce where the BSY we 
index 50708cfca8a261cf37145da06f2541a71a512e9d..08e2897a6f1a193724954340f02c39e1bca1adc1 100644 (file)
@@ -314,29 +314,33 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
 static int NCR5380_transfer_pio (struct Scsi_Host *instance,
        unsigned char *phase, int *count, unsigned char **data);
 
-#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
-static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
+
+#if defined(i386) || defined(__alpha__)
+
+static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance,
        unsigned char *ptr, unsigned int count, unsigned char mode) {
     unsigned limit;
+    unsigned long bus_addr = virt_to_bus(ptr);
 
     if (instance->dma_channel <=3) {
        if (count > 65536)
            count = 65536;
-       limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+       limit = 65536 - (bus_addr & 0xFFFF);
     } else {
        if (count > 65536 * 2) 
            count = 65536 * 2;
-       limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
+       limit = 65536* 2 - (bus_addr & 0x1FFFF);
     }
 
     if (count > limit) count = limit;
 
-    if ((count & 1) || (((unsigned) ptr) & 1))
+    if ((count & 1) || (bus_addr & 1))
        panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
     cli();
     disable_dma(instance->dma_channel);
     clear_dma_ff(instance->dma_channel);
-    set_dma_addr(instance->dma_channel, (unsigned int) ptr);
+    set_dma_addr(instance->dma_channel, bus_addr);
     set_dma_count(instance->dma_channel, count);
     set_dma_mode(instance->dma_channel, mode);
     enable_dma(instance->dma_channel);
@@ -344,17 +348,17 @@ static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
     return count;
 }
 
-static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE);
 }
 
-static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ);
 }
 
-static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
+static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) {
     register int tmp;
     cli();
     clear_dma_ff(instance->dma_channel);
@@ -362,7 +366,8 @@ static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
     sti();
     return tmp;
 }
-#endif /* defined(REAL_DMA) && defined(i386)  */
+#endif /* defined(i386) || defined(__alpha__) */
+#endif /* defined(REAL_DMA)  */
 #endif __KERNEL_
 #endif /* ndef ASM */
 #endif /* NCR5380_H */
index d7126695be8b66e8b6f8f0fdb6f8812da7981442..36a7d703be16a33c921875358c9f3b61e6613de0 100644 (file)
@@ -1,10 +1,10 @@
           BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-                        Version 2.0.13 for Linux 2.0
+                        Version 2.0.14 for Linux 2.0
 
                              PRODUCTION RELEASE
 
-                                17 April 1998
+                                29 April 1998
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -591,7 +591,7 @@ To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.13.tar.gz
+  tar -xvzf BusLogic-2.0.14.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
   patch -p < BusLogic.patch
   cd linux
index 509541d7a8fba832a5e0b4411c27b348ec18d43b..370d1b03d1a178dbabfe049acb1a3b5dbf365d51 100644 (file)
@@ -1,4 +1,5 @@
 README.ppa (c) 1996   Grant R. Guenther,  grant@torque.net
+README.ppa (c) 1998   David J. Campbell,  campbell@torque.net
 
 
          The IOMEGA PPA3 parallel port SCSI Host Bus Adapter
@@ -37,83 +38,72 @@ I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his
 observation that the 'guest' driver loads under DOSemu.  His remark was
 the stimulus that began this project.
 
-The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but 
-there is currently no support for EPP or ECP ports, as I have been unable 
-to make the DOS drivers work in these modes on my test rig.
+For information about using the ZIP drive, please read the generic
+instructions in the SCSI-HOWTO and the man pages for the normal disk
+management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
+circulating concerning the use of the normal SCSI version of the ZIP
+drive, most of its comments will apply to disks connected through the
+ppa driver as well.
 
-The driver may be built in to the kernel, or loaded as a module.  It
-may be configured on the command line in both cases, although the syntax
-is different.  It may also be configured by editing the source file.
+>------------------------------------------------------------------------<
+David Campbell writes:
 
-Built-in drivers accept parameters using this LILO/LOADLIN command line
-syntax (omitted parameters retain their default values):
+Since the original was released by Grant several people have made many minor
+modifications:
 
-        ppa=base[,speed_high[,speed_low[,nybble]]]
+       a) Support for EPP
+       b) Autoprobing known parallel ports
+       c) Parallel port sharing with other devices (see notes)
 
-For example:    ppa=0x378,0,3
+It has been found that the JAZ Traveller also uses the VPI0 interface chipset
+(a reworked ppa3). This driver will also support this device without
+modifications.
 
-If a driver is loaded as a module the parameters may be set on the
-insmod command line, but each one must be specified by name:
+Please note that the ZIP Plus drive uses a VPI2 interface chipset (VPI1 never
+made it out of the Iomega development lab). A driver for this device exists,
+check my web page at http://www.torque.net/~campbell for further details.
 
-For example:    insmod ppa.o ppa_base=0x378 ppa_nybble=1
+                                 -<-->-
 
-(Notice the ppa_ prefix on each of the parameters in the insmod form.)
+Built-in drivers accept parameters using this LILO/LOADLIN command line
+syntax (omitted parameters retain their default values):
 
-Here are the parameters and their functions:
+        ppa=base,mode[,sg_buffer_size]
 
-Variable        Default    Description
+For example:    ppa=0x378,1
 
-ppa_base        0x378   The base address of PPA's parallel port.
-ppa_speed_high  1       Microsecond i/o delay used in data transfers
-ppa_speed_low   6       Microsecond delay used in other operations
-ppa_nybble      0       1 to force the driver to use 4-bit mode.
+The modes are as follows:
+       0       Autodetect mode
+       1       work in standard 4 bit mode
+       2       PS/2 byte mode
+       3       EPP mode, 8 bit
+       4       EPP mode, 16 bit
+       5       EPP mode, 32 bit
 
-A word about the timing parameters:  the ppa_speed_low parameter controls 
-the widths of a large number of pulses that are sent over the parallel bus, 
-the narrower the pulses, the faster things go, but the greater the risk of 
-distortion by noise damping circuits in the parallel ports.  The 
-ppa_speed_high parameter controls the same delays, but during the data 
-transfer phase only.   In this phase, there is a lot of handshaking going 
-on and the pulse shaping should not be so much of an issue, but if you 
-see data corruption, you can increase this parameter as well.
+If ppa is built as a module there is currently no method of changing the
+operation of the driver. Basically there is no need (unless you have a very
+strange parallel port address).
 
-You might also want to reduce the timing values to attempt to increase
-the transfer rates on your system.  Please be careful to watch for
-SCSI timeout errors in your log files.  If you are getting timeouts, you
-have set these parameters too low.  The default values appear to be
-safe on most machines.
+                                 -<-->-
 
-If you have both the lp and ppa drivers in your kernel, you must ensure
-that they access different parallel ports.  By default, the lp driver is
-initialised early in the booting process, and it claims all parallel
-ports that it can find.  You may control this behaviour with a LILO or
-LOADLIN command line argument of the form:
+Using the ZIP drive and a printer either requires two parallel ports (one
+for each device) or use of the parport driver (which can be found in the
+2.1.x kernels).
 
+In the first case compile the lp driver as a module and load it after ppa.
+Alternatively specify which ports the lp driver should use by the LILO/LOADLIN
+options:
         lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
 
-For example:    lp=0x278,7
+                                 -<-->-
 
-If you use this method, only the ports named will be adopted by the lp
-driver.  You can disable them all with lp=0 .
+Mainboard buggy chipset hall of shame: [information courtesy of Iomega]
 
-So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would
-give the following options on your boot command:
+       National Semiconductor PC87306 rev ID 0x70, 0x71
+       Winbond xx837
 
-        lp=0x3bc ppa=0x278
-
-In this case lp would use the polling driver, since an interrupt was not 
-specified.
-
-If you want to share the same parallel port between a ZIP drive and a
-printer, you should build both the lp and ppa drivers as modules and
-load and unload one or the other as required.  This is clumsy but we
-currently have no protocol for synchronising access to shared parallel
-ports.
-
-For information about using the ZIP drive, please read the generic
-instructions in the SCSI-HOWTO and the man pages for the normal disk
-management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
-circulating concerning the use of the normal SCSI version of the ZIP
-drive, most of its comments will apply to disks connected through the
-ppa driver as well.
+The above chipsets are known to have problems using EPP. Note that the
+National Semicondutor problems only affect early batches of PC87306 which
+should really never made it to market (a run for mainboard developers).
+>------------------------------------------------------------------------<
 
index 17b17fe0c501e62f9467ff4987f6558e7ee7e5b2..b2622bc8dc87bb7fca7a579e3260cb4dc7456396 100644 (file)
@@ -209,7 +209,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.0.13"
+#define AIC7XXX_C_VERSION  "5.0.14"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -242,7 +242,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
 #  include <linux/bios32.h>
 #endif
 
-#if !defined(__alpha__)
+#if !defined(__alpha__) && !defined(__sparc__)
 #  define MMAPIO
 #endif
 
@@ -936,6 +936,7 @@ struct aic7xxx_host {
   volatile unsigned char   untagged_scbs[256];
   volatile unsigned char   qoutfifo[256];
   volatile unsigned char   qinfifo[256];
+  unsigned int             irq;              /* IRQ for this adapter */
   unsigned short           needsdtr;
   unsigned short           sdtr_pending;
   unsigned short           needwdtr;
@@ -953,7 +954,6 @@ struct aic7xxx_host {
   unsigned short           adapter_control;  /* adapter control - SEEPROM */
   unsigned char            pci_bus;
   unsigned char            pci_device_fn;
-  unsigned char            irq;              /* IRQ for this adapter */
 
 #ifdef AIC7XXX_PROC_STATS
   /*
@@ -1799,10 +1799,16 @@ scbq_init(volatile scb_queue_type *queue)
 static inline void
 scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   scb->q_next = queue->head;
   queue->head = scb;
   if (queue->tail == NULL)       /* If list was empty, update tail. */
     queue->tail = queue->head;
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1817,11 +1823,17 @@ static __inline struct aic7xxx_scb *
 scbq_remove_head(volatile scb_queue_type *queue)
 {
   struct aic7xxx_scb * scbp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
+  DRIVER_UNLOCK
   return(scbp);
 }
 
@@ -1836,6 +1848,11 @@ scbq_remove_head(volatile scb_queue_type *queue)
 static inline void
 scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   if (queue->head == scb)
   {
     /* At beginning of queue, remove from head. */
@@ -1864,6 +1881,7 @@ scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
       }
     }
   }
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -1877,12 +1895,18 @@ scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 static inline void
 scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
+  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2167,7 +2191,6 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
   Scsi_Cmnd *cmd;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned int cpu_flags = 0;
-#endif
   
   DRIVER_LOCK
   while (p->completeq.head != NULL)
@@ -2175,11 +2198,20 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    DRIVER_UNLOCK
+    sti();
     cmd->scsi_done(cmd);
-    DRIVER_LOCK
+    cli();
   }
   DRIVER_UNLOCK
+#else
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+#endif
 }
 
 /*+F*************************************************************************
@@ -2321,16 +2353,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         scbq_insert_tail(&p->waiting_scbs, scbp);
     }
   }
-  if ( (p->dev_timer[tindex].expires) &&
-      ((p->dev_active_cmds[tindex] == 1) ||
-       (p->dev_max_queue_depth[tindex] ==
-        p->dev_temp_queue_depth[tindex])) )
-  {
-    del_timer(&p->dev_timer[tindex]);
-    p->dev_timer[tindex].expires = 0;
-    p->dev_temp_queue_depth[tindex] = 
-          p->dev_max_queue_depth[tindex];
-  }
   p->dev_active_cmds[tindex]--;
   p->activescbs--;
 
@@ -2528,13 +2550,18 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
         */
        if (requeue && (queue != NULL))
        {
-         if ( !(scbp->flags & SCB_WAITINGQ) )
+         if (scbp->flags & SCB_WAITINGQ)
          {
-           scbq_insert_tail(queue, scbp);
-           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
-           p->activescbs--;
-           scbp->flags |= SCB_WAITINGQ;
+           scbq_remove(queue, scbp);
+           scbq_remove(&p->waiting_scbs, scbp);
+           scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+           p->activescbs++;
          }
+         scbq_insert_tail(queue, scbp);
+         p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+         p->activescbs--;
+         scbp->flags |= SCB_WAITINGQ;
          if ( !(scbp->tag_action & TAG_ENB) )
          {
            aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
@@ -2704,12 +2731,11 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
    * here so that we can delay all re-sent commands for this device for the
    * 4 seconds and then have our timer routine pick them back up.
    */
-        if( (p->dev_timer[i].prev != NULL) ||
-            (p->dev_timer[i].next != NULL) )
+        if(p->dev_timer[i].expires)
         {
           del_timer(&p->dev_timer[i]);
         }
-        p->dev_timer[i].expires = jiffies + (3 * HZ);
+        p->dev_timer[i].expires = jiffies + (4 * HZ);
         add_timer(&p->dev_timer[i]);
       }
       for(j=0; j<MAX_LUNS; j++)
@@ -2741,7 +2767,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
         {
           scbq_remove(&p->delayed_scbs[i], prev_scbp);
-          if ( !(prev_scbp->flags & SCB_WAITINGQ) )
+          if (prev_scbp->flags & SCB_WAITINGQ)
           {
             p->dev_active_cmds[i]++;
             p->activescbs++;
@@ -2800,7 +2826,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
       {
         scbq_remove(&p->waiting_scbs, prev_scbp);
-        if ( !(prev_scbp->flags & SCB_WAITINGQ) )
+        if (prev_scbp->flags & SCB_WAITINGQ)
         {
           p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
           p->activescbs++;
@@ -2853,7 +2879,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-          if ( !(scbp->flags & SCB_WAITINGQ) )
+          if (scbp->flags & SCB_WAITINGQ)
           {
             p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
             p->activescbs++;
@@ -2869,6 +2895,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
              * it isn't already off.
              */
             aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
           }
         }
         else
@@ -2890,6 +2917,9 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
    * Go through disconnected list and remove any entries we have queued
    * for completion, zeroing their control byte too.
    */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning disconnected scbs "
+      "list.\n", p->host_no, channel, target, lun);
   {
     unsigned char next, prev, scb_index;
 
@@ -2902,7 +2932,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
       scb_index = aic_inb(p, SCB_TAG);
       if (scb_index > p->scb_data->numscbs)
       {
-        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+        printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
           "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
           p->scb_data->numscbs);
         next = aic7xxx_rem_scb_from_disc_list(p, next);
@@ -2913,7 +2943,7 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
         {
           next = aic7xxx_rem_scb_from_disc_list(p, next);
-          if ( !(scbp->flags & SCB_WAITINGQ) )
+          if (scbp->flags & SCB_WAITINGQ)
           {
             p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
             p->activescbs++;
@@ -3027,6 +3057,13 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
         aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
         !aic7xxx_scb_on_qoutfifo(p, scbp))
     {
+      if (scbp->flags & SCB_WAITINGQ)
+      {
+        scbq_remove(&p->waiting_scbs, scbp);
+        scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+        p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+        p->activescbs++;
+      }
       scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
     }
@@ -3203,12 +3240,6 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
     restart_sequencer(p);
   }
 
-  /*
-   * Now loop through all the SCBs that have been marked for abortion,
-   * and call the scsi_done routines.
-   */
-  if(!(p->flags & AHC_IN_ISR))
-    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
   return;
 }
 
@@ -3245,18 +3276,21 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
     tindex = TARGET_INDEX(scb->cmd);
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_last_reset[tindex] >= (jiffies + (3 * HZ))) )
+         (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) )
     {
         scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+        if ( !(p->dev_timer[tindex].expires) &&
+             !(p->dev_active_cmds[tindex]) )
+        {
+          p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
+          add_timer(&p->dev_timer[tindex]);
+        }
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-        if ( !(scb->flags & SCB_QUEUED_ABORT) )
-        {
-          p->dev_active_cmds[tindex]++;
-          p->activescbs++;
-        }
+        p->dev_active_cmds[tindex]++;
+        p->activescbs++;
         if ( !(scb->tag_action) )
         {
           aic7xxx_busy_target(p, scb);
@@ -3293,7 +3327,7 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 static void
 aic7xxx_timer(struct aic7xxx_host *p)
 {
-  int i;
+  int i, j;
   unsigned long cpu_flags = 0;
   struct aic7xxx_scb *scb;
 
@@ -3314,10 +3348,23 @@ aic7xxx_timer(struct aic7xxx_host *p)
         del_timer(&p->dev_timer[i]);
       }
       p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
-      while ( (scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL )
+      j = 0;
+      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
+              (j++ < p->scb_data->numscbs) )
       {
         scbq_insert_tail(&p->waiting_scbs, scb);
       }
+      if (j == p->scb_data->numscbs)
+      {
+        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
+          p->host_no, 0, i, -1);
+        scbq_init(&p->delayed_scbs[i]);
+        scbq_init(&p->waiting_scbs);
+        /*
+         * Well, things are screwed now, wait for a reset to clean the junk
+         * out.
+         */
+      }
     }
   }
   aic7xxx_run_waiting_queues(p);
@@ -3458,7 +3505,7 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
   if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
     printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
       target, -1);
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+  aic7xxx_run_done_queue(p, /*complete*/ FALSE);
 }
 
 /*+F*************************************************************************
@@ -3520,6 +3567,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
 
         aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        aic7xxx_run_done_queue(p, FALSE);
 
       }
       break;
@@ -3585,7 +3633,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 
         if ( (last_msg == MSG_IDENTIFYFLAG) &&
              (scb->tag_action != 0 ) &&
-             !(p->flags & AHC_HANDLING_REQINITS) )
+             !(scb->flags & SCB_MSGOUT_BITS) )
         {
           if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
               (p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS))
@@ -3606,8 +3654,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
              * ATNO and hope this will take us into the identify phase again
              * so we can resend the tag type and info to the device.
              */
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
-          else
+          else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) &&
+                   !(p->dev_flags[scratch_offset] & DEVICE_TAGGED_SUCCESS) )
           {
             unsigned char i, reset = 0;
             struct aic7xxx_scb *scbp;
@@ -3637,7 +3688,6 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
              */
             scb->tag_action = 0;
             scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
-            scb->hscb->control |= MK_MESSAGE;
             aic_outb(p,  scb->hscb->control, SCB_CONTROL);
 
             old_verbose = aic7xxx_verbose;
@@ -3652,6 +3702,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                   aic7xxx_reset_device(p, target, channel, lun, i);
                   reset++;
                 }
+                aic7xxx_run_done_queue(p, FALSE);
               }
             }
             aic7xxx_verbose = old_verbose;
@@ -3663,12 +3714,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             aic7xxx_busy_target(p, scb);
             printk(INFO_LEAD "Device is refusing tagged commands, using "
               "untagged I/O.\n", p->host_no, channel, target, lun);
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
-          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
-          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
         }
-        else if ( (last_msg == MSG_IDENTIFYFLAG) && 
-                  (scb->flags & SCB_MSGOUT_WDTR) )
+        else if (scb->flags & SCB_MSGOUT_WDTR)
         {
           /*
            * note 8bit xfers and clear flag
@@ -3686,13 +3736,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           }
           scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
           p->syncinfo[scratch_offset].offset = MAX_OFFSET_8BIT;
-          if (p->needsdtr & target_mask)
-          {
-            p->sdtr_pending |= target_mask;
-            scb->flags |= SCB_MSGOUT_SDTR;
-            aic_outb(p, HOST_MSG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-          }
+          /*
+           * The sequencer should have already cleared the MK_MESSAGE bit in
+           * the SCB, so we simply restart the message out phase and resend
+           * the IDENTIFY and TAG values so that there is no confusion over
+           * what has been rejected.
+           */
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
@@ -3712,6 +3763,14 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               "asynchronous transfers.\n", p->host_no, CTL_OF_SCB(scb));
             p->dev_flags[scratch_offset] &= ~DEVICE_PRINT_SDTR;
           }
+          /*
+           * The sequencer should have already cleared the MK_MESSAGE bit in
+           * the SCB, so we simply restart the message out phase and resend
+           * the IDENTIFY and TAG values so that there is no confusion over
+           * what has been rejected.
+           */
+          aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
         }
         else if (aic7xxx_verbose & VERBOSE_SEQINT)
         {
@@ -3831,25 +3890,24 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                  * so if needed, we'll re-negotiate while doing the sense cmd.
                  * However, if this SCB already was attempting to negotiate,
                  * then we assume this isn't the problem and skip this part.
+                 *
+                 * 1998/04/23 - We also don't want to set the flag if the
+                 *   original command was a TEST_UNIT_READY since that
+                 *   implies a SEND_SENSE anyway.  Plus, we don't actually
+                 *   start the negotiation here, we just flag it because
+                 *   some devices appear to choke up their message buffer
+                 *   when we mix things together like this.
                  */
-                if ( !(scb->flags & SCB_MSGOUT_BITS) )
+                if ( !(scb->flags & SCB_MSGOUT_BITS) &&
+                      (scb->cmd->cmnd[0] != TEST_UNIT_READY) )
                 {
                   if ( p->needwdtr_copy & target_mask )
                   {
                     p->needwdtr |= target_mask;
-                    p->wdtr_pending |= target_mask;
-                    hscb->control |= MK_MESSAGE;
-                    scb->flags |= SCB_MSGOUT_WDTR_16BIT;
                   }
                   if ( p->needsdtr_copy & target_mask )
                   {
                     p->needsdtr |= target_mask;
-                    if ((hscb->control & MK_MESSAGE) == 0)
-                    {
-                      p->sdtr_pending |= target_mask;
-                      hscb->control |= MK_MESSAGE;
-                      scb->flags |= SCB_MSGOUT_SDTR;
-                    }
                   }
                 }
 
@@ -3904,41 +3962,60 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               {
                 aic_outb(p, next_hscb, SCBPTR);
                 scb_index = aic_inb(p, SCB_TAG);
-                next_scbp = p->scb_data->scb_array[scb_index];
-                if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
-                    SCB_LIST_NULL) )
+                if (scb_index < p->scb_data->numscbs)
                 {
-                  scbq_insert_head(&p->delayed_scbs[scratch_offset],
-                    next_scbp);
-                  next_scbp->flags |= SCB_WAITINGQ;
-                  p->dev_active_cmds[scratch_offset]--;
-                  p->activescbs--;
-                  next_hscb = aic_inb(p, SCB_NEXT);
-                  aic_outb(p, 0, SCB_CONTROL);
-                  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-                  aic7xxx_add_curscb_to_free_list(p);
-                  if (prev_hscb == SCB_LIST_NULL)
+                  next_scbp = p->scb_data->scb_array[scb_index];
+                  if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                      SCB_LIST_NULL) )
                   {
-                    aic_outb(p, 0, SCSISEQ);    /* We were first on the list,
-                                                 * so we kill the selection
-                                                 * hardware.  Let the sequencer
-                                                 * re-init the hardware itself
-                                                 */
-                    aic_outb(p, next_hscb, WAITING_SCBH);
+                    if (next_scbp->flags & SCB_WAITINGQ)
+                    {
+                      p->dev_active_cmds[scratch_offset]++;
+                      p->activescbs--;
+                      scbq_remove(&p->delayed_scbs[scratch_offset], next_scbp);
+                      scbq_remove(&p->waiting_scbs, next_scbp);
+                    }
+                    scbq_insert_head(&p->delayed_scbs[scratch_offset],
+                      next_scbp);
+                    next_scbp->flags |= SCB_WAITINGQ;
+                    p->dev_active_cmds[scratch_offset]--;
+                    p->activescbs--;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                    aic_outb(p, 0, SCB_CONTROL);
+                    aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                    aic7xxx_add_curscb_to_free_list(p);
+                    if (prev_hscb == SCB_LIST_NULL)
+                    {
+                      /* We were first on the list,
+                       * so we kill the selection
+                       * hardware.  Let the sequencer
+                       * re-init the hardware itself
+                       */
+                      aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+                      aic_outb(p, CLRSELTIMEO, CLRSINT1);
+                      aic_outb(p, next_hscb, WAITING_SCBH);
+                    }
+                    else
+                    {
+                      aic_outb(p, prev_hscb, SCBPTR);
+                      aic_outb(p, next_hscb, SCB_NEXT);
+                    }
                   }
                   else
                   {
-                    aic_outb(p, prev_hscb, SCBPTR);
-                    aic_outb(p, next_hscb, SCB_NEXT);
+                    prev_hscb = next_hscb;
+                    next_hscb = aic_inb(p, SCB_NEXT);
                   }
-                }
-                else
-                {
-                  prev_hscb = next_hscb;
-                  next_hscb = aic_inb(p, SCB_NEXT);
-                }
+                } /* scb_index >= p->scb_data->numscbs */
               }
               aic_outb(p, active_hscb, SCBPTR);
+              if (scb->flags & SCB_WAITINGQ)
+              {
+                scbq_remove(&p->delayed_scbs[scratch_offset], scb);
+                scbq_remove(&p->waiting_scbs, scb);
+                p->dev_active_cmds[scratch_offset]++;
+                p->activescbs++;
+              }
               scbq_insert_head(&p->delayed_scbs[scratch_offset], scb);
               p->dev_active_cmds[scratch_offset]--;
               p->activescbs--;
@@ -4014,9 +4091,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 
     case AWAITING_MSG:
       {
-        unsigned char scb_index;
+        unsigned char scb_index, msg_out;
 
         scb_index = aic_inb(p, SCB_TAG);
+        msg_out = aic_inb(p, MSG_OUT);
         scb = p->scb_data->scb_array[scb_index];
         p->msg_index = p->msg_len = 0;
         /*
@@ -4037,7 +4115,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         {
           if (scb->hscb->control & TAG_ENB)
           {
-            if (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG)
+            if (msg_out == MSG_IDENTIFYFLAG)
             {
               p->msg_buf[p->msg_index++] = scb->tag_action;
               p->msg_buf[p->msg_index++] = scb->hscb->tag;
@@ -4056,6 +4134,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         }
         else if (scb->flags & SCB_MSGOUT_WDTR)
         {
+          if ( (scb->hscb->control & TAG_ENB) &&
+               (msg_out == MSG_IDENTIFYFLAG) )
+          {
+            p->msg_buf[p->msg_index++] = scb->tag_action;
+            p->msg_buf[p->msg_index++] = scb->hscb->tag;
+            p->msg_len += 2;
+          }
           aic7xxx_construct_wdtr(p, (scb->flags & SCB_WDTR_16BIT));
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
@@ -4072,10 +4157,18 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             period = 0;
             offset = 0;
           }
+          if ( (scb->hscb->control & TAG_ENB) &&
+               (msg_out == MSG_IDENTIFYFLAG) )
+          {
+            p->msg_buf[p->msg_index++] = scb->tag_action;
+            p->msg_buf[p->msg_index++] = scb->hscb->tag;
+            p->msg_len += 2;
+          }
           aic7xxx_construct_sdtr(p, period, offset);
         }
         else 
         {
+          sti();
           panic("aic7xxx: AWAITING_MSG for an SCB that does "
                 "not have a waiting message.\n");
         }
@@ -4398,21 +4491,6 @@ aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
         p->syncinfo[scratch_offset].offset =
           (bus_width == MSG_EXT_WDTR_BUS_8_BIT) ? 
           MAX_OFFSET_8BIT : MAX_OFFSET_16BIT;
-        if ( !(p->wdtr_pending & target_mask) && !reject)
-        {
-          /*
-           * We've successfully completed the wide negotiation, so let's start
-           * up the sync negotiation now.
-           */
-          scb->flags &= ~SCB_MSGOUT_WDTR_16BIT;
-          if ((p->needsdtr & target_mask) && !(p->sdtr_pending & target_mask))
-          {
-            p->sdtr_pending |= target_mask;
-            scb->flags |= SCB_MSGOUT_SDTR;
-            aic_outb(p, HOST_MSG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-          }
-        }
         done = TRUE;
         break;
       }
@@ -4594,6 +4672,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * reset the channel again.
      */
     aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    aic7xxx_run_done_queue(p, FALSE);
     scb = NULL;
   }
   else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
@@ -4749,9 +4828,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
       }
     }
     /*
-     * Stop the selection.
+     * Restarting the sequencer will stop the selection and make sure devices
+     * are allowed to reselect in.
      */
-    aic_outb(p, 0, SCSISEQ);
     aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
     aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
@@ -5096,6 +5175,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
       aic7xxx_reset_channel(p, 1, TRUE);
       restart_sequencer(p);
     }
+    aic7xxx_run_done_queue(p, FALSE);
     aic_outb(p, CLRBRKADRINT, CLRINT);
   }
 
@@ -5108,11 +5188,8 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   {
     aic7xxx_handle_scsiint(p, intstat);
   }
-  if(!(p->flags & (AHC_IN_ABORT | AHC_IN_RESET)))
-  {
-    aic7xxx_done_cmds_complete(p);
-    aic7xxx_run_waiting_queues(p);
-  }
+  aic7xxx_done_cmds_complete(p);
+  aic7xxx_run_waiting_queues(p);
   p->flags &= ~AHC_IN_ISR;
 }
 
@@ -5306,7 +5383,13 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
+ *
+ * NOTE:  This function is only needed on Intel and Alpha platforms,
+ *   the other platforms we support don't have EISA/VLB busses.  So,
+ *   we #ifdef this entire function to avoid compiler warnings about
+ *   an unused function.
  *-F*************************************************************************/
+#if defined(__i386__) || defined(__alpha__)
 static ahc_type
 aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 {
@@ -5362,6 +5445,8 @@ aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
 
   return (AHC_NONE);
 }
+#endif /* (__i386__) || (__alpha__) */
+
 
 /*+F*************************************************************************
  * Function:
@@ -7306,7 +7391,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
     unsigned short command;
     unsigned int  devconfig, i;
 #ifdef MMAPIO
-    unsigned long page_offset;
+    unsigned long page_offset, base;
 #endif
     struct aic7xxx_host *first_7895 = NULL;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
@@ -7314,7 +7399,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
 #else
     int index;
     unsigned int piobase, mmapbase;
-    unsigned char pci_bus, pci_devfn;
+    unsigned char pci_bus, pci_devfn, pci_irq;
 #endif
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -7365,7 +7450,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
           temp_p->pci_bus = pci_bus;
           temp_p->pci_device_fn = pci_devfn;
           pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
-            &temp_p->irq);
+            &pci_irq);
+          temp_p->irq = pci_irq;
           pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
             &piobase);
           temp_p->base = piobase;
@@ -7521,7 +7607,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
             temp_p->flags |= AHC_USEDEFAULTS;
             if (sxfrctl1 & STPWEN)
               temp_p->flags |= AHC_TERM_ENB_A | AHC_TERM_ENB_B;
-            temp_p->scsi_id = temp_p->scsi_id_b = 7;
+            temp_p->scsi_id_b = temp_p->scsi_id;
           }
 
           /*
@@ -7943,7 +8029,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   }
   if ( (p->needwdtr & mask) &&
       !(p->wdtr_pending & mask) &&
-      !(scb->tag_action))
+       (scb->cmd->lun == 0) )
   {
     p->wdtr_pending |= mask;
     hscb->control |= MK_MESSAGE;
@@ -7957,7 +8043,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     if ( (p->needsdtr & mask) &&
         !(p->sdtr_pending & mask) &&
         !(p->wdtr_pending & mask) &&
-        !(scb->tag_action) )
+         (scb->cmd->lun == 0) )
     {
       p->sdtr_pending |= mask;
       hscb->control |= MK_MESSAGE;
@@ -8224,9 +8310,6 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
     { 
       if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
-        /* Send the abort message to the active SCB. */
-        aic_outb(p, HOST_MSG, MSG_OUT);
-        aic_outb(p, lastphase | ATNO, SCSISIGO);
         if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
           printk(INFO_LEAD "Device reset message in "
                 "message buffer\n", p->host_no, CTL_OF_SCB(scb));
@@ -8236,6 +8319,9 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
                 ~DEVICE_SUCCESS;
         p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
                 BUS_DEVICE_RESET_PENDING;
+        /* Send the abort message to the active SCB. */
+        aic_outb(p, HOST_MSG, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
         return(SCSI_RESET_PENDING);
       }
       else
@@ -8594,9 +8680,12 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
         if ( prev_hscbptr == SCB_LIST_NULL )
         {
             aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
-            aic_outb(p, 0, SCSISEQ);    /* stop the selection since we just
-                                         * grabbed the scb out from under the
-                                         * card */
+            /* stop the selection since we just
+             * grabbed the scb out from under the
+             * card
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
         }
         else
         {
@@ -8932,6 +9021,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
         p->msg_index = 0;
         p->msg_len = 0;
       }
+      aic7xxx_run_done_queue(p, TRUE);
       p->flags &= ~AHC_IN_RESET;
       /*  We can't rely on run_waiting_queues to unpause the sequencer for
        *  PCI based controllers since we use AAP */
index 8e2ef88cd41605233039c1f7c12229cec7669370..d951420643d78ebc10b2e320491944e4a2ab9934 100644 (file)
@@ -94,23 +94,23 @@ struct proc_dir_entry proc_scsi_dtc = {
 
 
 static struct override {
-   unsigned char *address;
+   __u32 address;
    int irq;
 } overrides
 #ifdef OVERRIDE
 [] = OVERRIDE;
 #else
-[4] = {{NULL, IRQ_AUTO}, {NULL, IRQ_AUTO}, {NULL, IRQ_AUTO},
-     {NULL, IRQ_AUTO}};
+[4] = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, {0, IRQ_AUTO},
+       {0, IRQ_AUTO}};
 #endif
 
 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 
 static struct base {
-   unsigned char *address;
+   __u32 address;
    int noauto;
-} bases[] = {{(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0},
-{(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}};
+} bases[] = {{0xcc000, 0}, {0xc8000, 0},
+{0xdc000, 0}, {0xd8000, 0}};
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
@@ -138,10 +138,10 @@ void dtc_setup(char *str, int *ints) {
       printk("dtc_setup: usage dtc=address,irq\n");
    else
       if (commandline_current < NO_OVERRIDES) {
-      overrides[commandline_current].address = (unsigned char *) ints[1];
+      overrides[commandline_current].address = ints[1];
       overrides[commandline_current].irq = ints[2];
       for (i = 0; i < NO_BASES; ++i)
-        if (bases[i].address == (unsigned char *) ints[1]) {
+        if (bases[i].address == ints[1]) {
         bases[i].noauto = 1;
         break;
       }
index eafc5d3c41c39cfa523b42dbd34cdda54df89a8e..ec0ed5554b51b0eb11f5c2654f037b78a198edbd 100644 (file)
@@ -67,7 +67,7 @@
 */
 
 /*
-**     2 January 1998, version 2.5f
+**     30 January 1998, version 2.5f.1
 **
 **     Supported SCSI-II features:
 **         Synchronous negotiation
@@ -1959,7 +1959,7 @@ static    void    ncr_free_ccb    (ncb_p np, ccb_p cp, u_long t, u_long l);
 static void    ncr_getclock    (ncb_p np, int mult);
 static void    ncr_selectclock (ncb_p np, u_char scntl3);
 static ccb_p   ncr_get_ccb     (ncb_p np, u_long t,u_long l);
-static void    ncr_init        (ncb_p np, char * msg, u_long code);
+static void    ncr_init        (ncb_p np, int reset, char * msg, u_long code);
 static int     ncr_int_sbmc    (ncb_p np);
 static int     ncr_int_par     (ncb_p np);
 static void    ncr_int_ma      (ncb_p np);
@@ -5243,6 +5243,12 @@ static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
        OUTB (nc_istat, 0);
        if (enab_int)
                OUTW (nc_sien, RST);
+       /*
+       **      Enable Tolerant, reset IRQD if present and 
+       **      properly set IRQ mode, prior to resetting the bus.
+       */
+       OUTB (nc_stest3, TE);
+       OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
        OUTB (nc_scntl1, CRST);
        DELAY (100);
 
@@ -5958,16 +5964,21 @@ void ncr_wakeup (ncb_p np, u_long code)
 **==========================================================
 */
 
-void ncr_init (ncb_p np, char * msg, u_long code)
+void ncr_init (ncb_p np, int reset, char * msg, u_long code)
 {
        int     i;
 
        /*
-       **      Reset chip.
+       **      Reset chip if asked, otherwise just clear fifos.
        */
-
-       OUTB (nc_istat,  SRST);
-       DELAY (10000);
+       if (reset) {
+               OUTB (nc_istat,  SRST);
+               DELAY (10000);
+       }
+       else {
+               OUTB (nc_stest3, TE|CSF);
+               OUTONB (nc_ctest3, CLF);
+       }
 
        /*
        **      Message.
@@ -7035,7 +7046,7 @@ void ncr_exception (ncb_p np)
        */
 
        if (sist & RST) {
-               ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
+               ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET);
                return;
        };
 
@@ -7156,7 +7167,7 @@ void ncr_int_sto (ncb_p np)
                OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
                return;
        };
-       ncr_init (np, "selection timeout", HS_FAIL);
+       ncr_init (np, 1, "selection timeout", HS_FAIL);
        np->disc = 1;
 }
 
@@ -7181,11 +7192,17 @@ static int ncr_int_sbmc (ncb_p np)
 {
        u_char scsi_mode = INB (nc_stest4) & SMODE;
 
-       printf("%s: SCSI bus mode change from %x to %x, resetting ...\n",
+       printf("%s: SCSI bus mode change from %x to %x.\n",
                ncr_name(np), np->scsi_mode, scsi_mode);
 
        np->scsi_mode = scsi_mode;
-       ncr_start_reset(np, driver_setup.settle_delay);
+
+       /*
+       **      Suspend command processing for 1 second and 
+       **      reinitialize all except the chip.
+       */
+       np->settle_time = jiffies + HZ;
+       ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 
        return 1;
 }
@@ -8785,7 +8802,7 @@ static void ncr_selectclock(ncb_p np, u_char scntl3)
        OUTB(nc_stest3, HSC);           /* Halt the scsi clock          */
        OUTB(nc_scntl3, scntl3);
        OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier      */
-       OUTB(nc_stest3, 0x00);          /* Restart scsi clock           */
+       OUTB(nc_stest3, 0x00|TE);               /* Restart scsi clock           */
 }
 
 
index 9b54fc3b231a73d1732b1219a8083e9c08b145da..cc009ca6436009869d2a8f3c2f6151f2c5492040 100644 (file)
@@ -45,7 +45,7 @@
 /*
 **     Name and revision of the driver
 */
-#define SCSI_NCR_DRIVER_NAME           "ncr53c8xx - revision 2.5f"
+#define SCSI_NCR_DRIVER_NAME           "ncr53c8xx - revision 2.5f.1"
 
 /*
 **     Check supported Linux versions
index 25297a5cddc190ef5fa9e3b813e01d8b5aceb6bb..4e47775fe36b325c3ac576105ceed9c443ef03cb 100644 (file)
-/*      ppa.c   --  low level driver for the IOMEGA PPA3 
-                    parallel port SCSI host adapter.
-
-        (The PPA3 is the embedded controller in the ZIP drive.)
-
-        (c) 1995,1996 Grant R. Guenther, grant@torque.net,
-                      under the terms of the GNU Public License.
-
-*/
-
-/*      This driver was developed without the benefit of any technical
-        specifications for the interface.  Instead, a modified version of
-        DOSemu was used to monitor the protocol used by the DOS driver
-        for this adapter.  I have no idea how my programming model relates
-        to IOMEGA's design.
-
-        IOMEGA's driver does not generate linked commands.  I've never
-        observed a SCSI message byte in the protocol transactions, so
-        I am assuming that as long as linked commands are not used
-        we won't see any.  
-
-        So far, this driver has been tested with the embedded PPA3 in the
-        ZIP drive, only.   It can detect and adapt to 4- and 8-bit parallel
-        ports, but there is currently no support for EPP or ECP ports, as
-        I have been unable to make the DOS drivers work in these modes on
-        my test rig.
-
-        For more information, see the file drivers/scsi/README.ppa.
-
-*/
-
-#define   PPA_VERSION   "0.26"
-
-/* Change these variables here or with insmod or with a LILO or LOADLIN
-   command line argument
-*/
-
-static int      ppa_base       = 0x378;  /* parallel port address    */
-static int      ppa_speed_high = 1;      /* port delay in data phase */
-static int      ppa_speed_low  = 6;      /* port delay otherwise     */
-static int      ppa_nybble     = 0;      /* don't force nybble mode  */
-
-
-#define   PPA_CAN_QUEUE         1       /* use "queueing" interface */
-#define   PPA_SELECT_TMO        5000    /* how long to wait for target ? */
-#define   PPA_SPIN_TMO          5000000 /* ppa_wait loop limiter */
-#define   PPA_SECTOR_SIZE       512     /* for a performance hack only */
-
-#include  <linux/stddef.h>
-#include  <linux/module.h>
-#include  <linux/kernel.h>
-#include  <linux/tqueue.h>
-#include  <linux/ioport.h>
-#include  <linux/delay.h>
-#include  <linux/blk.h>
-#include  <linux/proc_fs.h>
-#include  <linux/stat.h>
-#include  <asm/io.h>
-#include  "sd.h"
-#include  "hosts.h"
-#include  "ppa.h"
+/* ppa.c   --  low level driver for the IOMEGA PPA3 
+ * parallel port SCSI host adapter.
+ * 
+ * (The PPA3 is the embedded controller in the ZIP drive.)
+ * 
+ * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
+ * under the terms of the GNU Public License.
+ *
+ * Current Maintainer: David Campbell (Perth, Western Australia)
+ *                     campbell@gear.torque.net
+ *                     dcampbel@p01.as17.honeywell.com.au
+ *
+ * My unoffical company acronym list is 21 pages long:
+ *      FLA:    Four letter acronym with built in facility for
+ *              future expansion to five letters.
+ */
+
+#include <linux/config.h>
+
+/* The following #define is to avoid a clash with hosts.c */
+#define PPA_CODE 1
+#ifndef HAVE_PC87332
+#define HAVE_PC87332    0
+#endif
+#define PPA_PROBE_SPP   0x0001
+#define PPA_PROBE_PS2   0x0002
+#define PPA_PROBE_ECR   0x0010
+#define PPA_PROBE_EPP17 0x0100
+#define PPA_PROBE_EPP19 0x0200
+int port_probe(unsigned short);
+
+#include <linux/blk.h>
+#include "sd.h"
+#include "hosts.h"
+typedef struct {
+    int base;                  /* Actual port address          */
+    int mode;                  /* Transfer mode                */
+    int host;                  /* Host number (for proc)       */
+    Scsi_Cmnd *cur_cmd;                /* Current queued command       */
+    struct tq_struct ppa_tq;   /* Polling interupt stuff       */
+    unsigned long jstart;      /* Jiffies at start             */
+    unsigned failed:1;         /* Failure flag                 */
+} ppa_struct;
+
+#define PPA_EMPTY \
+{-1,            /* base */      \
+PPA_AUTODETECT, /* mode */      \
+-1,             /* host */      \
+NULL,           /* cur_cmd */   \
+{0, 0, ppa_interrupt, NULL},    \
+0,              /* jstart */    \
+0               /* failed */    \
+}
 
-struct proc_dir_entry proc_scsi_ppa = 
-                { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 };
+#include "ppa.h"
+#undef CONFIG_PARPORT
+#define NO_HOSTS 4
+static ppa_struct ppa_hosts[NO_HOSTS] =
+{PPA_EMPTY, PPA_EMPTY, PPA_EMPTY, PPA_EMPTY};
 
-static int              ppa_abort_flag = 0;
-static int              ppa_error_code = DID_OK;
-static char             ppa_info_string[132];
-static Scsi_Cmnd        *ppa_current = 0;
-static void             (*ppa_done) (Scsi_Cmnd *);
-static int              ppa_port_delay;
+#define PPA_BASE(x)    ppa_hosts[(x)].base
 
-void    out_p( short port, char byte)
+int base[NO_HOSTS] =
+{0x03bc, 0x0378, 0x0278, 0x0000};
+#define parbus_base    base
+#define parbus_no      NO_HOSTS
 
-{       outb(byte,ppa_base+port);
-        udelay(ppa_port_delay);
+static inline int ppa_pb_claim(int host_no)
+{
+    if (ppa_hosts[host_no].cur_cmd)
+       ppa_hosts[host_no].cur_cmd->SCp.phase++;
+    return 0;
 }
 
-char    in_p( short port)
-
-{       return inb(ppa_base+port);
-        udelay(ppa_port_delay);
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+  
+#ifndef MODULE
+/*
+ * Command line parameters (for built-in driver):
+ *
+ * Syntax:  ppa=base[,mode[,use_sg]]
+ *
+ * For example:  ppa=0x378   or   ppa=0x378,0,3
+ *
+ */
+
+void ppa_setup(char *str, int *ints)
+{
+    static int x = 0;
+
+    if (x == 0) {              /* Disable ALL known ports */
+       int i;
+
+       for (i = 0; i < NO_HOSTS; i++)
+           parbus_base[i] = 0x0000;
+    }
+    switch (ints[0]) {
+    case 3:
+       ppa_sg = ints[3];
+    case 2:
+       ppa_hosts[x].mode = ints[2];
+       parbus_base[x] = ints[1];
+       break;
+    default:
+       printk("PPA: I only use between 2 to 3 parameters.\n");
+       break;
+    }
+    x++;
+  }
+#else
+Scsi_Host_Template driver_template = PPA;
+#include  "scsi_module.c"
+#endif
+  
+/*
+ * Start of Chipset kludges
+ */
+
+#if HAVE_PC87332 > 0
+#warning PC87332 Kludge code included
+static inline int pc87332_port(int host_no)
+{
+    /* A routine to detect and kludge pc87332 chipsets into the
+     * "optimum" mode for parallel port data transfer.
+     * This assumes EPP is better than ECP...
+     * (Which it is for disk drives but not printers and scanners)
+     */
+    int base = ppa_hosts[host_no].base;
+
+    /* This is where an pc87332 can hide */
+    unsigned short index_addr[4] =
+    {
+       0x0398, 0x026e, 0x015c, 0x002e
+    };
+
+    /* Bits 0&1 of FAR (Function Address Register) which specify where
+     * the LPT port will show up at.
+     */
+    unsigned short port_ref[4] =
+    {
+       0x378, 0x3bc, 0x278, 0xffff
+    };
+
+    unsigned char a;
+    int loop;
+
+    for (loop = 0; loop < 4; loop++) {
+       /* Clear the "wax" out of the pc87332, only needed after hard
+        * reset.
+        */
+       inb(index_addr[loop]);
+       inb(index_addr[loop]);
+       inb(index_addr[loop]);
+       inb(index_addr[loop]);
+
+       /* Anyone home ?? */
+       outb(0xff, index_addr[loop]);
+       a = inb(index_addr[loop]);
+       switch (a) {
+       case (0x0f):            /* PC87732 */
+           break;
+       case (0x1f):            /* PC87306 */
+           break;
+       case (0x7f):            /* PC87??? */
+           break;
+       default:
+           continue;
+       }                       /* Is this pc87332 on the desired port */
+       outb(0x01, index_addr[loop]);
+       a = inb(index_addr[loop] + 1);
+       if (port_ref[a & 0x03] != base)
+           continue;
+
+       /* Found a pc87332 */
+       printk("NatSemi PC87332 (or variant) at 0x%04x\n", base);
+
+       /* Try to enable EPP modes
+        * with hardware data direction
+        */
+       if (base != 0x3bc) {
+           /* EPP 1.9 */
+           outb(0x04, index_addr[loop]);
+           a = inb(index_addr[loop] + 1);
+           printk("Old reg1 = %02x\n", a);
+           /* 0x01 for EPP 1.7, 0x03 for EPP 1.9, 0x0c for ECP */
+           a = (a & 0xf0) | 0x03;
+           outb(a, index_addr[loop] + 1);
+           outb(a, index_addr[loop] + 1);
+
+           /* Software data direction selection */
+           outb(0x02, index_addr[loop]);
+           a = inb(index_addr[loop] + 1);
+           printk("Old reg2 = %02x\n", a);
+           /* 0x80 for software, 0x00 for hardware */
+           a = (a & 0x7f) | 0x80;
+           outb(a, index_addr[loop] + 1);
+           outb(a, index_addr[loop] + 1);
+           ppa_hosts[host_no].mode = PPA_EPP_32;
+       } else {
+           /* There is not enough address space for the 0x3bc port
+            * to have EPP registers so we will kludge it into an
+            * ECP
+            * port to allow bi-directional byte mode...
+            */
+           /* ECP */
+           outb(0x04, index_addr[loop]);
+           a = inb(index_addr[loop] + 1);
+           a = (a & 0xfb) | 0x06;
+           outb(a, index_addr[loop] + 1);
+           outb(a, index_addr[loop] + 1);
+           ppa_hosts[host_no].mode = PPA_PS2;
+       }
+
+       outb(0x04, index_addr[loop]);
+       a = inb(index_addr[loop] + 1);
+       return ppa_hosts[host_no].mode;
+    }
+    return 0;
+  }
+#else
+#define pc87332_port(x)
+#endif                         /* HAVE_PC87332 */
+  
+static inline int generic_port(int host_no)
+{
+    /* Generic parallel port detection
+     * This will try to discover if the port is
+     * EPP, ECP, PS/2 or NIBBLE (In that order, approx....)
+     */
+    unsigned int save_ctr, save_ecr, r;
+    int ppb = PPA_BASE(host_no);
+
+    save_ctr = r_ctr(ppb);
+    save_ecr = r_ecr(ppb);
+    r = port_probe(ppb);
+    w_ecr(ppb, save_ecr);
+    w_ctr(ppb, save_ctr);
+
+    if (r & PPA_PROBE_SPP)
+       ppa_hosts[host_no].mode = PPA_NIBBLE;
+
+    if (r & PPA_PROBE_PS2) {
+       ppa_hosts[host_no].mode = PPA_PS2;
+       if (r & PPA_PROBE_ECR)
+           w_ecr(ppb, 0x20);
+    }
+    if ((r & PPA_PROBE_EPP17) || (r & PPA_PROBE_EPP19)) {
+       /* ppa_hosts[host_no].mode = PPA_EPP_32; */
+       if (r & PPA_PROBE_ECR)
+           w_ecr(ppb, 0x80);
+    }
+    return ppa_hosts[host_no].mode;
 }
 
-void    ppa_d_pulse( char b )
-
-{       out_p(0,b);
-        out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc);
+int ppa_detect(Scsi_Host_Template * host)
+{
+    struct Scsi_Host *hreg;
+    int ports;
+    int i, nhosts;
+    unsigned short ppb;
+
+    printk("ppa: Version %s\n", PPA_VERSION);
+    nhosts = 0;
+
+    for (i = 0; i < parbus_no; i++) {
+       if (parbus_base[i] == 0x0000)
+           continue;
+       ppb = ppa_hosts[i].base = parbus_base[i];
+
+       /* sanity checks */
+       if (check_region(parbus_base[i],
+                        (parbus_base[i] == 0x03bc) ? 3 : 8))
+           continue;
+
+       pc87332_port(i);
+       if (!generic_port(i))
+           continue;
+
+       if (ppa_init(i))
+           continue;
+
+       /* now the glue ... */
+       switch (ppa_hosts[i].mode) {
+       case PPA_NIBBLE:
+       case PPA_PS2:
+           ports = 3;
+           break;
+       case PPA_EPP_8:
+       case PPA_EPP_16:
+       case PPA_EPP_32:
+           ports = 8;
+           break;
+       default:                /* Never gets here */
+           continue;
+       }
+       request_region(ppa_hosts[i].base, ports, "ppa");
+       host->can_queue = PPA_CAN_QUEUE;
+       host->sg_tablesize = ppa_sg;
+       hreg = scsi_register(host, 0);
+       hreg->io_port = ppa_hosts[i].base;
+       hreg->n_io_port = ports;
+       hreg->dma_channel = -1;
+       hreg->unique_id = i;
+       ppa_hosts[i].host = hreg->host_no;
+       nhosts++;
+    }
+    if (nhosts == 0)
+       return 0;
+    else
+       return 1;               /* return number of hosts detected */
 }
 
-void    ppa_disconnect( void )
-
-{       ppa_d_pulse(0);
-        ppa_d_pulse(0x3c);
-        ppa_d_pulse(0x20);
-        ppa_d_pulse(0xf);
+/* This is to give the ppa driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/ppa/0 file.
+ * Very simple method really... (To simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+
+static inline int ppa_strncmp(const char *a, const char *b, int len)
+{
+    int loop;
+    for (loop = 0; loop < len; loop++)
+       if (a[loop] != b[loop])
+           return 1;
+
+    return 0;
 }
-
-void    ppa_c_pulse( char b )
-
-{       out_p(0,b);
-        out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc);
+static inline int ppa_proc_write(int hostno, char *buffer, int length)
+{
+    unsigned long x;
+
+    if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) {
+       x = simple_strtoul(buffer + 5, NULL, 0);
+       ppa_hosts[hostno].mode = x;
+       return length;
+    }
+    printk("ppa /proc: invalid variable\n");
+    return (-EINVAL);
 }
 
-void    ppa_connect( void )
-
-{       ppa_c_pulse(0);
-        ppa_c_pulse(0x3c);
-        ppa_c_pulse(0x20);
-        ppa_c_pulse(0x8f);
+int ppa_proc_info(char *buffer, char **start, off_t offset,
+                 int length, int hostno, int inout)
+{
+    int i;
+    int len = 0;
+
+    for (i = 0; i < 4; i++)
+       if (ppa_hosts[i].host == hostno)
+           break;
+
+    if (inout)
+       return ppa_proc_write(i, buffer, length);
+
+    len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
+    len += sprintf(buffer + len, "Port    : 0x%04x\n", ppa_hosts[i].base);
+    len += sprintf(buffer + len, "Mode    : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
+
+    /* Request for beyond end of buffer */
+    if (offset > len)
+       return 0;
+
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+       len = length;
+    return len;
+}                              /* end of ppa.c */
+static int device_check(int host_no);
+
+#if PPA_DEBUG > 0
+#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
+          y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+static inline void ppa_fail_func(int host_no, int error_code)
+#else
+static inline void ppa_fail(int host_no, int error_code)
+  #endif
+{
+    /* If we fail a device then we trash status / message bytes */
+    if (ppa_hosts[host_no].cur_cmd) {
+       ppa_hosts[host_no].cur_cmd->result = error_code << 16;
+       ppa_hosts[host_no].failed = 1;
+    }
 }
 
-void    ppa_do_reset( void )
-
-{       out_p(2,0);             /* This is really just a guess */
-        udelay(100);
+/*
+ * Wait for the high bit to be set.
+ * 
+ * In principle, this could be tied to an interrupt, but the adapter
+ * doesn't appear to be designed to support interrupts.  We spin on
+ * the 0x80 ready bit. 
+ */
+static unsigned char ppa_wait(int host_no)
+{
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char r;
+
+    k = PPA_SPIN_TMO;
+    do {
+       r = r_str(ppb);
+       k--;
+       udelay(1);
+    }
+    while (!(r & 0x80) && (k));
+
+    /*
+     * return some status information.
+     * Semantics: 0xc0 = ZIP wants more data
+     *            0xd0 = ZIP wants to send more data
+     *            0xe0 = ZIP is expecting SCSI command data
+     *            0xf0 = end of transfer, ZIP is sending status
+     */
+    if (k)
+       return (r & 0xf0);
+
+    /* Counter expired - Time out occured */
+    ppa_fail(host_no, DID_TIME_OUT);
+    printk("ppa timeout in ppa_wait\n");
+    return 0;                  /* command timed out */
 }
 
-char    ppa_select( int  initiator, int target )
-
-{       char    r;
-        int     k;
-
-        r = in_p(1);
-        out_p(0,(1<<target)); out_p(2,0xe); out_p(2,0xc);
-        out_p(0,(1<<initiator)); out_p(2,0x8);
-
-        k = 0;
-        while ( !(r = (in_p(1) & 0xf0)) && (k++ < PPA_SELECT_TMO)) barrier();
-        return r;
+/*
+ * output a string, in whatever mode is available, according to the
+ * PPA protocol. 
+ */
+static inline void epp_reset(unsigned short ppb)
+{
+    int i;
+
+    i = r_str(ppb);
+    w_str(ppb, i);
+    w_str(ppb, i & 0xfe);
 }
 
-char    ppa_wait( void ) 
-
-/*      Wait for the high bit to be set.
+static inline void ecp_sync(unsigned short ppb)
+{
+    int i;
 
-        In principle, this could be tied to an interrupt, but the adapter
-        doesn't appear to be designed to support interrupts.  We spin on
-        the 0x80 ready bit. 
-*/
+    if ((r_ecr(ppb) & 0xe0) != 0x80)
+       return;
 
-{       int     k;
-        char    r;
-
-        ppa_error_code = DID_OK;
-        k = 0;
-        while (!((r = in_p(1)) & 0x80) 
-                && (k++ < PPA_SPIN_TMO) && !ppa_abort_flag  ) barrier();
-                        
-        if (ppa_abort_flag) {
-                if (ppa_abort_flag == 1) ppa_error_code = DID_ABORT;
-                else {  ppa_do_reset();
-                        ppa_error_code = DID_RESET;
-                }
-                ppa_disconnect();
-                return 0;
-        }
-        if (k >= PPA_SPIN_TMO) { 
-                ppa_error_code = DID_TIME_OUT;
-                ppa_disconnect();
-                return 0;               /* command timed out */
-        }
-        return (r & 0xf0);
+    for (i = 0; i < 100; i++) {
+       if (r_ecr(ppb) & 0x01)
+           return;
+       udelay(5);
+    }
+    printk("ppa: ECP sync failed as data still present in FIFO.\n");
 }
 
-int     ppa_init( void )
-
-/* This is based on a trace of what the Iomega DOS 'guest' driver does.
-   I've tried several different kinds of parallel ports with guest and
-   coded this to react in the same ways that it does.
+/*
+ * Here is the asm code for the SPP/PS2 protocols for the i386.
+ * This has been optimised for speed on 386/486 machines. There will
+ * be very little improvement on the current 586+ machines as it is the
+ * IO statements which will limit throughput.
+ */
+#ifdef __i386__
+#define BYTE_OUT(reg) \
+       "       movb " #reg ",%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       addl $2,%%edx\n" \
+       "       movb $0x0e,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       movb $0x0c,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       subl $2,%%edx\n"
+
+static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_bo\n" \
+       "       .align 4\n" \
+       ".loop_bulk_bo:\n" \
+       "       movl (%%esi),%%ebx\n" \
+       BYTE_OUT(%%bl) \
+       BYTE_OUT(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       BYTE_OUT(%%bl) \
+       BYTE_OUT(%%bh) \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_bo\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_bo:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_bo\n" \
+       "       .align 4\n" \
+       ".loop_loose_bo:\n" \
+       BYTE_OUT((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_bo\n" \
+       ".no_more_loose_bo:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
+}
 
-   The return value from this function is just a hint about where the
-   handshaking failed.
+#define BYTE_IN(reg) \
+       "       inb (%%dx),%%al\n" \
+       "       movb %%al," #reg "\n" \
+       "       addl $2,%%edx\n" \
+       "       movb $0x27,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       movb $0x25,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       subl $2,%%edx\n"
+
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_bi\n" \
+       "       .align 4\n" \
+       ".loop_bulk_bi:\n" \
+       BYTE_IN(%%bl) \
+       BYTE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       BYTE_IN(%%bl) \
+       BYTE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       "       movl %%ebx,(%%esi)\n" \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_bi\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_bi:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_bi\n" \
+       "       .align 4\n" \
+       ".loop_loose_bi:\n" \
+       BYTE_IN((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_bi\n" \
+       ".no_more_loose_bi:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
+}
 
-*/
+#define NIBBLE_IN(reg) \
+       "       incl %%edx\n" \
+       "       movb $0x04,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       decl %%edx\n" \
+       "       inb (%%dx),%%al\n" \
+       "       andb $0xf0,%%al\n" \
+       "       movb %%al," #reg "\n" \
+       "       incl %%edx\n" \
+       "       movb $0x06,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       decl %%edx\n" \
+       "       inb (%%dx),%%al\n" \
+       "       shrb $4,%%al\n" \
+       "       orb %%al," #reg "\n"
+
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+{
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_ni\n" \
+       "       .align 4\n" \
+       ".loop_bulk_ni:\n" \
+       NIBBLE_IN(%%bl) \
+       NIBBLE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       NIBBLE_IN(%%bl) \
+       NIBBLE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       "       movl %%ebx,(%%esi)\n" \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_ni\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_ni:" \
+  : "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_ni\n" \
+       "       .align 4\n" \
+       ".loop_loose_ni:\n" \
+       NIBBLE_IN((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_ni\n" \
+       ".no_more_loose_ni:\n" \
+  : /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
+}
+#else                          /* Old style C routines */
+
+static inline int ppa_byte_out(unsigned short base, const char *buffer, int len)
+{
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+       outb(*buffer++, base);
+       outb(0xe, ctr_p);
+       outb(0xc, ctr_p);
+    }
+    return 1;                  /* All went well - we hope! */
+}
 
-{       char    r, s;
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
+{
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+       *buffer++ = inb(base);
+       outb(0x27, ctr_p);
+       outb(0x25, ctr_p);
+    }
+    return 1;                  /* All went well - we hope! */
+}
 
-        out_p(0,0xaa); 
-        if (in_p(0) != (char) 0xaa) return 1; 
-        ppa_disconnect();
-        ppa_connect();
-        out_p(2,0x6); 
-        if ((in_p(1) & 0xf0) != 0xf0) return 2; 
-        out_p(2,0x4);
-        if ((in_p(1) & 0xf0) != 0x80) return 3; 
-        ppa_disconnect();
-        s = in_p(2);
-        out_p(2,0xec);
-        out_p(0,0x55); 
-        r = in_p(0);    
-        if (r != (char) 0xff) { 
-                ppa_nybble = 1;
-                if (r != (char) 0x55) return 4; 
-                out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5; 
-        }
-        out_p(2,s);
-        ppa_connect();
-        out_p(0,0x40); out_p(2,0x8); out_p(2,0xc);
-        ppa_disconnect();
-
-        return 0;
-}
-
-int     ppa_start( Scsi_Cmnd * cmd )
-
-{       int     k;
-
-        ppa_error_code = DID_OK;
-        ppa_abort_flag = 0;
-
-        if (cmd->target == PPA_INITIATOR) {
-                ppa_error_code = DID_BAD_TARGET;
-                return 0;
-        }
-        ppa_connect();
-        if (!ppa_select(PPA_INITIATOR,cmd->target)) {
-                ppa_disconnect();
-                ppa_error_code = DID_NO_CONNECT;
-                return 0;
-        }
-        out_p(2,0xc);
-
-        for (k=0; k < cmd->cmd_len; k++) {        /* send the command */
-                if (!ppa_wait()) return 0;
-                out_p(0,cmd->cmnd[k]);
-                out_p(2,0xe);
-                out_p(2,0xc);
-        }
-
-#ifdef PPA_DEBUG
-        printk("PPA: command out: ");
-        for (k=0; k < cmd->cmd_len; k++)
-                printk("%3x",(cmd->cmnd[k]) & 0xff );
-        printk("\n");
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+{
+    unsigned short ctr_p = str_p + 1;
+    unsigned char h, l;
+    int i;
+
+    for (i = len; i; i--) {
+       outb(0x4, ctr_p);
+       h = inb(str_p);
+       outb(0x6, ctr_p);
+       l = inb(str_p);
+       *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
+    }
+    return 1;                  /* All went well - we hope! */
+  }
+  #endif
+  
+static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--) {
+       outb(*buffer++, epp_p);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+       if (inb(str_p) & 0x01)
+           return 0;
+  #endif
+    }
+    return 1;
+  }
+  
+static int ppa_out(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    r = ppa_wait(host_no);
+
+    if ((r & 0x50) != 0x40) {
+       ppa_fail(host_no, DID_ERROR);
+       return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+    case PPA_PS2:
+       /* 8 bit output, with a loop */
+       r = ppa_byte_out(ppb, buffer, len);
+       break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+       epp_reset(ppb);
+       w_ctr(ppb, 0x4);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+       r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);
+#else
+       if (!(((long) buffer | len) & 0x03))
+           outsl(ppb + 4, buffer, len >> 2);
+       else
+           outsb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0xc);
+       r = !(r_str(ppb) & 0x01);
 #endif
-
-        return 1;
+       w_ctr(ppb, 0xc);
+       ecp_sync(ppb);
+       break;
+
+    default:
+       printk("PPA: bug in ppa_out()\n");
+       r = 0;
+    }
+    return r;
 }
 
-int     ppa_completion( Scsi_Cmnd * cmd )
-
-/* The bulk flag enables some optimisations in the data transfer loops,
-   it should be true for any command that transfers data in integral
-   numbers of sectors.
-
-   The driver appears to remain stable if we speed up the parallel port
-   i/o in this function, but not elsewhere.
-*/
-
-{       char    r, l, h, v;
-        int     dir, cnt, blen, fast, bulk;
-        char    *buffer;
-
-#ifdef PPA_DEBUG
-        int     k;
+static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--) {
+       *buffer++ = inb(epp_p);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+       if (inb(str_p) & 0x01)
+           return 0;
 #endif
-
-        if (!(r = ppa_wait())) return 0;
-        v = cmd->cmnd[0];
-        bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10));
-        buffer = cmd->request_buffer;
-        blen = cmd->request_bufflen;
-        cnt = 0;  dir = 0;
-        if (r == (char) 0xc0) dir = 1;  /* d0 = read c0 = write f0 = status */
-
-        ppa_port_delay = ppa_speed_high;
-
-        while (r != (char) 0xf0) {
-                if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) {
-                        ppa_disconnect();
-                        ppa_error_code = DID_ERROR;
-                        return 0;
-                }
-                fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE);
-                if (dir) do {
-                        out_p(0,buffer[cnt++]);
-                        out_p(2,0xe); out_p(2,0xc);
-                        if (!fast) break;
-                } while (cnt % PPA_SECTOR_SIZE);
-                else {  
-                        if (ppa_nybble) do {
-                                out_p(2,0x4); h = in_p(1); 
-                                out_p(2,0x6); l = in_p(1);
-                                v = ((l >> 4) & 0x0f) + (h & 0xf0);
-                                buffer[cnt++] = v;
-                                if (!fast) break;
-                        } while (cnt % PPA_SECTOR_SIZE);
-                        else do {
-                                out_p(2,0x25); v = in_p(0); out_p(2,0x27);
-                                buffer[cnt++] = v;
-                                if (!fast) break;
-                        } while (cnt % PPA_SECTOR_SIZE);
-                        if (!ppa_nybble) {
-                                out_p(2,0x5); out_p(2,0x4);
-                        }
-                        out_p(2,0xc);
-                }
-                if (!(r = ppa_wait())) return 0;
-        }
-
-        ppa_port_delay = ppa_speed_low;
-
-        out_p(2,0x4);            /* now read status byte */
-        h = in_p(1);
-        out_p(2,0x6);
-        l = in_p(1);
-        out_p(2,0xc);
-        r = ((l >> 4) & 0x0f) + (h & 0xf0);
-
-        out_p(2,0xe); out_p(2,0xc);
-        ppa_disconnect();
-
-#ifdef PPA_DEBUG
-        printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt);
-        if (cnt > 12) cnt = 12;
-        for (k=0; k < cnt; k++)
-           printk("%3x",buffer[k] & 0xff );
-        printk("\n");   
+    }
+    return 1;
+  }
+  
+static int ppa_in(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    r = ppa_wait(host_no);
+
+    if ((r & 0x50) != 0x50) {
+       ppa_fail(host_no, DID_ERROR);
+       return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+       /* 4 bit input, with a loop */
+       r = ppa_nibble_in(ppb + 1, buffer, len);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case PPA_PS2:
+       /* 8 bit input, with a loop */
+       w_ctr(ppb, 0x25);
+       r = ppa_byte_in(ppb, buffer, len);
+       w_ctr(ppb, 0x4);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+       epp_reset(ppb);
+       w_ctr(ppb, 0x24);
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+       r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);
+  #else
+       if (!(((long) buffer | len) & 0x03))
+           insl(ppb + 4, buffer, len >> 2);
+       else
+           insb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0x2c);
+       r = !(r_str(ppb) & 0x01);
 #endif
-
-        return (r & STATUS_MASK);
+       w_ctr(ppb, 0x2c);
+       ecp_sync(ppb);
+       break;
+
+    default:
+       printk("PPA: bug in ppa_ins()\n");
+       r = 0;
+       break;
+    }
+    return r;
 }
 
-/* deprecated synchronous interface */
-
-int     ppa_command( Scsi_Cmnd * cmd )
-
-{       int     s;
-
-        sti();
-        s = 0;
-        if (ppa_start(cmd))
-           if (ppa_wait()) 
-               s = ppa_completion(cmd);
-        return s + (ppa_error_code << 16);
+/* end of ppa_io.h */
+static inline void ppa_d_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
 }
 
-/* pseudo-interrupt queueing interface */
-
-/* Since the PPA itself doesn't generate interrupts, we use
-   the scheduler's task queue to generate a stream of call-backs and
-   complete the request when the drive is ready.
-*/
-
-static void ppa_interrupt( void *data);
-
-static struct tq_struct ppa_tq = {0,0,ppa_interrupt,NULL};
-
-static void ppa_interrupt( void *data)
+static void ppa_disconnect(int host_no)
+{
+    unsigned short ppb = PPA_BASE(host_no);
 
-{       Scsi_Cmnd *cmd;
-        void  (*done) (Scsi_Cmnd *);
-
-        cmd = ppa_current;
-        done = ppa_done;
-        if (!cmd) return;
-        
-        if (ppa_abort_flag) {
-                ppa_disconnect();
-                if(ppa_abort_flag == 1) cmd->result = DID_ABORT << 16;
-                else { ppa_do_reset();
-                       cmd->result = DID_RESET << 16;
-                }
-                ppa_current = 0;
-                done(cmd);
-                return;
-        }
-        if (!( in_p(1) & 0x80)) {
-                queue_task(&ppa_tq,&tq_scheduler);
-                return;
-        }
-        cmd->result = ppa_completion(cmd) + (ppa_error_code << 16);
-        ppa_current = 0;
-        done(cmd);
-        return;
+    ppa_d_pulse(ppb, 0);
+    ppa_d_pulse(ppb, 0x3c);
+    ppa_d_pulse(ppb, 0x20);
+    ppa_d_pulse(ppb, 0xf);
 }
 
-int     ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-
-{       if (ppa_current) return 0;
-        sti();
-        ppa_current = cmd;
-        ppa_done = done;
-        if (!ppa_start(cmd)) {
-                cmd->result = ppa_error_code << 16;
-                ppa_current = 0;
-                done(cmd);
-                return 0;
-        }
-        queue_task(&ppa_tq,&tq_scheduler);
-        return 0;
+static inline void ppa_c_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0x6);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
 }
 
-int     ppa_detect( Scsi_Host_Template * host )
-
-{       struct  Scsi_Host       *hreg;
-        int     rs;
-
-        host->proc_dir = &proc_scsi_ppa;
-
-        /* can we have the ports ? */
-
-        if (check_region(ppa_base,3)) {
-                printk("PPA: ports at 0x%3x are not available\n",ppa_base);
-                return 0;
-        }
-
-        /* attempt to initialise the controller */
-
-        ppa_port_delay = ppa_speed_low;
-
-        rs = ppa_init();
-        if (rs) {
-            printk("PPA: unable to initialise controller at 0x%x, error %d\n",
-                   ppa_base,rs);
-            return 0;
-        }
-
-        /* now the glue ... */
-
-        request_region(ppa_base,3,"ppa");
-
-        host->can_queue = PPA_CAN_QUEUE;
-
-        hreg = scsi_register(host,0);
-        hreg->io_port = ppa_base;
-        hreg->n_io_port = 3;
-        hreg->dma_channel = -1;
+static inline void ppa_connect(int host_no, int flag)
+{
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_c_pulse(ppb, 0);
+    ppa_c_pulse(ppb, 0x3c);
+    ppa_c_pulse(ppb, 0x20);
+    if ((flag == CONNECT_EPP_MAYBE) &&
+       IN_EPP_MODE(ppa_hosts[host_no].mode))
+       ppa_c_pulse(ppb, 0xcf);
+    else
+       ppa_c_pulse(ppb, 0x8f);
+}
 
-        sprintf(ppa_info_string,
-                "PPA driver version %s using %d-bit mode on port 0x%x.",
-                PPA_VERSION,8-ppa_nybble*4,ppa_base);
-        host->name = ppa_info_string;
+static int ppa_select(int host_no, int target)
+{
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    /*
+     * Bit 6 (0x40) is the device selected bit.
+     * First we must wait till the current device goes off line...
+     */
+    k = PPA_SELECT_TMO;
+    do {
+       k--;
+    } while ((r_str(ppb) & 0x40) && (k));
+    if (!k)
+       return 0;
+
+    w_dtr(ppb, (1 << target));
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_dtr(ppb, 0x80);          /* This is NOT the initator */
+    w_ctr(ppb, 0x8);
+
+    k = PPA_SELECT_TMO;
+    do {
+       k--;
+    }
+    while (!(r_str(ppb) & 0x40) && (k));
+    if (!k)
+       return 0;
+
+    return 1;
+}
 
-        return 1;       /* 1 host detected */
+/* 
+ * This is based on a trace of what the Iomega DOS 'guest' driver does.
+ * I've tried several different kinds of parallel ports with guest and
+ * coded this to react in the same ways that it does.
+ * 
+ * The return value from this function is just a hint about where the
+ * handshaking failed.
+ * 
+ */
+static int ppa_init(int host_no)
+{
+    int retv;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_disconnect(host_no);
+    ppa_connect(host_no, CONNECT_NORMAL);
+
+    retv = 2;                  /* Failed */
+
+    w_ctr(ppb, 0xe);
+    if ((r_str(ppb) & 0x08) == 0x08)
+       retv--;
+
+    w_ctr(ppb, 0xc);
+    if ((r_str(ppb) & 0x08) == 0x00)
+       retv--;
+
+    /* This is a SCSI BUS reset signal */
+    if (!retv) {
+       w_dtr(ppb, 0x40);
+       w_ctr(ppb, 0x08);
+       udelay(30);
+       w_ctr(ppb, 0x0c);
+       udelay(1000);           /* Allow devices to settle down */
+    }
+    ppa_disconnect(host_no);
+    udelay(1000);              /* Another delay to allow devices to settle */
+
+    if (!retv)
+       retv = device_check(host_no);
+
+    return retv;
 }
 
-int     ppa_biosparam( Disk * disk, kdev_t dev, int ip[])
+static inline int ppa_send_command(Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    int k;
 
-/*  Apparently the the disk->capacity attribute is off by 1 sector 
-    for all disk drives.  We add the one here, but it should really
-    be done in sd.c.  Even if it gets fixed there, this will still
-    work.
-*/
+    w_ctr(PPA_BASE(host_no), 0x0c);
 
-{       ip[0] = 0x40;
-        ip[1] = 0x20;
-        ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
-        if (ip[2] > 1024) {
-                ip[0] = 0xff;
-                ip[1] = 0x3f;
-                ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
-                if (ip[2] > 1023)
-                        ip[2] = 1023;
-        }
-        return 0;
+    for (k = 0; k < cmd->cmd_len; k++)
+       if (!ppa_out(host_no, &cmd->cmnd[k], 1))
+           return 0;
+    return 1;
 }
 
-int     ppa_abort( Scsi_Cmnd * cmd )
-
-{       ppa_abort_flag = 1;
-        return SCSI_ABORT_SNOOZE;
+/*
+ * The bulk flag enables some optimisations in the data transfer loops,
+ * it should be true for any command that transfers data in integral
+ * numbers of sectors.
+ * 
+ * The driver appears to remain stable if we speed up the parallel port
+ * i/o in this function, but not elsewhere.
+ */
+static int ppa_completion(Scsi_Cmnd * cmd)
+{
+    /* Return codes:
+     * -1     Error
+     *  0     Told to schedule
+     *  1     Finished data transfer
+     */
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned long start_jiffies = jiffies;
+
+    unsigned char r, v;
+    int fast, bulk, status;
+
+    v = cmd->cmnd[0];
+    bulk = ((v == READ_6) ||
+           (v == READ_10) ||
+           (v == WRITE_6) ||
+           (v == WRITE_10));
+
+    /*
+     * We only get here if the drive is ready to comunicate,
+     * hence no need for a full ppa_wait.
+     */
+    r = (r_str(ppb) & 0xf0);
+
+    while (r != (unsigned char) 0xf0) {
+       /*
+        * If we have been running for more than a full timer tick
+        * then take a rest.
+        */
+       if (jiffies > start_jiffies + 1)
+           return 0;
+
+       if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+           ppa_fail(host_no, DID_ERROR);
+           return -1;          /* ERROR_RETURN */
+       }
+       /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+           ? PPA_BURST_SIZE : 1;
+
+       if (r == (unsigned char) 0xc0)
+           status = ppa_out(host_no, cmd->SCp.ptr, fast);
+       else
+           status = ppa_in(host_no, cmd->SCp.ptr, fast);
+
+       cmd->SCp.ptr += fast;
+       cmd->SCp.this_residual -= fast;
+
+       if (!status) {
+           ppa_fail(host_no, DID_BUS_BUSY);
+           return -1;          /* ERROR_RETURN */
+       }
+       if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+           /* if scatter/gather, advance to the next segment */
+           if (cmd->SCp.buffers_residual--) {
+               cmd->SCp.buffer++;
+               cmd->SCp.this_residual = cmd->SCp.buffer->length;
+               cmd->SCp.ptr = cmd->SCp.buffer->address;
+           }
+       }
+       /* Now check to see if the drive is ready to comunicate */
+       r = (r_str(ppb) & 0xf0);
+       /* If not, drop back down to the scheduler and wait a timer tick */
+       if (!(r & 0x80))
+           return 0;
+    }
+    return 1;                  /* FINISH_RETURN */
 }
 
-int     ppa_reset( Scsi_Cmnd * cmd )
-
-{       ppa_abort_flag = 2;
-        return SCSI_RESET_PUNT;
+/*
+ * Since the PPA itself doesn't generate interrupts, we use
+ * the scheduler's task queue to generate a stream of call-backs and
+ * complete the request when the drive is ready.
+ */
+static void ppa_interrupt(void *data)
+{
+    ppa_struct *tmp = (ppa_struct *) data;
+    Scsi_Cmnd *cmd = tmp->cur_cmd;
+
+    if (!cmd) {
+       printk("PPA: bug in ppa_interrupt\n");
+       return;
+    }
+    if (ppa_engine(tmp, cmd)) {
+       tmp->ppa_tq.data = (void *) tmp;
+       tmp->ppa_tq.sync = 0;
+       queue_task(&tmp->ppa_tq, &tq_timer);
+       return;
+    }
+    /* Command must of completed hence it is safe to let go... */
+#if PPA_DEBUG > 0
+    switch ((cmd->result >> 16) & 0xff) {
+    case DID_OK:
+       break;
+    case DID_NO_CONNECT:
+       printk("ppa: no device at SCSI ID %i\n", cmd->target);
+       break;
+    case DID_BUS_BUSY:
+       printk("ppa: BUS BUSY - EPP timeout detected\n");
+       break;
+    case DID_TIME_OUT:
+       printk("ppa: unknown timeout\n");
+       break;
+    case DID_ABORT:
+       printk("ppa: told to abort\n");
+       break;
+    case DID_PARITY:
+       printk("ppa: parity error (???)\n");
+       break;
+    case DID_ERROR:
+       printk("ppa: internal driver error\n");
+       break;
+    case DID_RESET:
+       printk("ppa: told to reset device\n");
+       break;
+    case DID_BAD_INTR:
+       printk("ppa: bad interrupt (???)\n");
+       break;
+    default:
+       printk("ppa: bad return code (%02x)\n", (cmd->result >> 16) & 0xff);
+    }
+  #endif
+  
+    if (cmd->SCp.phase > 1)
+       ppa_disconnect(cmd->host->unique_id);
+
+    tmp->cur_cmd = 0;
+    cmd->scsi_done(cmd);
+    return;
 }
 
-const char      *ppa_info( struct Scsi_Host * host )
-
-{       return ppa_info_string;
+static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char l = 0, h = 0;
+    int retv;
+
+    /* First check for any errors that may of occured
+     * Here we check for internal errors
+     */
+    if (tmp->failed)
+       return 0;
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Phase 0 - Waiting for parport */
+       if ((jiffies - tmp->jstart) > HZ) {
+           /*
+            * We waited more than a second
+            * for parport to call us
+            */
+           ppa_fail(host_no, DID_BUS_BUSY);
+           return 0;
+       }
+       return 1;               /* wait until ppa_wakeup claims parport */
+    case 1:                    /* Phase 1 - Connected */
+       {                       /* Perform a sanity check for cable unplugged */
+           int retv = 2;       /* Failed */
+
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+
+           w_ctr(ppb, 0xe);
+           if ((r_str(ppb) & 0x08) == 0x08)
+               retv--;
+
+           w_ctr(ppb, 0xc);
+           if ((r_str(ppb) & 0x08) == 0x00)
+               retv--;
+
+           if (retv)
+               if ((jiffies - tmp->jstart) > (1 * HZ)) {
+                   printk("ppa: Parallel port cable is unplugged!!\n");
+                   ppa_fail(host_no, DID_BUS_BUSY);
+                   return 0;
+               } else {
+                   ppa_disconnect(host_no);
+                   return 1;   /* Try again in a jiffy */
+               }
+           cmd->SCp.phase++;
+       }
+
+    case 2:                    /* Phase 2 - We are now talking to the scsi bus */
+       if (!ppa_select(host_no, cmd->target)) {
+           ppa_fail(host_no, DID_NO_CONNECT);
+           return 0;
+       }
+       cmd->SCp.phase++;
+
+    case 3:                    /* Phase 3 - Ready to accept a command */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       if (!ppa_send_command(cmd))
+           return 0;
+       cmd->SCp.phase++;
+
+    case 4:                    /* Phase 4 - Setup scatter/gather buffers */
+       if (cmd->use_sg) {
+           /* if many buffers are available, start filling the first */
+           cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+           cmd->SCp.this_residual = cmd->SCp.buffer->length;
+           cmd->SCp.ptr = cmd->SCp.buffer->address;
+       } else {
+           /* else fill the only available buffer */
+           cmd->SCp.buffer = NULL;
+           cmd->SCp.this_residual = cmd->request_bufflen;
+           cmd->SCp.ptr = cmd->request_buffer;
+       }
+       cmd->SCp.buffers_residual = cmd->use_sg;
+       cmd->SCp.phase++;
+
+    case 5:                    /* Phase 5 - Data transfer stage */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       retv = ppa_completion(cmd);
+       if (retv == -1)
+           return 0;
+       if (retv == 0)
+           return 1;
+       cmd->SCp.phase++;
+
+    case 6:                    /* Phase 6 - Read status/message */
+       cmd->result = DID_OK << 16;
+       /* Check for data overrun */
+       if (ppa_wait(host_no) != (unsigned char) 0xf0) {
+           ppa_fail(host_no, DID_ERROR);
+           return 0;
+       }
+       if (ppa_in(host_no, &l, 1)) {   /* read status byte */
+           /* Check for optional message byte */
+           if (ppa_wait(host_no) == (unsigned char) 0xf0)
+               ppa_in(host_no, &h, 1);
+           cmd->result = (DID_OK << 16) + (h << 8) + (l & STATUS_MASK);
+       }
+       return 0;               /* Finished */
+       break;
+
+    default:
+       printk("ppa: Invalid scsi phase\n");
+    }
+    return 0;
 }
 
-#ifndef MODULE
-
-/* Command line parameters (for built-in driver):
-
-   Syntax:  ppa=base[,speed_high[,speed_low[,nybble]]]
-
-   For example:  ppa=0x378   or   ppa=0x378,0,3
-
-*/
-
-void    ppa_setup(char *str, int *ints)
-
-{       if (ints[0] > 0) ppa_base = ints[1];
-        if (ints[0] > 1) ppa_speed_high = ints[2];
-        if (ints[0] > 2) ppa_speed_low = ints[3];
-        if (ints[0] > 3) ppa_nybble = ints[4];
-        if (ints[0] > 4) ppa_nybble = ints[5];
+int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+    int host_no = cmd->host->unique_id;
+
+    if (ppa_hosts[host_no].cur_cmd) {
+       printk("PPA: bug in ppa_queuecommand\n");
+       return 0;
+    }
+    ppa_hosts[host_no].failed = 0;
+    ppa_hosts[host_no].jstart = jiffies;
+    ppa_hosts[host_no].cur_cmd = cmd;
+    cmd->scsi_done = done;
+    cmd->result = DID_ERROR << 16;     /* default return code */
+    cmd->SCp.phase = 0;                /* bus free */
+
+    ppa_pb_claim(host_no);
+
+    ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no;
+    ppa_hosts[host_no].ppa_tq.sync = 0;
+    queue_task(&ppa_hosts[host_no].ppa_tq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+
+    return 0;
 }
 
-#else
+/*
+ * Apparently the the disk->capacity attribute is off by 1 sector 
+ * for all disk drives.  We add the one here, but it should really
+ * be done in sd.c.  Even if it gets fixed there, this will still
+ * work.
+ */
+int ppa_biosparam(Disk * disk, kdev_t dev, int ip[])
+{
+    ip[0] = 0x40;
+    ip[1] = 0x20;
+    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    if (ip[2] > 1024) {
+       ip[0] = 0xff;
+       ip[1] = 0x3f;
+       ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+       if (ip[2] > 1023)
+           ip[2] = 1023;
+    }
+    return 0;
+}
 
-Scsi_Host_Template      driver_template = PPA;
+int ppa_abort(Scsi_Cmnd * cmd)
+{
+    /*
+     * There is no method for aborting commands since Iomega
+     * have tied the SCSI_MESSAGE line high in the interface
+     */
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Do not have access to parport */
+    case 1:                    /* Have not connected to interface */
+       cmd->result = DID_ABORT;
+       cmd->done(cmd);
+       return SCSI_ABORT_SUCCESS;
+       break;
+    default:                   /* SCSI command sent, can not abort */
+       return SCSI_ABORT_BUSY;
+       break;
+    }
+}
 
-#include  "scsi_module.c"
+int ppa_reset(Scsi_Cmnd * cmd, unsigned int x)
+{
+    int host_no = cmd->host->unique_id;
+    int ppb = PPA_BASE(host_no);
+
+    /*
+     * PHASE1:
+     * Bring the interface crashing down on whatever is running
+     * hopefully this will kill the request.
+     * Bring back up the interface, reset the drive (and anything
+     * attached for that manner)
+     */
+    if (cmd)
+       if (cmd->SCp.phase)
+           ppa_disconnect(cmd->host->unique_id);
+
+    ppa_connect(host_no, CONNECT_NORMAL);
+    w_dtr(ppb, 0x40);
+    w_ctr(ppb, 0x8);
+    udelay(30);
+    w_ctr(ppb, 0xc);
+    udelay(1000);              /* delay for devices to settle down */
+    ppa_disconnect(host_no);
+    udelay(1000);              /* Additional delay to allow devices to settle down */
+
+    /*
+     * PHASE2:
+     * Sanity check for the sake of mid-level driver
+     */
+    if (!cmd) {
+       printk("ppa bus reset called for invalid command.\n");
+       return SCSI_RESET_NOT_RUNNING;
+    }
+    /*
+     * PHASE3:
+     * Flag the current command as having died due to reset
+     */
+    ppa_connect(host_no, CONNECT_NORMAL);
+    ppa_fail(host_no, DID_RESET);
+
+    /* Since the command was already on the timer queue ppa_interrupt
+     * will be called shortly.
+     */
+    return SCSI_RESET_PENDING;
+}
 
-#endif
+static int device_check(int host_no)
+{
+    /* This routine looks for a device and then attempts to use EPP
+       to send a command. If all goes as planned then EPP is available. */
+
+    static char cmd[6] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    int loop, old_mode, status, k, ppb = PPA_BASE(host_no);
+    unsigned char l;
+
+    old_mode = ppa_hosts[host_no].mode;
+    for (loop = 0; loop < 8; loop++) {
+       /* Attempt to use EPP for Test Unit Ready */
+       if ((ppb & 0x0007) == 0x0000)
+           ppa_hosts[host_no].mode = PPA_EPP_32;
+
+      second_pass:
+       ppa_connect(host_no, CONNECT_EPP_MAYBE);
+       /* Select SCSI device */
+       if (!ppa_select(host_no, loop)) {
+           ppa_disconnect(host_no);
+           continue;
+       }
+       printk("ppa: Found device at ID %i, Attempting to use %s\n", loop,
+              PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+
+       /* Send SCSI command */
+       status = 1;
+       w_ctr(ppb, 0x0c);
+       for (l = 0; (l < 6) && (status); l++)
+           status = ppa_out(host_no, cmd, 1);
+
+       if (!status) {
+           ppa_disconnect(host_no);
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+           w_dtr(ppb, 0x40);
+           w_ctr(ppb, 0x08);
+           udelay(30);
+           w_ctr(ppb, 0x0c);
+           udelay(1000);
+           ppa_disconnect(host_no);
+           udelay(1000);
+           if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+               ppa_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("ppa: Unable to establish communication, aborting driver load.\n");
+           return 1;
+       }
+       w_ctr(ppb, 0x0c);
+       k = 1000000;            /* 1 Second */
+       do {
+           l = r_str(ppb);
+           k--;
+           udelay(1);
+       } while (!(l & 0x80) && (k));
+
+       l &= 0xf0;
+
+       if (l != 0xf0) {
+           ppa_disconnect(host_no);
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+           w_dtr(ppb, 0x40);
+           w_ctr(ppb, 0x08);
+           udelay(30);
+           w_ctr(ppb, 0x0c);
+           udelay(1000);
+           ppa_disconnect(host_no);
+           udelay(1000);
+           if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+               ppa_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("ppa: Unable to establish communication, aborting driver load.\n");
+           return 1;
+       }
+       ppa_disconnect(host_no);
+       printk("ppa: Communication established with ID %i using %s\n", loop,
+              PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+       return 0;
+    }
+    printk("ppa: No devices found, aborting driver load.\n");
+    return 1;
+}
 
-/* end of ppa.c */
+#define PPA_ID "ppa: "
+
+int port_probe(unsigned short port)
+{
+    int retv = 0;
+    unsigned char a, b, c;
+    unsigned int i, j;
+
+
+    printk(PPA_ID "Probing port %04x\n", port);
+
+/*                 #####  ######  ######
+ *                #     # #     # #     #
+ *                #       #     # #     #
+ *                 #####  ######  ######
+ *                      # #       #
+ *                #     # #       #
+ *                 #####  #       #
+ */
+
+    outb(0x0c, port + 0x402);
+    outb(0x0c, port + 0x002);
+    outb(0x55, port);
+    a = inb(port);
+    if (a != 0x55)
+       return retv;
+    printk(PPA_ID "    SPP port present\n");
+
+    retv += PPA_PROBE_SPP;
+
+/*                #######  #####  ######
+ *                #       #     # #     #
+ *                #       #       #     #
+ *                #####   #       ######
+ *                #       #       #
+ *                #       #     # #
+ *                #######  #####  #
+ */
+
+    for (i = 1024; i > 0; i--) {       /* clear at most 1k of data from FIFO */
+       a = inb(port + 0x402);
+       if ((a & 0x03) == 0x03)
+           goto no_ecp;
+       if (a & 0x01)
+           break;
+       inb(port + 0x400);      /* Remove byte from FIFO */
+    }
+
+    if (i <= 0)
+       goto no_ecp;
+
+    b = a ^ 3;
+    outb(b, port + 0x402);
+    c = inb(port + 0x402);
+
+    if (a == c) {
+       outb(0xc0, port + 0x402);       /* FIFO test */
+       j = 0;
+       while (!(inb(port + 0x402) & 0x01) && (j < 1024)) {
+           inb(port + 0x400);
+           j++;
+       }
+       if (j >= 1024)
+           goto no_ecp;
+       i = 0;
+       j = 0;
+       while (!(inb(port + 0x402) & 0x02) && (j < 1024)) {
+           outb(0x00, port + 0x400);
+           i++;
+           j++;
+       }
+       if (j >= 1024)
+           goto no_ecp;
+       j = 0;
+       while (!(inb(port + 0x402) & 0x01) && (j < 1024)) {
+           inb(port + 0x400);
+           j++;
+       }
+       if (j >= 1024)
+           goto no_ecp;
+       printk(PPA_ID "    ECP with a %i byte FIFO present\n", i);
+
+       retv += PPA_PROBE_ECR;
+    }
+/*                ######   #####   #####
+ *                #     # #     # #     #
+ *                #     # #             #
+ *                ######   #####   #####
+ *                #             # #
+ *                #       #     # #
+ *                #        #####  #######
+ */
+
+  no_ecp:
+    if (retv & PPA_PROBE_ECR)
+       outb(0x20, port + 0x402);
+
+    outb(0x55, port);
+    outb(0x0c, port + 2);
+    a = inb(port);
+    outb(0x55, port);
+    outb(0x2c, port + 2);
+    b = inb(port);
+    if (a != b) {
+       printk(PPA_ID "    PS/2 bidirectional port present\n");
+       retv += PPA_PROBE_PS2;
+    }
+/*                ####### ######  ######
+ *                #       #     # #     #
+ *                #       #     # #     #
+ *                #####   ######  ######
+ *                #       #       #
+ *                #       #       #
+ *                ####### #       #
+ */
+
+    if (port & 0x007) {
+       printk(PPA_ID "    EPP not supported at this address\n");
+       return retv;
+    }
+    if (retv & PPA_PROBE_ECR) {
+       for (i = 0x00; i < 0x80; i += 0x20) {
+           outb(i, port + 0x402);
+
+           a = inb(port + 1);
+           outb(a, port + 1);
+           outb(a & 0xfe, port + 1);
+           a = inb(port + 1);
+           if (!(a & 0x01)) {
+               printk(PPA_ID "    Failed Intel bug check. (Phony EPP in ECP)\n");
+               return retv;
+           }
+       }
+       printk(PPA_ID "    Passed Intel bug check.\n");
+       outb(0x80, port + 0x402);
+    }
+    a = inb(port + 1);
+    outb(a, port + 1);
+    outb(a & 0xfe, port + 1);
+    a = inb(port + 1);
+
+    if (a & 0x01) {
+       outb(0x0c, port + 0x402);
+       outb(0x0c, port + 0x002);
+       return retv;
+    }
+
+    outb(0x04, port + 2);
+    inb(port + 4);
+    a = inb(port + 1);
+    outb(a, port + 1);
+    outb(a & 0xfe, port + 1);
+
+    if (a & 0x01) {
+       printk(PPA_ID "    EPP 1.9 with hardware direction protocol\n");
+       retv += PPA_PROBE_EPP19;
+    } else {
+       /* The EPP timeout bit was not set, this could either be:
+        * EPP 1.7
+        * EPP 1.9 with software direction
+        */
+       outb(0x24, port + 2);
+       inb(port + 4);
+       a = inb(port + 1);
+       outb(a, port + 1);
+       outb(a & 0xfe, port + 1);
+       if (a & 0x01) {
+           printk(PPA_ID "    EPP 1.9 with software direction protocol\n");
+           retv += PPA_PROBE_EPP19;
+       } else {
+           printk(PPA_ID "    EPP 1.7\n");
+           retv += PPA_PROBE_EPP17;
+       }
+    }
+
+    outb(0x0c, port + 0x402);
+    outb(0x0c, port + 0x002);
+    return retv;
+}
index 9dbfe7e63c209f17a549bb22ff7e71cf8865c110..2106222293a110f86638037de65f224f1dd811f1 100644 (file)
+/*  Driver for the PPA3 parallel port SCSI HBA embedded in 
+ * the Iomega ZIP drive
+ * 
+ * (c) 1996     Grant R. Guenther  grant@torque.net
+ *             David Campbell     campbell@torque.net
+ *
+ *     All comments to David.
+ */
+
 #ifndef _PPA_H
 #define _PPA_H
 
-/*  Driver for the PPA3 parallel port SCSI HBA embedded in 
-    the Iomega ZIP drive
+#define   PPA_VERSION   "1.42"
+
+/* Use the following to enable certain chipset support
+ * Default is PEDANTIC = 3
+ */
+#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC
+#define CONFIG_SCSI_PPA_HAVE_PEDANTIC  3
+#endif
+
+/* 
+ * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
+ * to support EPP and scatter-gather.                        [0.26-athena]
+ *
+ * additional hacks by David Campbell
+ * in response to this driver "mis-behaving" on his machine.
+ *      Fixed EPP to handle "software" changing of EPP port data direction.
+ *      Chased down EPP timeouts
+ *      Made this driver "kernel version friendly"           [0.28-athena]
+ *
+ * [ Stuff removed ]
+ *
+ * Compiled against 2.1.53.
+ *     Rebuilt ppa_abort() function, should handle unplugged cable.
+ *                                                     [1.35s]
+ *
+ * PPA now auto probes for EPP on base address which are aligned on
+ * 8 byte boundaries (0x278 & 0x378) using the attached devices.
+ * This hopefully avoids the nasty problem of trying to detect EPP.
+ *     Tested on 2.1.53                                [1.36]
+ *
+ * The id_probe utility no longer performs read/write tests.
+ * Additional code included for checking the Intel ECP bug
+ * (Bit 0 of STR stuck low which fools the EPP detection routine)
+ *                                                     [1.37]
+ *
+ * Oops! Got the bit sign mixed up for the Intel bug check.
+ * Found that an additional delay is required during SCSI resets
+ * to allow devices to settle down.
+ *                                                     [1.38]
+ *
+ * Fixed all problems in the parport sharing scheme. Now ppa can be safe
+ * used with lp or other parport devices on the same parallel port.
+ *             1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *                                                     [1.39]
+ *
+ * Little fix in ppa engine to ensure that ppa don' t release parport
+ * or disconnect in wrong cases.
+ *             1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *                                                     [1.40]
+ *
+ * Corrected ppa.h for 2.1.x kernels (>=2.1.85)
+ * Modified "Nat Semi Kludge" for extended chipsets
+ *                                                     [1.41]
+ *
+ * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7)
+ *                                                     [1.42]
+ */
+/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+#ifdef PPA_CODE
+#include  <linux/stddef.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/tqueue.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <linux/blk.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
+
+#include  <asm/io.h>
+#include  "sd.h"
+#include  "hosts.h"
+/* batteries not included :-) */
+
+/*
+ * modes in which the driver can operate 
+ */
+#define   PPA_AUTODETECT        0      /* Autodetect mode                */
+#define   PPA_NIBBLE            1      /* work in standard 4 bit mode    */
+#define   PPA_PS2               2      /* PS/2 byte mode         */
+#define   PPA_EPP_8             3      /* EPP mode, 8 bit                */
+#define   PPA_EPP_16            4      /* EPP mode, 16 bit               */
+#define   PPA_EPP_32            5      /* EPP mode, 32 bit               */
+#define   PPA_UNKNOWN           6      /* Just in case...                */
 
-       (c) 1996        Grant R. Guenther  grant@torque.net
-*/
+static char *PPA_MODE_STRING[] =
+{
+    "Autodetect",
+    "SPP",
+    "PS/2",
+    "EPP 8 bit",
+    "EPP 16 bit",
+    "EPP 32 bit",
+    "Unknown"};
 
-#define        PPA_INITIATOR   7
+/* This is a global option */
+int ppa_sg = SG_ALL;           /* enable/disable scatter-gather. */
 
-int ppa_detect(Scsi_Host_Template * );
-const char * ppa_info(struct Scsi_Host *);
-int ppa_command(Scsi_Cmnd *);
-int ppa_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+/* other options */
+#define PPA_CAN_QUEUE   1      /* use "queueing" interface */
+#define PPA_BURST_SIZE 512     /* data burst size */
+#define PPA_SELECT_TMO  5000   /* how long to wait for target ? */
+#define PPA_SPIN_TMO    50000  /* ppa_wait loop limiter */
+#define PPA_DEBUG      0       /* debuging option */
+#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
+
+/* args to ppa_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb((x)+0x402)
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_ctr(x,y)      outb(y, (x)+2)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x)+0x400)
+#define w_ecr(x,y)      outb(y, (x)+0x402)
+
+static int ppa_engine(ppa_struct *, Scsi_Cmnd *);
+static int ppa_in(int, char *, int);
+static int ppa_init(int);
+static void ppa_interrupt(void *);
+static int ppa_out(int, char *, int);
+
+struct proc_dir_entry proc_scsi_ppa =
+{PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
+#else
+extern struct proc_dir_entry proc_scsi_ppa;
+#endif
+
+int ppa_detect(Scsi_Host_Template *);
+const char *ppa_info(struct Scsi_Host *);
+int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int ppa_abort(Scsi_Cmnd *);
-int ppa_reset(Scsi_Cmnd *);
-int ppa_biosparam(Disk *, kdev_t, int[]);
-
-#define PPA {                  \
-       0,                      \
-       0,                      \
-       0,                      \
-       0,                      \
-       0,                      \
-       ppa_detect,             \
-       0,                      \
-       ppa_info,               \
-       ppa_command,            \
-       ppa_queuecommand,       \
-       ppa_abort,              \
-       ppa_reset,              \
-       0,                      \
-       ppa_biosparam,          \
-       0,                      \
-       PPA_INITIATOR,          \
-       SG_NONE,                \
-       1,                      \
-       0,                      \
-       0,                      \
-       DISABLE_CLUSTERING      \
-}
+int ppa_reset(Scsi_Cmnd *, unsigned int);
+int ppa_proc_info(char *, char **, off_t, int, int, int);
+int ppa_biosparam(Disk *, kdev_t, int *);
 
-#endif /* _PPA_H */
+#define PPA {  proc_dir:               &proc_scsi_ppa,                 \
+               proc_info:              ppa_proc_info,                  \
+               name:                   "Iomega parport ZIP drive",     \
+               detect:                 ppa_detect,                     \
+               queuecommand:           ppa_queuecommand,               \
+               abort:                  ppa_abort,                      \
+               reset:                  ppa_reset,                      \
+               bios_param:             ppa_biosparam,                  \
+               this_id:                -1,                             \
+               sg_tablesize:           SG_ALL,                         \
+               cmd_per_lun:            1,                              \
+               use_clustering:         ENABLE_CLUSTERING               \
+}
+#endif                         /* _PPA_H */
index 324969f7dddc94075b096acd71ef3a8aea487382..36838856813846492dadca6906c39f7b28c3fd74 100644 (file)
@@ -296,7 +296,12 @@ struct Status_Entry {
 #define CS_DEVICE_RESET_MSG_FAILED     0x0012
 #define CS_ID_MSG_FAILED               0x0013
 #define CS_UNEXP_BUS_FREE              0x0014
+/* as per app note #83120-514-06a: */
 #define CS_DATA_UNDERRUN               0x0015
+#define CS_INVALID_ENTRY_TYPE          0x001b
+#define CS_DEVICE_QUEUE_FULL           0x001c
+#define CS_SCSI_PHASE_SKIPPED          0x001d
+#define CS_ARS_FAILED                  0x001e  /* auto Req. Sense failed */
 
 /* status entry state flag definitions */
 #define SF_GOT_BUS                     0x0100
@@ -992,6 +997,10 @@ static int isp1020_return_status(struct Status_Entry *sts)
              case CS_DEVICE_RESET_MSG_FAILED:
              case CS_ID_MSG_FAILED:
              case CS_UNEXP_BUS_FREE:
+             case CS_INVALID_ENTRY_TYPE:
+             case CS_DEVICE_QUEUE_FULL:
+             case CS_SCSI_PHASE_SKIPPED:
+             case CS_ARS_FAILED:
                host_status = DID_ERROR;
                break;
              case CS_DATA_UNDERRUN:
@@ -1248,7 +1257,8 @@ static int isp1020_init(struct Scsi_Host *sh)
        if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
            || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
        {
-               printk("qlogicisp : can't decode i/o address space\n");
+               printk("qlogicisp : can't decode i/o address space at 0x%x\n",
+                      io_base);
                return 1;
        }
 
index e6874f8cb7cebd8142c4842efbf6c3950563410f..c0a8ae894170b87c70665207c8a6a69f650f3853 100644 (file)
@@ -229,6 +229,7 @@ struct dev_info{
  */
 static struct dev_info device_list[] =
 {
+{"TEAC","CD-R55S","1.0H", BLIST_NOLUN},         /* Locks up if polled for lun != 0 */
 {"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
 {"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
 {"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
index 03bd0d7a041468a1ba6763e5683df52c4d1a55b3..7691859575f0a1064f38c53ac672fb6fed4a4a27 100644 (file)
@@ -164,7 +164,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
  * interface instead, as this is a more flexible approach to performing
  * generic SCSI commands on a device.
  */
-static int ioctl_command(Scsi_Device *dev, void *buffer)
+int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer)
 {
     char * buf;
     unsigned char cmd[12]; 
@@ -369,7 +369,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
        return ioctl_probe(dev->host, arg);
     case SCSI_IOCTL_SEND_COMMAND:
        if(!suser() || securelevel > 0)  return -EACCES;
-       return ioctl_command((Scsi_Device *) dev, arg);
+       return scsi_ioctl_send_command((Scsi_Device *) dev, arg);
     case SCSI_IOCTL_DOORLOCK:
        if (!dev->removable || !dev->lockable) return 0;
        scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
index 932610f98fa31c396f33f94ca96a674ff4a52c9f..985b3eaaa39c5448d28df6ac78bcd64258f52b5a 100644 (file)
@@ -36,6 +36,7 @@ extern int scsicam_bios_param (Disk * disk,
 
 extern void print_command (unsigned char *command);
 extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
+extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer);
 
 struct symbol_table scsi_symbol_table = {
 #include <linux/symtab_begin.h>
@@ -64,6 +65,7 @@ struct symbol_table scsi_symbol_table = {
     X(scsi_mark_host_reset),
     X(scsi_mark_bus_reset),
     X(scsi_device_types),
+    X(scsi_ioctl_send_command),
 #if defined(CONFIG_PROC_FS)
     X(proc_print_scsidevice),
 #endif
index 6cb8801864e6d4e90f26bb8db244132aa609585c..706639dab376781c4c368bf7730ca5a2a08f3d17 100644 (file)
@@ -73,13 +73,20 @@ static int sg_ioctl(struct inode * inode,struct file * file,
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(long));
+        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
         if (result) return result;
 
        scsi_generics[dev].timeout=get_user((int *) arg);
        return 0;
     case SG_GET_TIMEOUT:
        return scsi_generics[dev].timeout;
+    case SCSI_IOCTL_SEND_COMMAND:
+       /*
+         Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
+         user already has read/write access to the generic device and so
+         can execute arbitrary SCSI commands.
+       */
+       return scsi_ioctl_send_command(scsi_generics[dev].device, (void *) arg);
     default:
        return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
     }
index 5ac1952a9daaf93ddb55ae003d024891542b7474..13897ec1eef6efb570e6a4b3660872b6a4de4227 100644 (file)
@@ -190,6 +190,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_BINFMT_EM86),y)
+BINFMTS += binfmt_em86.o
+else
+  ifeq ($(CONFIG_BINFMT_EM86),m)
+  M_OBJS += binfmt_em86.o
+  endif
+endif
+
 # binfmt_script is always there
 BINFMTS += binfmt_script.o
 
index e4ebe3651f4c3a9a7d88cca059e1b27dd6a013e1..11c1a91496dd48856e71ef3438f8274cabf9118e 100644 (file)
@@ -37,9 +37,9 @@
 
 #include <linux/elf.h>
 
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static int load_elf_library(int fd);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 extern void dump_thread(struct pt_regs *, struct user *);
 
 /*
@@ -47,7 +47,7 @@ extern void dump_thread(struct pt_regs *, struct user *);
  * don't even try.
  */
 #ifdef USE_ELF_CORE_DUMP
-static int elf_core_dump(long signr, struct pt_regs * regs);
+static int elf_core_dump(long signr, struct pt_regs *regs);
 #else
 #define elf_core_dump  NULL
 #endif
@@ -55,11 +55,12 @@ static int elf_core_dump(long signr, struct pt_regs * regs);
 #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
 #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 
-static struct linux_binfmt elf_format = {
+static struct linux_binfmt elf_format =
+{
 #ifndef MODULE
        NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
 #else
-       NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
+  NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
 #endif
 };
 
@@ -67,7 +68,7 @@ static void set_brk(unsigned long start, unsigned long end)
 {
        start = PAGE_ALIGN(start);
        end = PAGE_ALIGN(end);
-       if (end <= start) 
+       if (end <= start)
                return;
        do_mmap(NULL, start, end - start,
                PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -84,9 +85,9 @@ static void set_brk(unsigned long start, unsigned long end)
 static void padzero(unsigned long elf_bss)
 {
        unsigned long nbyte;
-       char * fpnt;
-  
-       nbyte = elf_bss & (PAGE_SIZE-1);
+       char *fpnt;
+
+       nbyte = elf_bss & (PAGE_SIZE - 1);
        if (nbyte) {
                nbyte = PAGE_SIZE - nbyte;
                /* FIXME: someone should investigate, why a bad binary
@@ -103,10 +104,10 @@ static void padzero(unsigned long elf_bss)
        }
 }
 
-unsigned long * create_elf_tables(char *p, int argc, int envc, 
-                                 struct elfhdr * exec,
-                                 unsigned long load_addr,
-                                 unsigned long interp_load_addr, int ibcs)
+unsigned long *create_elf_tables(char *p, int argc, int envc,
+                                struct elfhdr *exec,
+                                unsigned long load_addr,
+                                unsigned long interp_load_addr, int ibcs)
 {
        unsigned long *argv, *envp, *dlinfo;
        unsigned long *sp;
@@ -115,52 +116,53 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
         * Force 16 byte alignment here for generality.
         */
        sp = (unsigned long *) (~15UL & (unsigned long) p);
-       sp -= exec ? DLINFO_ITEMS*2 : 2;
+       sp -= exec ? DLINFO_ITEMS * 2 : 2;
        dlinfo = sp;
-       sp -= envc+1;
+       sp -= envc + 1;
        envp = sp;
-       sp -= argc+1;
+       sp -= argc + 1;
        argv = sp;
        if (!ibcs) {
-               put_user(envp,--sp);
-               put_user(argv,--sp);
+               put_user(envp, --sp);
+               put_user(argv, --sp);
        }
-
 #define NEW_AUX_ENT(id, val) \
          put_user ((id), dlinfo++); \
          put_user ((val), dlinfo++)
 
-       if (exec) { /* Put this here for an ELF program interpreter */
-         struct elf_phdr * eppnt;
-         eppnt = (struct elf_phdr *) exec->e_phoff;
-
-         NEW_AUX_ENT (AT_PHDR, load_addr + exec->e_phoff);
-         NEW_AUX_ENT (AT_PHENT, sizeof (struct elf_phdr));
-         NEW_AUX_ENT (AT_PHNUM, exec->e_phnum);
-         NEW_AUX_ENT (AT_PAGESZ, PAGE_SIZE);
-         NEW_AUX_ENT (AT_BASE, interp_load_addr);
-         NEW_AUX_ENT (AT_FLAGS, 0);
-         NEW_AUX_ENT (AT_ENTRY, (unsigned long) exec->e_entry);
-         NEW_AUX_ENT (AT_UID, (unsigned long) current->uid);
-         NEW_AUX_ENT (AT_EUID, (unsigned long) current->euid);
-         NEW_AUX_ENT (AT_GID, (unsigned long) current->gid);
-         NEW_AUX_ENT (AT_EGID, (unsigned long) current->egid);
+       if (exec) {             /* Put this here for an ELF program interpreter */
+               struct elf_phdr *eppnt;
+               eppnt = (struct elf_phdr *) exec->e_phoff;
+
+               NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff);
+               NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr));
+               NEW_AUX_ENT(AT_PHNUM, exec->e_phnum);
+               NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE);
+               NEW_AUX_ENT(AT_BASE, interp_load_addr);
+               NEW_AUX_ENT(AT_FLAGS, 0);
+               NEW_AUX_ENT(AT_ENTRY, (unsigned long) exec->e_entry);
+               NEW_AUX_ENT(AT_UID, (unsigned long) current->uid);
+               NEW_AUX_ENT(AT_EUID, (unsigned long) current->euid);
+               NEW_AUX_ENT(AT_GID, (unsigned long) current->gid);
+               NEW_AUX_ENT(AT_EGID, (unsigned long) current->egid);
        }
-       NEW_AUX_ENT (AT_NULL, 0);
+       NEW_AUX_ENT(AT_NULL, 0);
 #undef NEW_AUX_ENT
-       put_user((unsigned long)argc,--sp);
+       put_user((unsigned long) argc, --sp);
        current->mm->arg_start = (unsigned long) p;
-       while (argc-->0) {
-               put_user(p,argv++);
-               while (get_user(p++)) /* nothing */ ;
+       while (argc-- > 0) {
+               put_user(p, argv++);
+               while (get_user(p++))   /* nothing */
+                       ;
        }
-       put_user(0,argv);
+       put_user(0, argv);
        current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-       while (envc-->0) {
-               put_user(p,envp++);
-               while (get_user(p++)) /* nothing */ ;
+       while (envc-- > 0) {
+               put_user(p, envp++);
+               while (get_user(p++))   /* nothing */
+                       ;
        }
-       put_user(0,envp);
+       put_user(0, envp);
        current->mm->env_end = (unsigned long) p;
        return sp;
 }
@@ -171,12 +173,12 @@ unsigned long * create_elf_tables(char *p, int argc, int envc,
    is only provided so that we can read a.out libraries that have
    an ELF header */
 
-static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
-                                    struct inode * interpreter_inode, 
+static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
+                                    struct inode *interpreter_inode,
                                     unsigned long *interp_load_addr)
 {
-       struct file * file;
-       struct elf_phdr *elf_phdata  =  NULL;
+       struct file *file;
+       struct elf_phdr *elf_phdata = NULL;
        struct elf_phdr *eppnt;
        unsigned long load_addr;
        int load_addr_set = 0;
@@ -185,108 +187,104 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
        unsigned long last_bss, elf_bss;
        unsigned long error;
        int i;
-       
+
        elf_bss = 0;
        last_bss = 0;
        error = load_addr = 0;
-       
+
        /* First of all, some simple consistency checks */
-       if ((interp_elf_ex->e_type != ET_EXEC && 
-           interp_elf_ex->e_type != ET_DYN) || 
-          !elf_check_arch(interp_elf_ex->e_machine) ||
-          (!interpreter_inode->i_op ||
-           !interpreter_inode->i_op->default_file_ops->mmap)){
+       if ((interp_elf_ex->e_type != ET_EXEC &&
+            interp_elf_ex->e_type != ET_DYN) ||
+           !elf_check_arch(interp_elf_ex->e_machine) ||
+           (!interpreter_inode->i_op ||
+            !interpreter_inode->i_op->default_file_ops->mmap)) {
                return ~0UL;
        }
-       
        /* Now read in all of the header information */
-       
+
        if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
-           return ~0UL;
-       
-       elf_phdata =  (struct elf_phdr *) 
-               kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 
-                       GFP_KERNEL);
+                return ~0UL;
+
+       elf_phdata = (struct elf_phdr *)
+           kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
+                   GFP_KERNEL);
        if (!elf_phdata)
-         return ~0UL;
-       
+               return ~0UL;
+
        /*
         * If the size of this structure has changed, then punt, since
         * we will be doing the wrong thing.
         */
-       if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
-         {
-           kfree(elf_phdata);
-           return ~0UL;
-         }
-
-       retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, 
+       if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
+               kfree(elf_phdata);
+               return ~0UL;
+       }
+       retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
                           (char *) elf_phdata,
-                          sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
-       
+                   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+
        if (retval < 0) {
-               kfree (elf_phdata);
+               kfree(elf_phdata);
                return retval;
-       }
-
+       }
        elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
        if (elf_exec_fileno < 0) {
-         kfree(elf_phdata);
-         return ~0UL;
+               kfree(elf_phdata);
+               return ~0UL;
        }
-
        file = current->files->fd[elf_exec_fileno];
 
        eppnt = elf_phdata;
-       for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
-         if (eppnt->p_type == PT_LOAD) {
-           int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-           int elf_prot = 0;
-           unsigned long vaddr = 0;
-           unsigned long k;
-
-           if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-           if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-           if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-           if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
-               elf_type |= MAP_FIXED;
-               vaddr = eppnt->p_vaddr;
-           }
-           
-           error = do_mmap(file, 
-                           load_addr + ELF_PAGESTART(vaddr),
-                           eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
-                           elf_prot,
-                           elf_type,
-                           eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-           
-           if (error > -1024UL) {
-             /* Real error */
-             sys_close(elf_exec_fileno);
-             kfree(elf_phdata);
-             return ~0UL;
-           }
-
-           if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
-             load_addr = error;
-             load_addr_set = 1;
-           }
-
-           /*
-            * Find the end of the file  mapping for this phdr, and keep
-            * track of the largest address we see for this.
-            */
-           k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
-           if (k > elf_bss) elf_bss = k;
-
-           /*
-            * Do the same thing for the memory mapping - between
-            * elf_bss and last_bss is the bss section.
-            */
-           k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
-           if (k > last_bss) last_bss = k;
-         }
-       
+       for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++)
+               if (eppnt->p_type == PT_LOAD) {
+                       int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                       int elf_prot = 0;
+                       unsigned long vaddr = 0;
+                       unsigned long k;
+
+                       if (eppnt->p_flags & PF_R)
+                               elf_prot = PROT_READ;
+                       if (eppnt->p_flags & PF_W)
+                               elf_prot |= PROT_WRITE;
+                       if (eppnt->p_flags & PF_X)
+                               elf_prot |= PROT_EXEC;
+                       if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+                               elf_type |= MAP_FIXED;
+                               vaddr = eppnt->p_vaddr;
+                       }
+                       error = do_mmap(file,
+                                       load_addr + ELF_PAGESTART(vaddr),
+                       eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
+                                       elf_prot,
+                                       elf_type,
+                       eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+                       if (error > -1024UL) {
+                               /* Real error */
+                               sys_close(elf_exec_fileno);
+                               kfree(elf_phdata);
+                               return ~0UL;
+                       }
+                       if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+                               load_addr = error;
+                               load_addr_set = 1;
+                       }
+                       /*
+                        * Find the end of the file  mapping for this phdr, and keep
+                        * track of the largest address we see for this.
+                        */
+                       k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+                       if (k > elf_bss)
+                               elf_bss = k;
+
+                       /*
+                        * Do the same thing for the memory mapping - between
+                        * elf_bss and last_bss is the bss section.
+                        */
+                       k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+                       if (k > last_bss)
+                               last_bss = k;
+               }
        /* Now use mmap to map the library into memory. */
 
        sys_close(elf_exec_fileno);
@@ -298,55 +296,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
         * bss page.
         */
        padzero(elf_bss);
-       elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
+       elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1);       /* What we have mapped so far */
 
        /* Map the last of the bss segment */
        if (last_bss > elf_bss)
-         do_mmap(NULL, elf_bss, last_bss-elf_bss,
-                 PROT_READ|PROT_WRITE|PROT_EXEC,
-                 MAP_FIXED|MAP_PRIVATE, 0);
+               do_mmap(NULL, elf_bss, last_bss - elf_bss,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE, 0);
        kfree(elf_phdata);
 
        *interp_load_addr = load_addr;
        return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
 }
 
-static unsigned long load_aout_interp(struct exec * interp_ex,
-                            struct inode * interpreter_inode)
+static unsigned long load_aout_interp(struct exec *interp_ex,
+                                     struct inode *interpreter_inode)
 {
-  int retval;
-  unsigned long elf_entry;
-  
-  current->mm->brk = interp_ex->a_bss +
-    (current->mm->end_data = interp_ex->a_data +
-     (current->mm->end_code = interp_ex->a_text));
-  elf_entry = interp_ex->a_entry;
-  
-  
-  if (N_MAGIC(*interp_ex) == OMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0, 
-                      interp_ex->a_text+interp_ex->a_data, 0);
-  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
-    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode,
-                      N_TXTOFF(*interp_ex) ,
-                      (char *) N_TXTADDR(*interp_ex),
-                      interp_ex->a_text+interp_ex->a_data, 0);
-  } else
-    retval = -1;
-  
-  if (retval >= 0)
-    do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
-           interp_ex->a_bss,
-           PROT_READ|PROT_WRITE|PROT_EXEC,
-           MAP_FIXED|MAP_PRIVATE, 0);
-  if (retval < 0) return ~0UL;
-  return elf_entry;
+       int retval;
+       unsigned long elf_entry;
+
+       current->mm->brk = interp_ex->a_bss +
+           (current->mm->end_data = interp_ex->a_data +
+            (current->mm->end_code = interp_ex->a_text));
+       elf_entry = interp_ex->a_entry;
+
+
+       if (N_MAGIC(*interp_ex) == OMAGIC) {
+               do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE, 0);
+               retval = read_exec(interpreter_inode, 32, (char *) 0,
+                              interp_ex->a_text + interp_ex->a_data, 0);
+       } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+               do_mmap(NULL, 0, interp_ex->a_text + interp_ex->a_data,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE, 0);
+               retval = read_exec(interpreter_inode,
+                                  N_TXTOFF(*interp_ex),
+                                  (char *) N_TXTADDR(*interp_ex),
+                              interp_ex->a_text + interp_ex->a_data, 0);
+       } else
+               retval = -1;
+
+       if (retval >= 0)
+               do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
+                       interp_ex->a_bss,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE, 0);
+       if (retval < 0)
+               return ~0UL;
+       return elf_entry;
 }
 
 /*
@@ -359,13 +358,12 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
 #define INTERPRETER_ELF 2
 
 
-static inline int
-do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static inline int do_load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
        struct elfhdr elf_ex;
        struct elfhdr interp_elf_ex;
-       struct file * file;
-       struct exec interp_ex;
+       struct file *file;
+       struct exec interp_ex;
        struct inode *interpreter_inode;
        unsigned long load_addr;
        int load_addr_set = 0;
@@ -374,125 +372,123 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        int i;
        int old_fs;
        int error;
-       struct elf_phdr * elf_ppnt, *elf_phdata;
+       struct elf_phdr *elf_ppnt, *elf_phdata;
        int elf_exec_fileno;
        unsigned long elf_bss, k, elf_brk;
-       int retval;
-       char * elf_interpreter;
+       int retval, ret_namei = -1;
+       char *elf_interpreter;
        unsigned long elf_entry, interp_load_addr = 0;
        int status;
        unsigned long start_code, end_code, end_data;
        unsigned long elf_stack;
        char passed_fileno[6];
-       
+
        ibcs2_interpreter = 0;
        status = 0;
        load_addr = 0;
-       elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
-       
+       elf_ex = *((struct elfhdr *) bprm->buf);        /* exec-header */
+
        if (elf_ex.e_ident[0] != 0x7f ||
-           strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-               return  -ENOEXEC;
+           strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0) {
+               return -ENOEXEC;
        }
-       
-       
        /* First of all, some simple consistency checks */
        if ((elf_ex.e_type != ET_EXEC &&
-           elf_ex.e_type != ET_DYN) || 
-          (! elf_check_arch(elf_ex.e_machine)) ||
-          (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-           !bprm->inode->i_op->default_file_ops->mmap)){
+            elf_ex.e_type != ET_DYN) ||
+           (!elf_check_arch(elf_ex.e_machine)) ||
+           (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+            !bprm->inode->i_op->default_file_ops->mmap)) {
                return -ENOEXEC;
        }
-       
        /* Now read in all of the header information */
-       
-       elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
-                                                elf_ex.e_phnum, GFP_KERNEL);
+
+       elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
+                                            elf_ex.e_phnum, GFP_KERNEL);
        if (elf_phdata == NULL) {
                return -ENOMEM;
        }
-       
        retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
                           elf_ex.e_phentsize * elf_ex.e_phnum, 1);
        if (retval < 0) {
-               kfree (elf_phdata);
+               kfree(elf_phdata);
                return retval;
        }
-       
        elf_ppnt = elf_phdata;
-       
+
        elf_bss = 0;
        elf_brk = 0;
-       
+
        elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
 
        if (elf_exec_fileno < 0) {
-               kfree (elf_phdata);
+               kfree(elf_phdata);
                return elf_exec_fileno;
        }
-       
        file = current->files->fd[elf_exec_fileno];
-       
+
        elf_stack = ~0UL;
        elf_interpreter = NULL;
        start_code = ~0UL;
        end_code = 0;
        end_data = 0;
-       
-       for(i=0;i < elf_ex.e_phnum; i++){
+
+       for (i = 0; i < elf_ex.e_phnum; i++) {
                if (elf_ppnt->p_type == PT_INTERP) {
-                       if ( elf_interpreter != NULL )
-                       {
-                               kfree (elf_phdata);
+                       if (elf_interpreter != NULL) {
+                               iput(interpreter_inode);
+                               kfree(elf_phdata);
                                kfree(elf_interpreter);
                                sys_close(elf_exec_fileno);
                                return -EINVAL;
                        }
-
                        /* This is the program interpreter used for
                         * shared libraries - for now assume that this
                         * is an a.out format binary 
                         */
-                       
-                       elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
+
+                       elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
                                                           GFP_KERNEL);
                        if (elf_interpreter == NULL) {
-                               kfree (elf_phdata);
+                               kfree(elf_phdata);
                                sys_close(elf_exec_fileno);
                                return -ENOMEM;
                        }
-                       
-                       retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+                       retval = read_exec(bprm->inode, elf_ppnt->p_offset,
                                           elf_interpreter,
                                           elf_ppnt->p_filesz, 1);
                        /* If the program interpreter is one of these two,
                           then assume an iBCS2 image. Otherwise assume
                           a native linux image. */
-                       if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
-                           strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
-                         ibcs2_interpreter = 1;
+                       if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 ||
+                       strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0)
+                               ibcs2_interpreter = 1;
 #if 0
                        printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
                        if (retval >= 0) {
-                               old_fs = get_fs(); /* This could probably be optimized */
+                               old_fs = get_fs();      /* This could probably be optimized */
                                set_fs(get_ds());
-                               retval = open_namei(elf_interpreter, 0, 0,
-                                                   &interpreter_inode, NULL);
+                               retval = ret_namei = open_namei(elf_interpreter, 0, 0,
+                                              &interpreter_inode, NULL);
                                set_fs(old_fs);
                        }
+                       if (retval >= 0)
+                               retval = permission(interpreter_inode, MAY_EXEC);
+                       if (retval >= 0)
+                               retval = S_ISREG(interpreter_inode->i_mode) ? 0 : -EACCES;
 
                        if (retval >= 0)
-                               retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
-                       
+                               retval = read_exec(interpreter_inode, 0, bprm->buf, 128, 1);
+
                        if (retval >= 0) {
-                               interp_ex = *((struct exec *) bprm->buf);               /* exec-header */
-                               interp_elf_ex = *((struct elfhdr *) bprm->buf);   /* exec-header */
-                               
+                               interp_ex = *((struct exec *) bprm->buf);       /* exec-header */
+                               interp_elf_ex = *((struct elfhdr *) bprm->buf);         /* exec-header */
+
                        }
                        if (retval < 0) {
-                               kfree (elf_phdata);
+                               if (ret_namei >= 0)
+                                       iput(interpreter_inode);
+                               kfree(elf_phdata);
                                kfree(elf_interpreter);
                                sys_close(elf_exec_fileno);
                                return retval;
@@ -502,56 +498,56 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        }
 
        /* Some simple consistency checks for the interpreter */
-       if (elf_interpreter){
+       if (elf_interpreter) {
                interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 
                /* Now figure out which format our binary is */
-               if ((N_MAGIC(interp_ex) != OMAGIC) && 
+               if ((N_MAGIC(interp_ex) != OMAGIC) &&
                    (N_MAGIC(interp_ex) != ZMAGIC) &&
-                   (N_MAGIC(interp_ex) != QMAGIC)) 
-                 interpreter_type = INTERPRETER_ELF;
+                   (N_MAGIC(interp_ex) != QMAGIC))
+                       interpreter_type = INTERPRETER_ELF;
 
                if (interp_elf_ex.e_ident[0] != 0x7f ||
-                   strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
-                 interpreter_type &= ~INTERPRETER_ELF;
-
-               if (!interpreter_type)
-                 {
-                   kfree(elf_interpreter);
-                   kfree(elf_phdata);
-                   sys_close(elf_exec_fileno);
-                   return -ELIBBAD;
-                 }
+                   strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0)
+                       interpreter_type &= ~INTERPRETER_ELF;
+
+               if (!interpreter_type) {
+                       iput(interpreter_inode);
+                       kfree(elf_interpreter);
+                       kfree(elf_phdata);
+                       sys_close(elf_exec_fileno);
+                       return -ELIBBAD;
+               }
        }
-       
        /* OK, we are done with that, now set up the arg stuff,
           and then start this sucker up */
-       
+
        if (!bprm->sh_bang) {
-               char * passed_p;
-               
+               char *passed_p;
+
                if (interpreter_type == INTERPRETER_AOUT) {
-                 sprintf(passed_fileno, "%d", elf_exec_fileno);
-                 passed_p = passed_fileno;
-               
-                 if (elf_interpreter) {
-                   bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
-                   bprm->argc++;
-                 }
+                       sprintf(passed_fileno, "%d", elf_exec_fileno);
+                       passed_p = passed_fileno;
+
+                       if (elf_interpreter) {
+                               bprm->p = copy_strings(1, &passed_p, bprm->page, bprm->p, 2);
+                               bprm->argc++;
+                       }
                }
                if (!bprm->p) {
                        if (elf_interpreter) {
-                             kfree(elf_interpreter);
+                               kfree(elf_interpreter);
                        }
-                       kfree (elf_phdata);
+                       iput(interpreter_inode);
+                       kfree(elf_phdata);
                        sys_close(elf_exec_fileno);
                        return -E2BIG;
                }
        }
-       
-       if (flush_old_exec(bprm))
+       if (flush_old_exec(bprm)) {
+               iput(interpreter_inode);
                return -ENOMEM;
-
+       }
        /* OK, This is the point of no return */
 
        current->mm->end_data = 0;
@@ -559,86 +555,93 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->mm->start_mmap = ELF_START_MMAP;
        current->mm->mmap = NULL;
        elf_entry = (unsigned long) elf_ex.e_entry;
-       
+
        /* Do this so that we can load the interpreter, if need be.  We will
           change some of these later */
        current->mm->rss = 0;
        bprm->p = setup_arg_pages(bprm->p, bprm);
        current->mm->start_stack = bprm->p;
-       
+
        /* Now we do a little grungy work by mmaping the ELF image into
           the correct location in memory.  At this point, we assume that
           the image should be loaded at fixed address, not at a variable
           address. */
-       
+
        old_fs = get_fs();
        set_fs(get_ds());
-       for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+       for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
                if (elf_ppnt->p_type == PT_LOAD) {
                        int elf_prot = 0;
-                       if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
-                       if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-                       if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+                       if (elf_ppnt->p_flags & PF_R)
+                               elf_prot |= PROT_READ;
+                       if (elf_ppnt->p_flags & PF_W)
+                               elf_prot |= PROT_WRITE;
+                       if (elf_ppnt->p_flags & PF_X)
+                               elf_prot |= PROT_EXEC;
 
                        error = do_mmap(file,
                                        ELF_PAGESTART(elf_ppnt->p_vaddr),
                                        (elf_ppnt->p_filesz +
-                                        ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+                                     ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
                                        elf_prot,
                                        (MAP_FIXED | MAP_PRIVATE |
                                         MAP_DENYWRITE | MAP_EXECUTABLE),
                                        (elf_ppnt->p_offset -
-                                        ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-                       
+                                    ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
 #ifdef LOW_ELF_STACK
-                       if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) 
+                       if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
                                elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
 #endif
-                       
-                       if (!load_addr_set) { 
-                         load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
-                         load_addr_set = 1;
+
+                       if (!load_addr_set) {
+                               load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+                               load_addr_set = 1;
                        }
                        k = elf_ppnt->p_vaddr;
-                       if (k < start_code) start_code = k;
+                       if (k < start_code)
+                               start_code = k;
                        k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-                       if (k > elf_bss) elf_bss = k;
+                       if (k > elf_bss)
+                               elf_bss = k;
 #if 1
-                       if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+                       if ((elf_ppnt->p_flags & PF_X) && end_code < k)
 #else
-                       if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
+                       if (!(elf_ppnt->p_flags & PF_W) && end_code < k)
 #endif
-                               end_code = k; 
-                       if (end_data < k) end_data = k; 
+                               end_code = k;
+                       if (end_data < k)
+                               end_data = k;
                        k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
-                       if (k > elf_brk) elf_brk = k;                
+                       if (k > elf_brk)
+                               elf_brk = k;
                }
        }
        set_fs(old_fs);
 
        if (elf_interpreter) {
-               if (interpreter_type & 1) 
+               if (interpreter_type & 1)
                        elf_entry = load_aout_interp(&interp_ex,
                                                     interpreter_inode);
-               else if (interpreter_type & 2) 
-                       elf_entry = load_elf_interp(&interp_elf_ex, 
-                                                   interpreter_inode, 
+               else if (interpreter_type & 2)
+                       elf_entry = load_elf_interp(&interp_elf_ex,
+                                                   interpreter_inode,
                                                    &interp_load_addr);
 
                iput(interpreter_inode);
                kfree(elf_interpreter);
-                       
-               if (elf_entry == ~0UL) { 
+
+               if (elf_entry == ~0UL) {
                        printk("Unable to load interpreter\n");
                        kfree(elf_phdata);
                        send_sig(SIGSEGV, current, 0);
                        return 0;
                }
        }
-
        kfree(elf_phdata);
-       
-       if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+
+       if (interpreter_type != INTERPRETER_AOUT)
+               sys_close(elf_exec_fileno);
        current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
 
        if (current->exec_domain && current->exec_domain->use_count)
@@ -662,16 +665,16 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        current->suid = current->euid = current->fsuid = bprm->e_uid;
        current->sgid = current->egid = current->fsgid = bprm->e_gid;
        current->flags &= ~PF_FORKNOEXEC;
-       bprm->p = (unsigned long) 
-         create_elf_tables((char *)bprm->p,
-                       bprm->argc,
-                       bprm->envc,
-                       (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
-                       load_addr,
-                       interp_load_addr,
-                       (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+       bprm->p = (unsigned long)
+           create_elf_tables((char *) bprm->p,
+                             bprm->argc,
+                             bprm->envc,
+                 (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+                             load_addr,
+                             interp_load_addr,
+                        (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
        if (interpreter_type == INTERPRETER_AOUT)
-         current->mm->arg_start += strlen(passed_fileno) + 1;
+               current->mm->arg_start += strlen(passed_fileno) + 1;
        current->mm->start_brk = current->mm->brk = elf_brk;
        current->mm->end_code = end_code;
        current->mm->start_code = start_code;
@@ -685,16 +688,15 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        padzero(elf_bss);
 
 #if 0
-       printk("(start_brk) %x\n" , current->mm->start_brk);
-       printk("(end_code) %x\n" , current->mm->end_code);
-       printk("(start_code) %x\n" , current->mm->start_code);
-       printk("(end_data) %x\n" , current->mm->end_data);
-       printk("(start_stack) %x\n" , current->mm->start_stack);
-       printk("(brk) %x\n" , current->mm->brk);
+       printk("(start_brk) %x\n", current->mm->start_brk);
+       printk("(end_code) %x\n", current->mm->end_code);
+       printk("(start_code) %x\n", current->mm->start_code);
+       printk("(end_data) %x\n", current->mm->end_data);
+       printk("(start_stack) %x\n", current->mm->start_stack);
+       printk("(brk) %x\n", current->mm->brk);
 #endif
 
-       if ( current->personality == PER_SVR4 )
-       {
+       if (current->personality == PER_SVR4) {
                /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
                   and some applications "depend" upon this behavior.
                   Since we do not have the power to recompile these, we
@@ -702,7 +704,6 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE, 0);
        }
-
 #ifdef ELF_PLAT_INIT
        /*
         * The ABI may specify that certain registers be set up in special
@@ -720,8 +721,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        return 0;
 }
 
-static int
-load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
        int retval;
 
@@ -734,24 +734,24 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 /* This is really simpleminded and specialized - we are loading an
    a.out library that is given an ELF header. */
 
-static inline int
-do_load_elf_library(int fd){
-       struct file * file;
+static inline int do_load_elf_library(int fd)
+{
+       struct file *file;
        struct elfhdr elf_ex;
-       struct elf_phdr *elf_phdata  =  NULL;
-       struct  inode * inode;
+       struct elf_phdr *elf_phdata = NULL;
+       struct inode *inode;
        unsigned long len;
        int elf_bss;
        int retval;
        unsigned long bss;
        int error;
-       int i,j, k;
+       int i, j, k;
 
        len = 0;
        file = current->files->fd[fd];
        inode = file->f_inode;
        elf_bss = 0;
-       
+
        if (!file || !file->f_op)
                return -EACCES;
 
@@ -769,39 +769,40 @@ do_load_elf_library(int fd){
                return -ENOEXEC;
 
        if (elf_ex.e_ident[0] != 0x7f ||
-           strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+           strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
                return -ENOEXEC;
 
        /* First of all, some simple consistency checks */
        if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
-          !elf_check_arch(elf_ex.e_machine) ||
-          (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+           !elf_check_arch(elf_ex.e_machine) ||
+           (!inode->i_op || !inode->i_op->default_file_ops->mmap))
                return -ENOEXEC;
-       
+
        /* Now read in all of the header information */
-       
+
        if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
-               return -ENOEXEC;
-       
-       elf_phdata =  (struct elf_phdr *) 
-               kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+                return -ENOEXEC;
+
+       elf_phdata = (struct elf_phdr *)
+           kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
        if (elf_phdata == NULL)
                return -ENOMEM;
-       
+
        retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
                           sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
-       
+
        j = 0;
-       for(i=0; i<elf_ex.e_phnum; i++)
-               if ((elf_phdata + i)->p_type == PT_LOAD) j++;
-       
-       if (j != 1)  {
+       for (i = 0; i < elf_ex.e_phnum; i++)
+               if ((elf_phdata + i)->p_type == PT_LOAD)
+                       j++;
+
+       if (j != 1) {
                kfree(elf_phdata);
                return -ENOEXEC;
        }
-       
-       while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-       
+       while (elf_phdata->p_type != PT_LOAD)
+               elf_phdata++;
+
        /* Now use mmap to map the library into memory. */
        error = do_mmap(file,
                        ELF_PAGESTART(elf_phdata->p_vaddr),
@@ -813,21 +814,21 @@ do_load_elf_library(int fd){
                         ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
 
        k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
-       if (k > elf_bss) elf_bss = k;
-       
+       if (k > elf_bss)
+               elf_bss = k;
+
        if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
                kfree(elf_phdata);
                return error;
        }
-
        padzero(elf_bss);
 
-       len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
+       len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_EXEC_PAGESIZE - 1);
        bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
        if (bss > len)
-         do_mmap(NULL, len, bss-len,
-                 PROT_READ|PROT_WRITE|PROT_EXEC,
-                 MAP_FIXED|MAP_PRIVATE, 0);
+               do_mmap(NULL, len, bss - len,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED | MAP_PRIVATE, 0);
        kfree(elf_phdata);
        return 0;
 }
@@ -882,12 +883,12 @@ static int dump_seek(struct file *file, off_t off)
  */
 static inline int maydump(struct vm_area_struct *vma)
 {
-       if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+       if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                return 0;
 #if 1
-       if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+       if (vma->vm_flags & (VM_WRITE | VM_GROWSUP | VM_GROWSDOWN))
                return 1;
-       if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+       if (vma->vm_flags & (VM_READ | VM_EXEC | VM_EXECUTABLE | VM_SHARED))
                return 0;
 #endif
        return 1;
@@ -896,8 +897,7 @@ static inline int maydump(struct vm_area_struct *vma)
 #define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
 
 /* An ELF note in memory */
-struct memelfnote
-{
+struct memelfnote {
        const char *name;
        int type;
        unsigned int datasz;
@@ -907,32 +907,33 @@ struct memelfnote
 static int notesize(struct memelfnote *en)
 {
        int sz;
-       
+
        sz = sizeof(struct elf_note);
        sz += roundup(strlen(en->name), 4);
        sz += roundup(en->datasz, 4);
-       
+
        return sz;
 }
 
 /* #define DEBUG */
 
 #ifdef DEBUG
-static void dump_regs(const char *str, elf_greg_t *r)
+static void dump_regs(const char *str, elf_greg_t * r)
 {
        int i;
-       static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
-                                             "eax", "ds", "es", "fs", "gs",
-                                             "orig_eax", "eip", "cs",
-                                             "efl", "uesp", "ss"};
+       static const char *regs[] =
+       {"ebx", "ecx", "edx", "esi", "edi", "ebp",
+        "eax", "ds", "es", "fs", "gs",
+        "orig_eax", "eip", "cs",
+        "efl", "uesp", "ss"};
        printk("Registers: %s\n", str);
 
-       for(i = 0; i < ELF_NGREG; i++)
-       {
+       for (i = 0; i < ELF_NGREG; i++) {
                unsigned long val = r[i];
                printk("   %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
        }
 }
+
 #endif
 
 #define DUMP_WRITE(addr, nr)   \
@@ -951,10 +952,10 @@ static int writenote(struct memelfnote *men, struct file *file)
        DUMP_WRITE(&en, sizeof(en));
        DUMP_WRITE(men->name, en.n_namesz);
        /* XXX - cast from long long to long to avoid need for libgcc.a */
-       DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));      /* XXX */
+       DUMP_SEEK(roundup((unsigned long) file->f_pos, 4));     /* XXX */
        DUMP_WRITE(men->data, men->datasz);
-       DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));      /* XXX */
-       
+       DUMP_SEEK(roundup((unsigned long) file->f_pos, 4));     /* XXX */
+
        return 1;
 }
 #undef DUMP_WRITE
@@ -973,13 +974,13 @@ static int writenote(struct memelfnote *men, struct file *file)
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_core_dump(long signr, struct pt_regs * regs)
+static int elf_core_dump(long signr, struct pt_regs *regs)
 {
        int has_dumped = 0;
        struct file file;
        struct inode *inode;
        unsigned short fs;
-       char corefile[6+sizeof(current->comm)];
+       char corefile[6 + sizeof(current->comm)];
        int segs;
        int i;
        size_t size;
@@ -990,9 +991,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        int numnote = 4;
        struct memelfnote notes[4];
        struct elf_prstatus prstatus;   /* NT_PRSTATUS */
-       elf_fpregset_t fpu;             /* NT_PRFPREG */
+       elf_fpregset_t fpu;     /* NT_PRFPREG */
        struct elf_prpsinfo psinfo;     /* NT_PRPSINFO */
-       
+
        if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
                return 0;
        current->dumpable = 0;
@@ -1004,17 +1005,15 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        /* Count what's needed to dump, up to the limit of coredump size */
        segs = 0;
        size = 0;
-       for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-               if (maydump(vma))
-               {
-                       int sz = vma->vm_end-vma->vm_start;
-               
-                       if (size+sz >= limit)
+       for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+               if (maydump(vma)) {
+                       int sz = vma->vm_end - vma->vm_start;
+
+                       if (size + sz >= limit)
                                break;
                        else
                                size += sz;
                }
-               
                segs++;
        }
 #ifdef DEBUG
@@ -1026,8 +1025,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        elf.e_ident[EI_CLASS] = ELF_CLASS;
        elf.e_ident[EI_DATA] = ELF_DATA;
        elf.e_ident[EI_VERSION] = EV_CURRENT;
-       memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-       
+       memset(elf.e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD);
+
        elf.e_type = ET_CORE;
        elf.e_machine = ELF_ARCH;
        elf.e_version = EV_CURRENT;
@@ -1037,20 +1036,20 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        elf.e_flags = 0;
        elf.e_ehsize = sizeof(elf);
        elf.e_phentsize = sizeof(struct elf_phdr);
-       elf.e_phnum = segs+1;           /* Include notes */
+       elf.e_phnum = segs + 1; /* Include notes */
        elf.e_shentsize = 0;
        elf.e_shnum = 0;
        elf.e_shstrndx = 0;
-       
+
        fs = get_fs();
        set_fs(KERNEL_DS);
-       memcpy(corefile,"core.",5);
+       memcpy(corefile, "core.", 5);
 #if 0
-       memcpy(corefile+5,current->comm,sizeof(current->comm));
+       memcpy(corefile + 5, current->comm, sizeof(current->comm));
 #else
        corefile[4] = '\0';
 #endif
-       if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+       if (open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600, &inode, NULL)) {
                inode = NULL;
                goto end_coredump;
        }
@@ -1066,7 +1065,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        file.f_reada = 0;
        file.f_op = inode->i_op->default_file_ops;
        if (file.f_op->open)
-               if (file.f_op->open(inode,&file))
+               if (file.f_op->open(inode, &file))
                        goto end_coredump;
        if (!file.f_op->write)
                goto close_coredump;
@@ -1074,8 +1073,8 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        current->flags |= PF_DUMPCORE;
 
        DUMP_WRITE(&elf, sizeof(elf));
-       offset += sizeof(elf);                          /* Elf header */
-       offset += (segs+1) * sizeof(struct elf_phdr);   /* Program headers */
+       offset += sizeof(elf);  /* Elf header */
+       offset += (segs + 1) * sizeof(struct elf_phdr);         /* Program headers */
 
        /*
         * Set up the notes in similar form to SVR4 core dumps made
@@ -1111,18 +1110,16 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
 #ifdef ELF_CORE_COPY_REGS
        ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
 #else
-       if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
-       {
+       if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
                printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
-                       sizeof(elf_gregset_t), sizeof(struct pt_regs));
-       }
-       else
-               *(struct pt_regs *)&prstatus.pr_reg = *regs;
+                      sizeof(elf_gregset_t), sizeof(struct pt_regs));
+       } else
+               *(struct pt_regs *) &prstatus.pr_reg = *regs;
 #endif
-       
+
 #ifdef DEBUG
-       dump_regs("Passed in regs", (elf_greg_t *)regs);
-       dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
+       dump_regs("Passed in regs", (elf_greg_t *) regs);
+       dump_regs("prstatus regs", (elf_greg_t *) & prstatus.pr_reg);
 #endif
 
        notes[1].name = "CORE";
@@ -1132,7 +1129,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        psinfo.pr_state = current->state;
        psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
        psinfo.pr_zomb = psinfo.pr_sname == 'Z';
-       psinfo.pr_nice = current->priority-15;
+       psinfo.pr_nice = current->priority - 15;
        psinfo.pr_flag = current->flags;
        psinfo.pr_uid = current->uid;
        psinfo.pr_gid = current->gid;
@@ -1140,12 +1137,12 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                int i, len;
 
                set_fs(fs);
-               
+
                len = current->mm->arg_end - current->mm->arg_start;
-               len = (len >= ELF_PRARGSZ-1) ? ELF_PRARGSZ-1 : len;
+               len = (len >= ELF_PRARGSZ - 1) ? ELF_PRARGSZ - 1 : len;
                memcpy_fromfs(&psinfo.pr_psargs,
-                             (const char *)current->mm->arg_start, len);
-               for(i = 0; i < len; i++)
+                             (const char *) current->mm->arg_start, len);
+               for (i = 0; i < len; i++)
                        if (psinfo.pr_psargs[i] == 0)
                                psinfo.pr_psargs[i] = ' ';
                psinfo.pr_psargs[len] = 0;
@@ -1158,29 +1155,26 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        notes[2].type = NT_TASKSTRUCT;
        notes[2].datasz = sizeof(*current);
        notes[2].data = current;
-       
+
        /* Try to dump the fpu. */
-       prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
-       if (!prstatus.pr_fpvalid)
-       {
+       prstatus.pr_fpvalid = dump_fpu(regs, &fpu);
+       if (!prstatus.pr_fpvalid) {
                numnote--;
-       }
-       else
-       {
+       } else {
                notes[3].name = "CORE";
                notes[3].type = NT_PRFPREG;
                notes[3].datasz = sizeof(fpu);
                notes[3].data = &fpu;
        }
-       
+
        /* Write notes phdr entry */
        {
                struct elf_phdr phdr;
                int sz = 0;
 
-               for(i = 0; i < numnote; i++)
+               for (i = 0; i < numnote; i++)
                        sz += notesize(&notes[i]);
-               
+
                phdr.p_type = PT_NOTE;
                phdr.p_offset = offset;
                phdr.p_vaddr = 0;
@@ -1196,17 +1190,17 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
 
        /* Page-align dumped data */
        dataoff = offset = roundup(offset, PAGE_SIZE);
-       
+
        /* Write program headers for segments dump */
-       for(vma = current->mm->mmap, i = 0;
-               i < segs && vma != NULL; vma = vma->vm_next) {
+       for (vma = current->mm->mmap, i = 0;
+            i < segs && vma != NULL; vma = vma->vm_next) {
                struct elf_phdr phdr;
                size_t sz;
 
                i++;
 
                sz = vma->vm_end - vma->vm_start;
-               
+
                phdr.p_type = PT_LOAD;
                phdr.p_offset = offset;
                phdr.p_vaddr = vma->vm_start;
@@ -1215,34 +1209,36 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                phdr.p_memsz = sz;
                offset += phdr.p_filesz;
                phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
-               if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
-               if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+               if (vma->vm_flags & VM_WRITE)
+                       phdr.p_flags |= PF_W;
+               if (vma->vm_flags & VM_EXEC)
+                       phdr.p_flags |= PF_X;
                phdr.p_align = PAGE_SIZE;
 
                DUMP_WRITE(&phdr, sizeof(phdr));
        }
 
-       for(i = 0; i < numnote; i++)
+       for (i = 0; i < numnote; i++)
                if (!writenote(&notes[i], &file))
                        goto close_coredump;
-       
+
        set_fs(fs);
 
        DUMP_SEEK(dataoff);
-       
-       for(i = 0, vma = current->mm->mmap;
-           i < segs && vma != NULL;
-           vma = vma->vm_next) {
+
+       for (i = 0, vma = current->mm->mmap;
+            i < segs && vma != NULL;
+            vma = vma->vm_next) {
                unsigned long addr = vma->vm_start;
                unsigned long len = vma->vm_end - vma->vm_start;
-               
+
                i++;
                if (!maydump(vma))
                        continue;
 #ifdef DEBUG
                printk("elf_core_dump: writing %08lx %lx\n", addr, len);
 #endif
-               DUMP_WRITE((void *)addr, len);
+               DUMP_WRITE((void *) addr, len);
        }
 
        if ((off_t) file.f_pos != offset) {
@@ -1250,12 +1246,11 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
                       (off_t) file.f_pos, offset);
        }
-
- close_coredump:
+      close_coredump:
        if (file.f_op->release)
-               file.f_op->release(inode,&file);
+               file.f_op->release(inode, &file);
 
- end_coredump:
     end_coredump:
        set_fs(fs);
        iput(inode);
 #ifndef CONFIG_BINFMT_ELF
@@ -1263,16 +1258,16 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
 #endif
        return has_dumped;
 }
-#endif         /* USE_ELF_CORE_DUMP */
+#endif                         /* USE_ELF_CORE_DUMP */
 
-int init_elf_binfmt(void) 
+int init_elf_binfmt(void)
 {
        return register_binfmt(&elf_format);
 }
 
 #ifdef MODULE
 
-int init_module(void) 
+int init_module(void)
 {
        /* Install the COFF, ELF and XOUT loaders.
         * N.B. We *rely* on the table being the right size with the
@@ -1282,9 +1277,10 @@ int init_module(void)
 }
 
 
-void cleanup_module( void) 
+void cleanup_module(void)
 {
        /* Remove the COFF and ELF loaders. */
        unregister_binfmt(&elf_format);
 }
+
 #endif
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
new file mode 100644 (file)
index 0000000..ca99226
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *  linux/fs/binfmt_em86.c
+ *
+ *  Based on linux/fs/binfmt_script.c
+ *  Copyright (C) 1996  Martin von Löwis
+ *  original #!-checking implemented by tytso.
+ *
+ *  em86 changes Copyright (C) 1997  Jim Paradis
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+
+#define EM86_INTERP    "/usr/bin/em86"
+#define EM86_I_NAME    "em86"
+
+static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+       char *cp, *interp, *i_name, *i_arg;
+       int retval;
+       struct elfhdr   elf_ex;
+       uid_t           x86_uid;
+       gid_t           x86_gid;
+
+       /* Make sure this is a Linux/Intel ELF executable... */
+       elf_ex = *((struct elfhdr *)bprm->buf);
+       
+        if (elf_ex.e_ident[0] != 0x7f ||
+            strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
+                return  -ENOEXEC;
+        }
+
+
+        /* First of all, some simple consistency checks */
+        if ((elf_ex.e_type != ET_EXEC &&
+            elf_ex.e_type != ET_DYN) ||
+           (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
+           (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+            !bprm->inode->i_op->default_file_ops->mmap)){
+                return -ENOEXEC;
+        }
+
+       bprm->sh_bang++;        /* Well, the bang-shell is implicit... */
+       iput(bprm->inode);
+       bprm->dont_iput = 1;
+
+       /* Unlike in the script case, we don't have to do any hairy
+        * parsing to find our interpreter... it's hardcoded!
+        */
+       interp = EM86_INTERP;
+       i_name = EM86_I_NAME;
+       i_arg = NULL;           /* We reserve the right to add an arg later */
+
+       /*
+        * Splice in (1) the interpreter's name for argv[0]
+        *           (2) (optional) argument to interpreter
+        *           (3) filename of emulated file (replace argv[0])
+        *
+        * This is done in reverse order, because of how the
+        * user environment and arguments are stored.
+        */
+       remove_arg_zero(bprm);
+       bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+       bprm->argc++;
+       if (i_arg) {
+               bprm->p = copy_strings(1, &i_arg, bprm->page, bprm->p, 2);
+               bprm->argc++;
+       }
+       bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
+       bprm->argc++;
+       if (!bprm->p) 
+               return -E2BIG;
+       /*
+        * OK, now restart the process with the interpreter's inode.
+        * Note that we use open_namei() as the name is now in kernel
+        * space, and we don't need to copy it.
+        */
+       retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
+       if (retval)
+               return retval;
+       bprm->dont_iput=0;
+
+       /* Remember the uid/gid that was set by this executable */
+       x86_uid = bprm->e_uid;
+       x86_gid = bprm->e_gid;
+       retval=prepare_binprm(bprm);
+       if(retval<0)
+               return retval;
+
+       /* ...so that we may propagate them to em86 */
+       bprm->e_uid = x86_uid;
+       bprm->e_gid = x86_gid;
+       current->personality = PER_LINUX_EM86;
+       return search_binary_handler(bprm,regs);
+}
+
+static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+       int retval;
+       MOD_INC_USE_COUNT;
+       retval = do_load_em86(bprm,regs);
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+struct linux_binfmt em86_format = {
+#ifndef MODULE
+       NULL, 0, load_em86, NULL, NULL
+#else
+       NULL, &mod_use_count_, load_em86, NULL, NULL
+#endif
+};
+
+int init_em86_binfmt(void) {
+       return register_binfmt(&em86_format);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return init_em86_binfmt();
+}
+
+void cleanup_module( void) {
+       unregister_binfmt(&em86_format);
+}
+#endif
index ed101ec0241cd46f9ac97951bd24812da3f42892..7d1aec49fde03d1a8547f41a77c5bba7ae65b950 100644 (file)
@@ -1249,6 +1249,8 @@ void unlock_buffer(struct buffer_head * bh)
 
        clear_bit(BH_Lock, &bh->b_state);
        wake_up(&bh->b_wait);
+       if (waitqueue_active(&buffer_wait))
+               wake_up(&buffer_wait);
 
        if (!test_bit(BH_FreeOnIO, &bh->b_state))
                return;
index 0190764ba76957bed0822cbaa73f8d88e39083f5..4ad2789037c18a0cc750db5380d4450c11024e2d 100644 (file)
@@ -1080,6 +1080,9 @@ asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
                        return(-EINVAL);
        }
 
+       if (id & ~0xFFFF)
+               return(-EINVAL);
+
        flags |= QUOTA_SYSCALL;
        if (has_quota_enabled(dev, type))
                return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr));
index a1b70b7564b7401b79c32394008b39dd2c1c7510..6dd924d33b77c4dafb77bba59f874f59598e98f3 100644 (file)
@@ -573,6 +573,7 @@ static int empty_dir (struct inode * inode)
                ext2_warning (inode->i_sb, "empty_dir",
                              "bad directory (dir #%lu) - no `.' or `..'",
                              inode->i_ino);
+               brelse (bh);
                return 1;
        }
        offset = de->rec_len + de1->rec_len;
index ea135700cd2fd842f40e5624e160877aed29780b..38ce8af2c146a5b4b04603f617a19ac6c2c2f72e 100644 (file)
@@ -112,18 +112,6 @@ uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
 }
 
 
-static void dump_de(struct msdos_dir_entry *de)
-{
-       int i;
-       unsigned char *p = (unsigned char *) de;
-       printk("[");
-
-       for (i = 0; i < 32; i++, p++) {
-               printk("%02x ", *p);
-       }
-       printk("]\n");
-}
-
 int fat_readdirx(
        struct inode *inode,
        struct file *filp,
@@ -172,9 +160,6 @@ int fat_readdirx(
        is_long = 0;
        ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
        while (ino > -1) {
-#if 0
-               dump_de(de);
-#endif
                /* Check for long filename entry */
                if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) {
                        is_long = 0;
index 1d62dcf53ac63e542e04f2bace2b5f88ec30ed14..d7e2fc621c8b561d4d611c1d47cca2f628d678d3 100644 (file)
@@ -629,26 +629,28 @@ int isofs_bmap(struct inode * inode,int block)
                inode->i_ino, nextino, firstext, size);
 #endif
        i = 0;
-       while(b_off >= offset + size) {
-               offset += size;
-
-               if(nextino == 0) return 0;
-               ino = iget(inode->i_sb, nextino);
-               if(!ino) return 0;
-               firstext = ino->u.isofs_i.i_first_extent;
-               size = ino->u.isofs_i.i_section_size;
+       if (nextino) {
+               while(b_off >= offset + size) {
+                       offset += size;
+
+                       if(nextino == 0) return 0;
+                       ino = iget(inode->i_sb, nextino);
+                       if(!ino) return 0;
+                       firstext = ino->u.isofs_i.i_first_extent;
+                       size = ino->u.isofs_i.i_section_size;
 #ifdef DEBUG
-               printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
-                       inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
+                       printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
+                              inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
 #endif
-               nextino = ino->u.isofs_i.i_next_section_ino;
-               iput(ino);
+                       nextino = ino->u.isofs_i.i_next_section_ino;
+                       iput(ino);
                
-               if(++i > 100) {
-                       printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
-                       printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
-                               inode->i_ino, block, firstext, (unsigned)size, nextino);
-                       return 0;
+                       if(++i > 100) {
+                               printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+                               printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
+                                      inode->i_ino, block, firstext, (unsigned)size, nextino);
+                               return 0;
+                       }
                }
        }
 #ifdef DEBUG
index 4a52f1b42572da022f2e4266bd1ac8b2eb34dd7f..479f08b0832cdadebcaf324f9b30355a222b984c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/personality.h>
 #include <linux/mm.h>
+#include <linux/file.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -56,6 +57,34 @@ static void free_wait(select_table * p)
        }
 }
 
+/*
+ *     File handle locking
+ */
+static void lock_fd_bits(int n, int x)
+{
+       int i;
+       for(i=0;i<__NFDBITS;i++)
+       {
+               if(x&(1<<i))
+                       fget(n+i);
+       }
+}
+
+static void unlock_fd_bits(int n, int x)
+{
+       int i;
+       for(i=0;i<__NFDBITS;i++)
+       {
+               if(x&(1<<i))
+               {
+                       /* ick */
+                       struct file *f=current->files->fd[n+i];
+                       fput(f, f->f_inode);
+               }
+       }
+}
+
 /*
  * The check function checks the ready status of a file using the vfs layer.
  *
@@ -83,7 +112,7 @@ static int check(int flag, select_table * wait, struct file * file)
 }
 
 static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
-       fd_set *res_in, fd_set *res_out, fd_set *res_ex)
+       fd_set *res_in, fd_set *res_out, fd_set *res_ex, fd_set *locked)
 {
        int count;
        select_table wait_table, *wait;
@@ -91,7 +120,7 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
        unsigned long set;
        int i,j;
        int max = -1;
-
+       int threaded = 0;
        j = 0;
        for (;;) {
                i = j * __NFDBITS;
@@ -113,8 +142,34 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
        }
 end_check:
        n = max + 1;
+       
+       /* Now we _must_ lock the handles before we get the page otherwise
+          they may get closed on us during the kmalloc causing explosions.. */
+       
+       if(current->files->count>1)
+       {       
+       
+               /*
+                *      Only for the threaded cases must we do work.
+                */
+               j = 0;
+               for (;;) {
+                       i = j * __NFDBITS;
+                       if (i >= n)
+                               break;
+                       lock_fd_bits(i,in->fds_bits[j]);
+                       lock_fd_bits(i,out->fds_bits[j]);
+                       lock_fd_bits(i,ex->fds_bits[j]);
+                       j++;
+               }
+               threaded=1;
+       }
+               
        if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+       {
+               count = -ENOMEM; 
+               goto bale;
+       }
        count = 0;
        wait_table.nr = 0;
        wait_table.entry = entry;
@@ -149,6 +204,22 @@ repeat:
        free_wait(&wait_table);
        free_page((unsigned long) entry);
        current->state = TASK_RUNNING;
+bale:
+
+       if(threaded)
+       {
+               /* Unlock handles now */        
+               j = 0;
+               for (;;) {
+                       i = j * __NFDBITS;
+                       if (i >= n)
+                               break;
+                       unlock_fd_bits(i,in->fds_bits[j]);
+                       unlock_fd_bits(i,out->fds_bits[j]);
+                       unlock_fd_bits(i,ex->fds_bits[j]);
+                       j++;
+               }
+       }
        return count;
 }
 
@@ -243,6 +314,7 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
        limited_fd_set res_in, in;
        limited_fd_set res_out, out;
        limited_fd_set res_ex, ex;
+       limited_fd_set locked;
        unsigned long timeout;
 
        error = -EINVAL;
@@ -273,7 +345,8 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
                (fd_set *) &ex,
                (fd_set *) &res_in,
                (fd_set *) &res_out,
-               (fd_set *) &res_ex);
+               (fd_set *) &res_ex,
+               (fd_set *) &locked);
        timeout = current->timeout - jiffies - 1;
        current->timeout = 0;
        if ((long) timeout < 0)
index 689963337b9be9865ad1f30c35c0d9fe8e99962d..f9cdecb9e5ed82038ea6e54b34980c8f5a110ec6 100644 (file)
@@ -972,12 +972,21 @@ static void do_mount_root(void)
 
 #ifdef CONFIG_BLK_DEV_FD
        if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+               extern int rd_doload;
                floppy_eject();
 #ifndef CONFIG_BLK_DEV_RAM
                printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
 #endif
-               printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
-               wait_for_keypress();
+#ifdef CONFIG_BLK_DEV_INITRD
+               /* rd_doload is 2 for a dual initrd/ramload setup */
+               if(rd_doload==2)
+                       rd_load_secondary();
+               else
+#endif         
+               {
+                       printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
+                       wait_for_keypress();
+               }
        }
 #endif
 
index f1965d5cae42832296fc75b5c0c66297cf28670f..bcda70a36539997fdac8d48200a694482eebe3ea 100644 (file)
@@ -90,7 +90,8 @@ struct exec
 
 #ifdef __KERNEL__
 
-#define STACK_TOP (0x00120000000UL)
+#define STACK_TOP ((current->personality & ADDR_MAX_32BIT) ? 0x100000000UL : \
+      ((current->personality&ADDR_MAX_31BIT) ? 0x80000000UL : 0x00120000000UL))
 
 #endif
 
index 0f38c8aac92025c17cb99bbe635c3b300c3c517c..36ac35922d8420f3defb6196c74276efca247050 100644 (file)
@@ -31,7 +31,7 @@
    BIOS ROMs. So we must put the windows high enough to avoid these areas.
 
    We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1,
-   and window 2 at BUS 512Mb for 512Mb, mapping physical 0 to 512Mb-1.
+   and window 2 at BUS 1Gb for 1Gb, mapping physical 0 to 1Gb-1.
    Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually
    be used for that range (via virt_to_bus()).
 
    DMAable memory; they count on being able to DMA to any memory they
    get from kmalloc()/get_free_pages(). They will also use window 1 for
    any physical memory accesses below 64Mb; the rest will be handled by
-   window 2, maxing out at 512Mb of memory. I trust this is enough... :-)
+   window 2, maxing out at 1Gb of memory. I trust this is enough... :-)
 
-   Finally, the reason we make window 2 start at 512Mb for 512Mb, is so that
-   we can allocate PCI bus devices' memory starting at 1Gb and up, to ensure
-   that no conflicts occur and bookkeeping is simplified (ie we don't
-   try to fill the gap between the two windows, we just go above the top).
+   We hope that the area before the first window is large enough so that
+   there will be no overlap at the top end (64Mb). We *must* locate the
+   PCI cards' memory just below window 1, so that there's still the
+   possibility of being able to access it via SPARSE space. This is
+   important for cards such as the Matrox Millennium, whose Xserver
+   wants to access memory-mapped registers in byte and short lengths.
 
    Note that the XL is treated differently from the AVANTI, even though
    for most other things they are identical. It didn't seem reasonable to
 #define APECS_XL_DMA_WIN1_BASE         (64*1024*1024)
 #define APECS_XL_DMA_WIN1_SIZE         (64*1024*1024)
 #define APECS_XL_DMA_WIN1_SIZE_PARANOID        (48*1024*1024)
-#define APECS_XL_DMA_WIN2_BASE         (512*1024*1024)
-#define APECS_XL_DMA_WIN2_SIZE         (512*1024*1024)
+#define APECS_XL_DMA_WIN2_BASE         (1024*1024*1024)
+#define APECS_XL_DMA_WIN2_SIZE         (1024*1024*1024)
 
 #else /* CONFIG_ALPHA_XL */
 
 /* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define APECS_DMA_WIN_BASE_DEFAULT     (1024*1024*1024)
+#define APECS_DMA_WIN_SIZE_DEFAULT     (1024*1024*1024)
+
+extern unsigned int APECS_DMA_WIN_BASE;
+extern unsigned int APECS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define APECS_DMA_WIN_BASE     (1024*1024*1024)
 #define APECS_DMA_WIN_SIZE     (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 #endif /* CONFIG_ALPHA_XL */
 
index 3bd5ea3cf9b33b069dd5201618f2ffebdf825cd0..2d9409ef84b5bd6d9212a138802c0c1dd4b74b33 100644 (file)
 
 #define BYTE_ENABLE_SHIFT 5
 #define TRANSFER_LENGTH_SHIFT 3
-#define MEM_SP1_MASK 0x1fffffff  /* Mem sparse space 1 mask is 29 bits */
 
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
 
-#define CIA_DMA_WIN_BASE       (1024UL*1024UL*1024UL)
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define CIA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define CIA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int CIA_DMA_WIN_BASE;
+extern unsigned int CIA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define CIA_DMA_WIN_BASE            (1024*1024*1024)
 #define CIA_DMA_WIN_SIZE       (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * 21171-CA Control and Status Registers (p4-1)
@@ -86,6 +98,7 @@
 #define CIA_IOC_CIA_REV               (IDENT_ADDR + 0x8740000080UL)
 #define CIA_IOC_PCI_LAT               (IDENT_ADDR + 0x87400000C0UL)
 #define CIA_IOC_CIA_CTRL              (IDENT_ADDR + 0x8740000100UL)
+#define CIA_IOC_CIA_CNFG              (IDENT_ADDR + 0x8740000140UL)
 #define CIA_IOC_HAE_MEM               (IDENT_ADDR + 0x8740000400UL)
 #define CIA_IOC_HAE_IO                (IDENT_ADDR + 0x8740000440UL)
 #define CIA_IOC_CFG                   (IDENT_ADDR + 0x8740000480UL)
 #define CIA_IOC_PCI_ERR3              (IDENT_ADDR + 0x8740008880UL)
 
 /*
- * 2117A-CA PCI Address Translation Registers.   I've only defined
- * the first window fully as that's the only one that we're currently using.
- * The other window bases are needed to disable the windows.
+ * 2117A-CA PCI Address Translation Registers.
  */
 #define CIA_IOC_PCI_TBIA              (IDENT_ADDR + 0x8760000100UL)
+
 #define CIA_IOC_PCI_W0_BASE           (IDENT_ADDR + 0x8760000400UL)
 #define CIA_IOC_PCI_W0_MASK           (IDENT_ADDR + 0x8760000440UL)
 #define CIA_IOC_PCI_T0_BASE           (IDENT_ADDR + 0x8760000480UL)
 
 #define CIA_IOC_PCI_W1_BASE           (IDENT_ADDR + 0x8760000500UL)
+#define CIA_IOC_PCI_W1_MASK           (IDENT_ADDR + 0x8760000540UL)
+#define CIA_IOC_PCI_T1_BASE           (IDENT_ADDR + 0x8760000580UL)
+
 #define CIA_IOC_PCI_W2_BASE           (IDENT_ADDR + 0x8760000600UL)
+#define CIA_IOC_PCI_W2_MASK           (IDENT_ADDR + 0x8760000640UL)
+#define CIA_IOC_PCI_T2_BASE           (IDENT_ADDR + 0x8760000680UL)
+
 #define CIA_IOC_PCI_W3_BASE           (IDENT_ADDR + 0x8760000700UL)
+#define CIA_IOC_PCI_W3_MASK           (IDENT_ADDR + 0x8760000740UL)
+#define CIA_IOC_PCI_T3_BASE           (IDENT_ADDR + 0x8760000780UL)
 
 /*
  * 21171-CA System configuration registers (p4-3)
 #define CIA_CONF                       (IDENT_ADDR + 0x8700000000UL)
 #define CIA_IO                         (IDENT_ADDR + 0x8580000000UL)
 #define CIA_SPARSE_MEM                 (IDENT_ADDR + 0x8000000000UL)
+#define CIA_SPARSE_MEM_R2              (IDENT_ADDR + 0x8400000000UL)
+#define CIA_SPARSE_MEM_R3              (IDENT_ADDR + 0x8500000000UL)
 #define CIA_DENSE_MEM                  (IDENT_ADDR + 0x8600000000UL)
 
 /*
@@ -296,13 +318,125 @@ extern inline void __outl(unsigned int b, unsigned long addr)
  * 
  */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x08);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
 extern inline unsigned long __readb(unsigned long addr)
 {
        unsigned long result, shift, msb;
 
        shift = (addr & 0x3) * 8 ;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -317,7 +451,7 @@ extern inline unsigned long __readw(unsigned long addr)
 
        shift = (addr & 0x3) * 8;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -326,17 +460,12 @@ extern inline unsigned long __readw(unsigned long addr)
        return 0xffffUL & result;
 }
 
-extern inline unsigned long __readl(unsigned long addr)
-{
-       return *(vuip) (addr + CIA_DENSE_MEM);
-}
-
 extern inline void __writeb(unsigned char b, unsigned long addr)
 {
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -348,13 +477,20 @@ extern inline void __writew(unsigned short b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
        *(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x08) = b * 0x00010001;
 }
 
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       return *(vuip) (addr + CIA_DENSE_MEM);
+}
+
 extern inline void __writel(unsigned int b, unsigned long addr)
 {
        *(vuip) (addr + CIA_DENSE_MEM) = b;
@@ -379,48 +515,73 @@ extern unsigned long cia_init (unsigned long mem_start,
 /*
  * Data structure for handling CIA machine checks:
  */
+/* ev5-specific info: */
+struct el_procdata {
+       unsigned long shadow[8];        /* PALmode shadow registers */
+       unsigned long paltemp[24];      /* PAL temporary registers */
+       /* EV5-specific fields */
+       unsigned long exc_addr;         /* Address of excepting instruction. */
+       unsigned long exc_sum;          /* Summary of arithmetic traps. */
+       unsigned long exc_mask;         /* Exception mask (from exc_sum). */
+       unsigned long exc_base;         /* PALbase at time of exception. */
+       unsigned long isr;              /* Interrupt summary register. */
+       unsigned long icsr;             /* Ibox control register. */
+       unsigned long ic_perr_stat;
+       unsigned long dc_perr_stat;
+       unsigned long va;               /* Effective VA of fault or miss. */
+       unsigned long mm_stat;
+       unsigned long sc_addr;
+       unsigned long sc_stat;
+       unsigned long bc_tag_addr;
+       unsigned long ei_addr;
+       unsigned long fill_syn;
+       unsigned long ei_stat;
+       unsigned long ld_lock;
+};
+
+/* system-specific info: */
 struct el_CIA_sysdata_mcheck {
-    u_long      coma_gcr;                       
-    u_long      coma_edsr;                      
-    u_long      coma_ter;                       
-    u_long      coma_elar;                      
-    u_long      coma_ehar;                      
-    u_long      coma_ldlr;                      
-    u_long      coma_ldhr;                      
-    u_long      coma_base0;                     
-    u_long      coma_base1;                     
-    u_long      coma_base2;                     
-    u_long      coma_cnfg0;                     
-    u_long      coma_cnfg1;                     
-    u_long      coma_cnfg2;                     
-    u_long      epic_dcsr;                      
-    u_long      epic_pear;                      
-    u_long      epic_sear;                      
-    u_long      epic_tbr1;                      
-    u_long      epic_tbr2;                      
-    u_long      epic_pbr1;                      
-    u_long      epic_pbr2;                      
-    u_long      epic_pmr1;                      
-    u_long      epic_pmr2;                      
-    u_long      epic_harx1;                     
-    u_long      epic_harx2;                     
-    u_long      epic_pmlt;                      
-    u_long      epic_tag0;                      
-    u_long      epic_tag1;                      
-    u_long      epic_tag2;                      
-    u_long      epic_tag3;                      
-    u_long      epic_tag4;                      
-    u_long      epic_tag5;                      
-    u_long      epic_tag6;                      
-    u_long      epic_tag7;                      
-    u_long      epic_data0;                     
-    u_long      epic_data1;                     
-    u_long      epic_data2;                     
-    u_long      epic_data3;                     
-    u_long      epic_data4;                     
-    u_long      epic_data5;                     
-    u_long      epic_data6;                     
-    u_long      epic_data7;                     
+    unsigned long      coma_gcr;                       
+    unsigned long      coma_edsr;                      
+    unsigned long      coma_ter;                       
+    unsigned long      coma_elar;                      
+    unsigned long      coma_ehar;                      
+    unsigned long      coma_ldlr;                      
+    unsigned long      coma_ldhr;                      
+    unsigned long      coma_base0;                     
+    unsigned long      coma_base1;                     
+    unsigned long      coma_base2;                     
+    unsigned long      coma_cnfg0;                     
+    unsigned long      coma_cnfg1;                     
+    unsigned long      coma_cnfg2;                     
+    unsigned long      epic_dcsr;                      
+    unsigned long      epic_pear;                      
+    unsigned long      epic_sear;                      
+    unsigned long      epic_tbr1;                      
+    unsigned long      epic_tbr2;                      
+    unsigned long      epic_pbr1;                      
+    unsigned long      epic_pbr2;                      
+    unsigned long      epic_pmr1;                      
+    unsigned long      epic_pmr2;                      
+    unsigned long      epic_harx1;                     
+    unsigned long      epic_harx2;                     
+    unsigned long      epic_pmlt;                      
+    unsigned long      epic_tag0;                      
+    unsigned long      epic_tag1;                      
+    unsigned long      epic_tag2;                      
+    unsigned long      epic_tag3;                      
+    unsigned long      epic_tag4;                      
+    unsigned long      epic_tag5;                      
+    unsigned long      epic_tag6;                      
+    unsigned long      epic_tag7;                      
+    unsigned long      epic_data0;                     
+    unsigned long      epic_data1;                     
+    unsigned long      epic_data2;                     
+    unsigned long      epic_data3;                     
+    unsigned long      epic_data4;                     
+    unsigned long      epic_data5;                     
+    unsigned long      epic_data6;                     
+    unsigned long      epic_data7;                     
 };
 
 #define RTC_PORT(x)    (0x70 + (x))
index 05e70c96185abe90160907566e26574f5ec5ac89..7ae23bb41b3cc0808c47f4463f928e9cd9f74f37 100644 (file)
@@ -75,7 +75,9 @@
 
 #define MAX_DMA_CHANNELS       8
 
-#ifdef CONFIG_ALPHA_XL
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#define MAX_DMA_ADDRESS         (0xfffffc0001000000UL) /* yup, 16Mb :-( */
+#elif defined(CONFIG_ALPHA_XL)
 /* The maximum address that we can perform a DMA transfer to on Alpha XL,
    due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
    See <asm/apecs.h> for more info.
    For now, this limit is set to 48Mb...
 */
 #define MAX_DMA_ADDRESS                (0xfffffc0003000000UL)
-#else /* CONFIG_ALPHA_XL */
-/* The maximum address that we can perform a DMA transfer to on normal
-   Alpha platforms */
+#else
+/*
+ * The maximum address that we can perform a DMA transfer to on
+ * normal Alpha platforms
+ */
 #define MAX_DMA_ADDRESS                (~0UL)
-#endif /* CONFIG_ALPHA_XL */
+#endif
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
index 27013a9ecdcfbdd76c5f4b75e233419866ca7897..0a1b217f6ed3bb64d56431fb62be098e0957a7fb 100644 (file)
@@ -51,11 +51,11 @@ static int FDC2 = -1;
 /*
  * Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh...
  */
-#ifdef CONFIG_ALPHA_XL
+#if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN)
 #define CROSS_64KB(a,s) \
     ((unsigned long)(a)/0x10000 != ((unsigned long)(a) + (s) - 1) / 0x10000)
-#else /* CONFIG_ALPHA_XL */
+#else /* XL || RUFFIAN */
 #define CROSS_64KB(a,s) (0)
-#endif /* CONFIG_ALPHA_XL */
+#endif /* XL || RUFFIAN */
 
 #endif /* __ASM_ALPHA_FLOPPY_H */
index 662aa35f6d722225f8051e12250873ece08852ac..fc2aa0517e310d7fa342f61a2c5e315fc79f61b7 100644 (file)
@@ -15,6 +15,8 @@
 #define EV45_CPU                6       /* EV4.5 (21064/xxx)    */
 #define EV56_CPU               7       /* EV5.6 (21164)        */
 #define EV6_CPU                        8       /* EV6 (21164)          */
+#define PCA56_CPU              9       /* PCA56 (21164PC)      */
+#define PCA57_CPU              10      /* PCA57 (21164??)      */
 
 /*
  * DEC system types for Alpha systems.  Found in HWRPB.
 #define ST_DEC_AXPPCI_33        11     /* NoName system type   */
 #define ST_DEC_TLASER           12     /* Turbolaser systype   */
 #define ST_DEC_2100_A50                 13     /* Avanti systype       */
-#define ST_DEC_MUSTANG          14     /* Mustang systype      */
 #define ST_DEC_ALCOR            15     /* Alcor (EV5) systype  */
 #define ST_DEC_1000             17     /* Mikasa systype       */
+#define ST_DEC_EB64             18     /* EB64 systype         */
 #define ST_DEC_EB66             19     /* EB66 systype         */
 #define ST_DEC_EB64P            20     /* EB64+ systype        */
-#define ST_DEC_EB66P           -19     /* EB66 systype         */
-#define ST_DEC_EBPC64          -20     /* Cabriolet (AlphaPC64) systype */
+#define ST_DEC_BURNS            21     /* laptop systype       */
+#define ST_DEC_RAWHIDE          22     /* Rawhide systype      */
+#define ST_DEC_K2               23     /* K2 systype           */
+#define ST_DEC_LYNX             24     /* Lynx systype         */
+#define ST_DEC_XL               25     /* Alpha XL systype     */
 #define ST_DEC_EB164            26     /* EB164 systype        */
+#define ST_DEC_NORITAKE                 27     /* Noritake systype     */
+#define ST_DEC_CORTEX           28     /* Cortex systype       */
+#define ST_DEC_MIATA            30     /* Miata systype        */
+#define ST_DEC_XXM              31     /* XXM systype          */
+#define ST_DEC_TAKARA           32     /* Takara systype       */
+#define ST_DEC_YUKON            33     /* Yukon systype        */
+#define ST_DEC_TSUNAMI          34     /* Tsunami systype      */
+#define ST_DEC_WILDFIRE                 35     /* Wildfire systype     */
+#define ST_DEC_CUSCO            36     /* CUSCO systype        */
+
+/* UNOFFICIAL!!! */
+#define ST_UNOFFICIAL_BIAS     100
+#define ST_DTI_RUFFIAN         101     /* RUFFIAN systype      */
 
 struct pcb_struct {
        unsigned long ksp;
@@ -118,6 +136,12 @@ struct memdesc_struct {
        struct memclust_struct cluster[0];
 };
 
+struct dsr_struct {
+       long smm;                       /* SMM nubber used by LMF       */
+       unsigned long  lurt_off;        /* offset to LURT table         */
+       unsigned long  sysname_off;     /* offset to sysname char count */
+};
+
 struct hwrpb_struct {
        unsigned long phys_addr;        /* check: physical address of the hwrpb */
        unsigned long id;               /* check: "HWRPB\0\0\0" */
@@ -157,7 +181,7 @@ struct hwrpb_struct {
        unsigned long chksum;
        unsigned long rxrdy;
        unsigned long txrdy;
-       unsigned long dsrdbt_offset;    /* "Dynamic System Recognition Data Block Table" Whee */
+       unsigned long dsr_offset;       /* "Dynamic System Recognition Data Block Table" */
 };
 
 #endif
index 44fea065e27a0f4cf8deed02f92aa43bde2d9fdb..24ab4cc02fbe9124820807ee942946ef86ba41a8 100644 (file)
@@ -25,7 +25,11 @@ extern struct hae {
 /*
  * Virtual -> physical identity mapping starts at this offset
  */
+#ifdef USE_48_BIT_KSEG
+#define IDENT_ADDR     (0xffff800000000000UL)
+#else
 #define IDENT_ADDR     (0xfffffc0000000000UL)
+#endif
 
 #ifdef __KERNEL__
 
@@ -42,6 +46,7 @@ extern inline void set_hae(unsigned long new_hae)
        hae.cache = new_hae;
        *hae.reg = new_hae;
        mb();
+       new_hae = *hae.reg; /* read to make sure it was written */
        setipl(ipl);
 }
 
@@ -79,6 +84,10 @@ extern void _sethae (unsigned long addr);    /* cached version */
 # include <asm/apecs.h>                /* get chip-specific definitions */
 #elif defined(CONFIG_ALPHA_CIA)
 # include <asm/cia.h>          /* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_T2)
+# include <asm/t2.h>           /* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_PYXIS)
+# include <asm/pyxis.h>                /* get chip-specific definitions */
 #else
 # include <asm/jensen.h>
 #endif
@@ -150,9 +159,21 @@ extern void                _writel(unsigned int b, unsigned long addr);
 #endif
 
 /*
- * The "address" in IO memory space is not clearly either a integer or a
+ * The "address" in IO memory space is not clearly either an integer or a
  * pointer. We will accept both, thus the casts.
+ *
+ * On the alpha, we have the whole physical address space mapped at all
+ * times, so "ioremap()" and "iounmap()" do not need to do anything.
  */
+extern inline void * ioremap(unsigned long offset, unsigned long size)
+{
+       return (void *) offset;
+} 
+
+extern inline void iounmap(void *addr)
+{
+}
+
 #ifndef readb
 # define readb(a)      _readb((unsigned long)(a))
 #endif
@@ -203,6 +224,22 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
 
 #define eth_io_copy_and_sum(skb,src,len,unused)        memcpy_fromio((skb)->data,(src),(len))
 
+static inline int check_signature(unsigned long io_addr,
+       const unsigned char *signature, int length)
+{
+       int retval = 0;
+       do {
+               if (readb(io_addr) != *signature)
+                       goto out;
+               io_addr++;
+               signature++;
+               length--;
+       } while (length);
+       retval = 1;
+out:
+       return retval;
+}
+
 #endif /* __KERNEL__ */
 
 #endif
index bf2a380e9743dbdd13409bbb281f83c9714913bd..4be70268171f28c934456f0087b2152f6106f642 100644 (file)
 #include <linux/linkage.h>
 #include <linux/config.h>
 
-#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164)
-# define NR_IRQS       33
-#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA)
+#if   defined(CONFIG_ALPHA_CABRIOLET) || \
+      defined(CONFIG_ALPHA_EB66P)     || \
+      defined(CONFIG_ALPHA_EB164)     || \
+      defined(CONFIG_ALPHA_PC164)     || \
+      defined(CONFIG_ALPHA_LX164)
+
+# define NR_IRQS       35
+
+#elif defined(CONFIG_ALPHA_EB66)      || \
+      defined(CONFIG_ALPHA_EB64P)     || \
+      defined(CONFIG_ALPHA_MIKASA)
+
 # define NR_IRQS       32
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+
+#elif defined(CONFIG_ALPHA_ALCOR)     || \
+      defined(CONFIG_ALPHA_XLT)       || \
+      defined(CONFIG_ALPHA_MIATA)     || \
+      defined(CONFIG_ALPHA_RUFFIAN)   || \
+      defined(CONFIG_ALPHA_NORITAKE)
+
 # define NR_IRQS       48
-#else
+
+#elif defined(CONFIG_ALPHA_SABLE)     || \
+      defined(CONFIG_ALPHA_SX164)
+
+# define NR_IRQS       40
+
+#elif defined(CONFIG_ALPHA_TAKARA)
+
+# define NR_IRQS       20
+
+#else /* everyone else */
+
 # define NR_IRQS       16
+
 #endif
 
 
index 161e89a6fbc76b8dbc1c5be9462d37084e1ebd3b..9ea03dd9b4aea030d8ffe96e811f91c69d27ae2c 100644 (file)
 
 #include <asm/system.h>
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define LCA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define LCA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int LCA_DMA_WIN_BASE;
+extern unsigned int LCA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define LCA_DMA_WIN_BASE       (1024*1024*1024)
 #define LCA_DMA_WIN_SIZE       (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * Memory Controller registers:
 
 #define HAE_ADDRESS    LCA_IOC_HAE
 
+/* LCA PMR Power Management register defines */
+#define LCA_PMR_ADDR   (IDENT_ADDR + 0x120000098UL)
+#define LCA_PMR_PDIV    0x7                     /* Primary clock divisor */
+#define LCA_PMR_ODIV    0x38                    /* Override clock divisor */
+#define LCA_PMR_INTO    0x40                    /* Interrupt override */
+#define LCA_PMR_DMAO    0x80                    /* DMA override */
+#define LCA_PMR_OCCEB   0xffff0000L             /* Override cycle counter - even
+ bits */
+#define LCA_PMR_OCCOB   0xffff000000000000L     /* Override cycle counter - even
+ bits */
+#define LCA_PMR_PRIMARY_MASK    0xfffffffffffffff8
+/* LCA PMR Macros */
+
+#define READ_PMR        (*(volatile unsigned long *)LCA_PMR_ADDR)
+#define WRITE_PMR(d)    (*((volatile unsigned long *)LCA_PMR_ADDR) = (d))
+
+#define GET_PRIMARY(r)  ((r) & LCA_PMR_PDIV)
+#define GET_OVERRIDE(r) (((r) >> 3) & LCA_PMR_PDIV)
+#define SET_PRIMARY_CLOCK(r, c) ((r) = (((r) & LCA_PMR_PRIMARY_MASK) | (c)))
+
+/* LCA PMR Divisor values */
+#define DIV_1   0x0
+#define DIV_1_5 0x1
+#define DIV_2   0x2
+#define DIV_4   0x3
+#define DIV_8   0x4
+#define DIV_16  0x5
+#define DIV_MIN DIV_1
+#define DIV_MAX DIV_16
+
+
 #ifdef __KERNEL__
 
 /*
@@ -317,7 +358,6 @@ extern unsigned long lca_init (unsigned long mem_start, unsigned long mem_end);
  */
 struct el_lca_mcheck_short {
        struct el_common        h;              /* common logout header */
-       unsigned long           reason;         /* reason for machine check */
        unsigned long           esr;            /* error-status register */
        unsigned long           ear;            /* error-address register */
        unsigned long           dc_stat;        /* dcache status register */
@@ -327,7 +367,7 @@ struct el_lca_mcheck_short {
 
 struct el_lca_mcheck_long {
        struct el_common        h;              /* common logout header */
-       unsigned long           pt[32];         /* PAL temps (pt[0] is reason) */
+       unsigned long           pt[31];         /* PAL temps */
        unsigned long           exc_addr;       /* exception address */
        unsigned long           pad1[3];
        unsigned long           pal_base;       /* PALcode base address */
index a4ef2e38a825e0f4b44419080d839a26d2da8882..510d13326de4436fa09a214068f96aeca388c337 100644 (file)
@@ -7,7 +7,6 @@
 #define PAL_halt         0
 #define PAL_cflush       1
 #define PAL_draina       2
-#define PAL_cobratt      9
 #define PAL_bpt                128
 #define PAL_bugchk     129
 #define PAL_chmk       131
@@ -27,6 +26,8 @@
 /*
  * OSF specific PAL-code
  */
+#define PAL_cserve      9
+#define PAL_wripir     13
 #define PAL_rdmces     16
 #define PAL_wrmces     17
 #define PAL_wrfen      43
index e4b897f69889817258c508ee55700ab44d3945ee..1bf57f01abab8acb31b09e3295acdd61d4a5b17c 100644 (file)
@@ -8,9 +8,17 @@
 #define __ASM_ALPHA_PROCESSOR_H
 
 /*
- * We have a 41-bit user address space: 2TB user VM...
+ * We have a 41-bit user address space: 2TB user VM.
+ * Under certain circumstances (e.g. when emulating 32-bit code)
+ * we may want to voluntarily limit this...
  */
 #define TASK_SIZE (0x40000000000UL)
+#define MAX_USER_ADDR ((current->personality&ADDR_MAX_32BIT) ? 0x100000000UL : \
+       ((current->personality & ADDR_MAX_31BIT) ? 0x80000000UL : \
+                                                       0x40000000000UL))
+#define MMAP_SEARCH_START ((current->personality & ADDR_MAX_31BIT) ? \
+                       (MAX_USER_ADDR/2) : (MAX_USER_ADDR/3))
+
 
 /*
  * Bus types
index 8f7d643fc8c321e3037595259dbd62a9ea6cf311..4079385ecb3be99255e9f4f479635f02b4f0cbab 100644 (file)
@@ -37,6 +37,10 @@ struct pt_regs {
        unsigned long r27;
        unsigned long r28;
        unsigned long hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+       unsigned long trap_a0;
+       unsigned long trap_a1;
+       unsigned long trap_a2;
 /* These are saved by PAL-code: */
        unsigned long ps;
        unsigned long pc;
diff --git a/include/asm-alpha/pyxis.h b/include/asm-alpha/pyxis.h
new file mode 100644 (file)
index 0000000..4cb98c4
--- /dev/null
@@ -0,0 +1,742 @@
+#ifndef __ALPHA_PYXIS__H__
+#define __ALPHA_PYXIS__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/*
+ * PYXIS is the internal name for a core logic chipset which provides
+ * memory controller and PCI access for the 21164A chip based systems.
+ *
+ * This file is based on:
+ *
+ * Pyxis Chipset Spec
+ * 14-Jun-96
+ * Rev. X2.0
+ *
+ */
+
+/*------------------------------------------------------------------------**
+**                                                                        **
+**  I/O procedures                                                   **
+**                                                                        **
+**      inport[b|w|t|l], outport[b|w|t|l] 8:16:24:32 IO xfers             **
+**     inportbxt: 8 bits only                                            **
+**      inport:    alias of inportw                                       **
+**      outport:   alias of outportw                                      **
+**                                                                        **
+**      inmem[b|w|t|l], outmem[b|w|t|l] 8:16:24:32 ISA memory xfers       **
+**     inmembxt: 8 bits only                                             **
+**      inmem:    alias of inmemw                                         **
+**      outmem:   alias of outmemw                                        **
+**                                                                        **
+**------------------------------------------------------------------------*/
+
+
+/* CIA ADDRESS BIT DEFINITIONS
+ *
+ *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
+ *  |                                                                        \_/ \_/
+ *  |                                                                         |   |
+ *  +-- IO space, not cached.                                   Byte Enable --+   |
+ *                                                              Transfer Length --+
+ *
+ *
+ *
+ *   Byte      Transfer
+ *   Enable    Length    Transfer  Byte    Address
+ *   adr<6:5>  adr<4:3>  Length    Enable  Adder
+ *   ---------------------------------------------
+ *      00        00      Byte      1110   0x000
+ *      01        00      Byte      1101   0x020
+ *      10        00      Byte      1011   0x040
+ *      11        00      Byte      0111   0x060
+ *
+ *      00        01      Word      1100   0x008
+ *      01        01      Word      1001   0x028 <= Not supported in this code.
+ *      10        01      Word      0011   0x048
+ *
+ *      00        10      Tribyte   1000   0x010
+ *      01        10      Tribyte   0001   0x030
+ *
+ *      10        11      Longword  0000   0x058
+ *
+ *      Note that byte enables are asserted low.
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define PYXIS_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int PYXIS_DMA_WIN_BASE;
+extern unsigned int PYXIS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define PYXIS_DMA_WIN_BASE     (1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE     (1024*1024*1024)
+#endif /* SRM_SETUP */
+
+/*
+ *  General Registers
+ */
+#define PYXIS_REV                      (IDENT_ADDR + 0x8740000080UL)
+#define PYXIS_PCI_LAT                  (IDENT_ADDR + 0x87400000C0UL)
+#define PYXIS_CTRL                     (IDENT_ADDR + 0x8740000100UL)
+#define PYXIS_CTRL1                    (IDENT_ADDR + 0x8740000140UL)
+#define PYXIS_FLASH_CTRL               (IDENT_ADDR + 0x8740000200UL)
+
+#define PYXIS_HAE_MEM                  (IDENT_ADDR + 0x8740000400UL)
+#define PYXIS_HAE_IO                   (IDENT_ADDR + 0x8740000440UL)
+#define PYXIS_CFG                      (IDENT_ADDR + 0x8740000480UL)
+
+/*
+ * Diagnostic Registers
+ */
+#define PYXIS_DIAG                     (IDENT_ADDR + 0x8740002000UL)
+#define PYXIS_DIAG_CHECK               (IDENT_ADDR + 0x8740003000UL)
+
+/*
+ * Performance Monitor registers
+ */
+#define PYXIS_PERF_MONITOR             (IDENT_ADDR + 0x8740004000UL)
+#define PYXIS_PERF_CONTROL             (IDENT_ADDR + 0x8740004040UL)
+
+/*
+ * Error registers
+ */
+#define PYXIS_ERR                      (IDENT_ADDR + 0x8740008200UL)
+#define PYXIS_STAT                     (IDENT_ADDR + 0x8740008240UL)
+#define PYXIS_ERR_MASK                 (IDENT_ADDR + 0x8740008280UL)
+#define PYXIS_SYN                      (IDENT_ADDR + 0x8740008300UL)
+#define PYXIS_ERR_DATA                 (IDENT_ADDR + 0x8740008308UL)
+
+#define PYXIS_MEAR                     (IDENT_ADDR + 0x8740008400UL)
+#define PYXIS_MESR                     (IDENT_ADDR + 0x8740008440UL)
+#define PYXIS_PCI_ERR0                 (IDENT_ADDR + 0x8740008800UL)
+#define PYXIS_PCI_ERR1                 (IDENT_ADDR + 0x8740008840UL)
+#define PYXIS_PCI_ERR2                 (IDENT_ADDR + 0x8740008880UL)
+
+/*
+ * PCI Address Translation Registers.
+ */
+#define PYXIS_TBIA                     (IDENT_ADDR + 0x8760000100UL)
+
+#define PYXIS_W0_BASE                  (IDENT_ADDR + 0x8760000400UL)
+#define PYXIS_W0_MASK                  (IDENT_ADDR + 0x8760000440UL)
+#define PYXIS_T0_BASE                  (IDENT_ADDR + 0x8760000480UL)
+
+#define PYXIS_W1_BASE                  (IDENT_ADDR + 0x8760000500UL)
+#define PYXIS_W1_MASK                  (IDENT_ADDR + 0x8760000540UL)
+#define PYXIS_T1_BASE                  (IDENT_ADDR + 0x8760000580UL)
+
+#define PYXIS_W2_BASE                  (IDENT_ADDR + 0x8760000600UL)
+#define PYXIS_W2_MASK                  (IDENT_ADDR + 0x8760000640UL)
+#define PYXIS_T2_BASE                  (IDENT_ADDR + 0x8760000680UL)
+
+#define PYXIS_W3_BASE                  (IDENT_ADDR + 0x8760000700UL)
+#define PYXIS_W3_MASK                  (IDENT_ADDR + 0x8760000740UL)
+#define PYXIS_T3_BASE                  (IDENT_ADDR + 0x8760000780UL)
+
+/*
+ * Memory Control registers
+ */
+#define PYXIS_MCR                      (IDENT_ADDR + 0x8750000000UL)
+
+/*
+ * Memory spaces:
+ */
+#define PYXIS_IACK_SC                  (IDENT_ADDR + 0x8720000000UL)
+#define PYXIS_CONF                     (IDENT_ADDR + 0x8700000000UL)
+#define PYXIS_IO                       (IDENT_ADDR + 0x8580000000UL)
+#define PYXIS_SPARSE_MEM               (IDENT_ADDR + 0x8000000000UL)
+#define PYXIS_SPARSE_MEM_R2            (IDENT_ADDR + 0x8400000000UL)
+#define PYXIS_SPARSE_MEM_R3            (IDENT_ADDR + 0x8500000000UL)
+#define PYXIS_DENSE_MEM                        (IDENT_ADDR + 0x8600000000UL)
+
+/*
+ * Byte/Word PCI Memory Spaces:
+ */
+#define PYXIS_BW_MEM                   (IDENT_ADDR + 0x8800000000UL)
+#define PYXIS_BW_IO                    (IDENT_ADDR + 0x8900000000UL)
+#define PYXIS_BW_CFG_0                 (IDENT_ADDR + 0x8a00000000UL)
+#define PYXIS_BW_CFG_1                 (IDENT_ADDR + 0x8b00000000UL)
+
+/*
+ * Interrupt Control registers
+ */
+#define PYXIS_INT_REQ                  (IDENT_ADDR + 0x87A0000000UL)
+#define PYXIS_INT_MASK                 (IDENT_ADDR + 0x87A0000040UL)
+#define PYXIS_INT_HILO                 (IDENT_ADDR + 0x87A00000C0UL)
+#define PYXIS_INT_ROUTE                        (IDENT_ADDR + 0x87A0000140UL)
+#define PYXIS_GPO                      (IDENT_ADDR + 0x87A0000180UL)
+#define PYXIS_INT_CNFG                 (IDENT_ADDR + 0x87A00001C0UL)
+#define PYXIS_RT_COUNT                 (IDENT_ADDR + 0x87A0000200UL)
+#define PYXIS_INT_TIME                 (IDENT_ADDR + 0x87A0000240UL)
+#define PYXIS_IIC_CTRL                 (IDENT_ADDR + 0x87A00002C0UL)
+
+/*
+ * Bit definitions for I/O Controller status register 0:
+ */
+#define PYXIS_STAT0_CMD                        0xf
+#define PYXIS_STAT0_ERR                        (1<<4)
+#define PYXIS_STAT0_LOST               (1<<5)
+#define PYXIS_STAT0_THIT               (1<<6)
+#define PYXIS_STAT0_TREF               (1<<7)
+#define PYXIS_STAT0_CODE_SHIFT         8
+#define PYXIS_STAT0_CODE_MASK          0x7
+#define PYXIS_STAT0_P_NBR_SHIFT                13
+#define PYXIS_STAT0_P_NBR_MASK         0x7ffff
+
+#define HAE_ADDRESS                    PYXIS_HAE_MEM
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#if 0
+/* Ruffian doesn't do 1G PCI window */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address);
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address);
+}
+#else
+/* Oh, yes, it does (at least with the latest FW) */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address - PYXIS_DMA_WIN_BASE);
+}
+#endif
+#else /* RUFFIAN */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address - PYXIS_DMA_WIN_BASE);
+}
+#endif /* RUFFIAN */
+
+/*
+ * I/O functions:
+ *
+ * PYXIS, the 21174 PCI/memory support chipset for the EV56 (21164)
+ * and PCA56 (21164PC) processors, can use either a sparse address
+ * mapping scheme, or the so-called byte-word PCI address space, to
+ * get at PCI memory and I/O.
+ */
+
+#define vuip   volatile unsigned int *
+
+#if defined(BWIO_ENABLED)
+# if defined(CONFIG_ALPHA_LX164) || \
+     defined(CONFIG_ALPHA_SX164)
+/* only for the above platforms can we be sure this will work */
+#  define BWIO_REALLY_ENABLED
+# else
+#  undef BWIO_REALLY_ENABLED
+# endif
+#else
+# undef BWIO_REALLY_ENABLED
+#endif
+
+#ifdef BWIO_REALLY_ENABLED
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(x, port) __outb((x),(port))
+#define outw(x, port) __outw((x),(port))
+#define outl(x, port) __outl((x),(port))
+
+#else /* BWIO_REALLY_ENABLED */
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x00);
+       result >>= (addr & 3) * 8;
+       return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       unsigned int w;
+
+       asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + PYXIS_IO + 0x00) = w;
+       mb();
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x08);
+       result >>= (addr & 3) * 8;
+       return 0xffffUL & result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       unsigned int w;
+
+       asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + PYXIS_IO + 0x08) = w;
+       mb();
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       return *(vuip) ((addr << 5) + PYXIS_IO + 0x18);
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       *(vuip) ((addr << 5) + PYXIS_IO + 0x18) = b;
+       mb();
+}
+
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#endif /* BWIO_REALLY_ENABLED */
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ * 
+ * For reading and writing 8 and 16 bit quantities we need to 
+ * go through one of the three sparse address mapping regions
+ * and use the HAE_MEM CSR to provide some bits of the address.
+ * The following few routines use only sparse address region 1
+ * which gives 1Gbyte of accessible space which relates exactly
+ * to the amount of PCI memory mapping *into* system address space.
+ * See p 6-17 of the specification but it looks something like this:
+ *
+ * 21164 Address:
+ * 
+ *          3         2         1
+ * 9876543210987654321098765432109876543210
+ * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ *
+ * ZZ = SBZ
+ * BB = Byte offset
+ * LL = Transfer length
+ *
+ * PCI Address:
+ *
+ * 3         2         1
+ * 10987654321098765432109876543210
+ * HHH....PCI.QW.Address........ 00
+ *
+ * HHH = 31:29 HAE_MEM CSR
+ * 
+ */
+
+#ifdef BWIO_REALLY_ENABLED
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+PYXIS_BW_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+PYXIS_BW_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+PYXIS_BW_MEM)));
+
+       return result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+#define readb(addr) __readb((addr))
+#define readw(addr) __readw((addr))
+
+#define writeb(b, addr) __writeb((b),(addr))
+#define writew(b, addr) __writew((b),(addr))
+
+#else /* BWIO_REALLY_ENABLED */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x08);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, msb, work, temp;
+
+       shift = (addr & 0x3) << 3;
+       msb = addr & 0xE0000000UL;
+       temp = addr & MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x00);
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, msb, work, temp;
+
+       shift = (addr & 0x3) << 3;
+       msb = addr & 0xE0000000UL;
+       temp = addr & MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x08);
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = b * 0x00010001;
+}
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       return *(vuip) (addr + PYXIS_DENSE_MEM);
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       *(vuip) (addr + PYXIS_DENSE_MEM) = b;
+}
+
+#endif /* BWIO_REALLY_ENABLED */
+
+#define readl(a)       __readl((unsigned long)(a))
+#define writel(v,a)    __writel((v),(unsigned long)(a))
+
+#undef vuip
+
+extern unsigned long pyxis_init (unsigned long mem_start,
+                                unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Data structure for handling PYXIS machine checks:
+ */
+struct el_PYXIS_sysdata_mcheck {
+    u_long      coma_gcr;                       
+    u_long      coma_edsr;                      
+    u_long      coma_ter;                       
+    u_long      coma_elar;                      
+    u_long      coma_ehar;                      
+    u_long      coma_ldlr;                      
+    u_long      coma_ldhr;                      
+    u_long      coma_base0;                     
+    u_long      coma_base1;                     
+    u_long      coma_base2;                     
+    u_long      coma_cnfg0;                     
+    u_long      coma_cnfg1;                     
+    u_long      coma_cnfg2;                     
+    u_long      epic_dcsr;                      
+    u_long      epic_pear;                      
+    u_long      epic_sear;                      
+    u_long      epic_tbr1;                      
+    u_long      epic_tbr2;                      
+    u_long      epic_pbr1;                      
+    u_long      epic_pbr2;                      
+    u_long      epic_pmr1;                      
+    u_long      epic_pmr2;                      
+    u_long      epic_harx1;                     
+    u_long      epic_harx2;                     
+    u_long      epic_pmlt;                      
+    u_long      epic_tag0;                      
+    u_long      epic_tag1;                      
+    u_long      epic_tag2;                      
+    u_long      epic_tag3;                      
+    u_long      epic_tag4;                      
+    u_long      epic_tag5;                      
+    u_long      epic_tag6;                      
+    u_long      epic_tag7;                      
+    u_long      epic_data0;                     
+    u_long      epic_data1;                     
+    u_long      epic_data2;                     
+    u_long      epic_data3;                     
+    u_long      epic_data4;                     
+    u_long      epic_data5;                     
+    u_long      epic_data6;                     
+    u_long      epic_data7;                     
+};
+
+#define RTC_PORT(x)    (0x70 + (x))
+#define RTC_ADDR(x)    (0x80 | (x))
+#ifdef CONFIG_ALPHA_RUFFIAN
+#define RTC_ALWAYS_BCD 1
+#else /* RUFFIAN */
+#define RTC_ALWAYS_BCD 0
+#endif /* RUFFIAN */
+#endif /* __ALPHA_PYXIS__H__ */
index 22f97fab11ef84b8c353ee5698584f454d859065..beb579c28de2057c034055110460acbeeaf2e012 100644 (file)
@@ -2,14 +2,10 @@
 #define _ASMAXP_SHMPARAM_H
 
 /*
- * Address range for shared memory attaches if no address passed to
- * shmat().  These ought to be changed to something >4GB so 32-bit
- * errors are caught more easily.  However, they don't seem to be used
- * except for ELF stuff, so it's not really critical until we get ELF
- * support for the Alpha.
+ * Address range for shared memory attaches if no address passed to shmat().
  */
-#define SHM_RANGE_START        0x50000000
-#define SHM_RANGE_END  0x60000000
+#define SHM_RANGE_START        0x14000000000
+#define SHM_RANGE_END  0x15000000000
 
 /*
  * Format of a swap-entry for shared memory pages currently out in
index db9c62a7d214f1b2f64129b12d0215dad19713f3..d67108caa42a6db4b8249d3a918be34d7278e65c 100644 (file)
@@ -52,6 +52,8 @@ extern void wrusp(unsigned long);
 extern unsigned long rdusp(void);
 extern unsigned long rdmces (void);
 extern void wrmces (unsigned long);
+extern unsigned long whami(void);
+extern void wripir(unsigned long);
 
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
diff --git a/include/asm-alpha/t2.h b/include/asm-alpha/t2.h
new file mode 100644 (file)
index 0000000..a86f02a
--- /dev/null
@@ -0,0 +1,654 @@
+#ifndef __ALPHA_T2__H__
+#define __ALPHA_T2__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/*
+ * T2 is the internal name for the core logic chipset which provides
+ * memory controller and PCI access for the SABLE-based systems.
+ *
+ * This file is based on:
+ *
+ * SABLE I/O Specification
+ * Revision/Update Information: 1.3
+ *
+ * jestabro@amt.tay1.dec.com Initial Version.
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+#define MEM_R1_MASK 0x03ffffff  /* Mem sparse space region 1 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define T2_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define T2_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int T2_DMA_WIN_BASE;
+extern unsigned int T2_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define T2_DMA_WIN_BASE        (1024*1024*1024)
+#define T2_DMA_WIN_SIZE        (1024*1024*1024)
+#endif /* SRM_SETUP */
+
+/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
+#ifdef CONFIG_ALPHA_GAMMA
+#  define GAMMA_BIAS           0x8000000000UL
+#else /* GAMMA */
+#  define GAMMA_BIAS           0x0000000000UL
+#endif /* GAMMA */
+
+/*
+ * Memory spaces:
+ */
+#define T2_CONF                        (IDENT_ADDR + GAMMA_BIAS + 0x390000000UL)
+#define T2_IO                  (IDENT_ADDR + GAMMA_BIAS + 0x3a0000000UL)
+#define T2_SPARSE_MEM          (IDENT_ADDR + GAMMA_BIAS + 0x200000000UL)
+#define T2_DENSE_MEM           (IDENT_ADDR + GAMMA_BIAS + 0x3c0000000UL)
+
+#define T2_IOCSR               (IDENT_ADDR + GAMMA_BIAS + 0x38e000000UL)
+#define T2_CERR1               (IDENT_ADDR + GAMMA_BIAS + 0x38e000020UL)
+#define T2_CERR2               (IDENT_ADDR + GAMMA_BIAS + 0x38e000040UL)
+#define T2_CERR3               (IDENT_ADDR + GAMMA_BIAS + 0x38e000060UL)
+#define T2_PERR1               (IDENT_ADDR + GAMMA_BIAS + 0x38e000080UL)
+#define T2_PERR2               (IDENT_ADDR + GAMMA_BIAS + 0x38e0000a0UL)
+#define T2_PSCR                        (IDENT_ADDR + GAMMA_BIAS + 0x38e0000c0UL)
+#define T2_HAE_1               (IDENT_ADDR + GAMMA_BIAS + 0x38e0000e0UL)
+#define T2_HAE_2               (IDENT_ADDR + GAMMA_BIAS + 0x38e000100UL)
+#define T2_HBASE               (IDENT_ADDR + GAMMA_BIAS + 0x38e000120UL)
+#define T2_WBASE1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000140UL)
+#define T2_WMASK1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000160UL)
+#define T2_TBASE1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000180UL)
+#define T2_WBASE2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001a0UL)
+#define T2_WMASK2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001c0UL)
+#define T2_TBASE2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001e0UL)
+#define T2_TLBBR               (IDENT_ADDR + GAMMA_BIAS + 0x38e000200UL)
+
+#define T2_HAE_3               (IDENT_ADDR + GAMMA_BIAS + 0x38e000240UL)
+#define T2_HAE_4               (IDENT_ADDR + GAMMA_BIAS + 0x38e000260UL)
+
+#define HAE_ADDRESS            T2_HAE_1
+
+/*  T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
+ 3.8fff.ffff
+ *
+ *  +--------------+ 3 8000 0000
+ *  | CPU 0 CSRs   |            
+ *  +--------------+ 3 8100 0000
+ *  | CPU 1 CSRs   |            
+ *  +--------------+ 3 8200 0000
+ *  | CPU 2 CSRs   |            
+ *  +--------------+ 3 8300 0000
+ *  | CPU 3 CSRs   |            
+ *  +--------------+ 3 8400 0000
+ *  | CPU Reserved |            
+ *  +--------------+ 3 8700 0000
+ *  | Mem Reserved |            
+ *  +--------------+ 3 8800 0000
+ *  | Mem 0 CSRs   |            
+ *  +--------------+ 3 8900 0000
+ *  | Mem 1 CSRs   |            
+ *  +--------------+ 3 8a00 0000
+ *  | Mem 2 CSRs   |            
+ *  +--------------+ 3 8b00 0000
+ *  | Mem 3 CSRs   |            
+ *  +--------------+ 3 8c00 0000           
+ *  | Mem Reserved |            
+ *  +--------------+ 3 8e00 0000           
+ *  | PCI Bridge   |            
+ *  +--------------+ 3 8f00 0000           
+ *  | Expansion IO |            
+ *  +--------------+ 3 9000 0000           
+ *                                              
+ *
+ */
+#define CPU0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x380000000L)
+#define CPU1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x381000000L)
+#define CPU2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x382000000L)
+#define CPU3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x383000000L)
+#define MEM0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x388000000L)
+#define MEM1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x389000000L)
+#define MEM2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38a000000L)
+#define MEM3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38b000000L)
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address) + T2_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address - T2_DMA_WIN_BASE);
+}
+
+/*
+ * I/O functions:
+ *
+ * T2 (the core logic PCI/memory support chipset for the SABLE
+ * series of processors uses a sparse address mapping scheme to
+ * get at PCI memory and I/O.
+ */
+
+#define vuip   volatile unsigned int *
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       long result = *(vuip) ((addr << 5) + T2_IO + 0x00);
+       result >>= (addr & 3) * 8;
+       return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       unsigned int w;
+
+       asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + T2_IO + 0x00) = w;
+       mb();
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       long result = *(vuip) ((addr << 5) + T2_IO + 0x08);
+       result >>= (addr & 3) * 8;
+       return 0xffffUL & result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       unsigned int w;
+
+       asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + T2_IO + 0x08) = w;
+       mb();
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       return *(vuip) ((addr << 5) + T2_IO + 0x18);
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       *(vuip) ((addr << 5) + T2_IO + 0x18) = b;
+       mb();
+}
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ * 
+ * For reading and writing 8 and 16 bit quantities we need to 
+ * go through one of the three sparse address mapping regions
+ * and use the HAE_MEM CSR to provide some bits of the address.
+ * The following few routines use only sparse address region 1
+ * which gives 1Gbyte of accessible space which relates exactly
+ * to the amount of PCI memory mapping *into* system address space.
+ * See p 6-17 of the specification but it looks something like this:
+ *
+ * 21164 Address:
+ * 
+ *          3         2         1                                                               
+ * 9876543210987654321098765432109876543210
+ * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ *
+ * ZZ = SBZ
+ * BB = Byte offset
+ * LL = Transfer length
+ *
+ * PCI Address:
+ *
+ * 3         2         1                                                               
+ * 10987654321098765432109876543210
+ * HHH....PCI.QW.Address........ 00
+ *
+ * HHH = 31:29 HAE_MEM CSR
+ * 
+ */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long t2_sm_base;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline unsigned long __readl(unsigned long addr)
+{
+       unsigned long result, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       {
+#if 0
+         printk("__readl: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffffffUL;
+       }
+       result = *(vuip) work;
+       return 0xffffffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       {
+#if 0
+         printk("__writel: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b;
+}
+
+#else /* SRM_SETUP */
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, msb;
+
+       shift = (addr & 0x3) * 8 ;
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) ;
+       result >>= shift;
+       return 0xffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, msb;
+
+       shift = (addr & 0x3) * 8;
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
+       result >>= shift;
+       return 0xffffUL & result;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline unsigned long __readl(unsigned long addr)
+{
+       unsigned long result, msb;
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
+       return 0xffffffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = b * 0x00010001;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
+}
+
+#endif /* SRM_SETUP */
+
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#define readl(a)       __readl((unsigned long)(a))
+#define writel(v,a)    __writel((v),(unsigned long)(a))
+
+#undef vuip
+
+extern unsigned long t2_init (unsigned long mem_start,
+                                unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Sable CPU Module CSRS
+ *
+ * These are CSRs for hardware other than the CPU chip on the CPU module.
+ * The CPU module has Backup Cache control logic, Cbus control logic, and
+ * interrupt control logic on it.  There is a duplicate tag store to speed
+ * up maintaining cache coherency.
+ */
+
+struct sable_cpu_csr {
+unsigned long bcc;     long fill_00[3]; /* Backup Cache Control */
+unsigned long bcce;    long fill_01[3]; /* Backup Cache Correctable Error */
+unsigned long bccea;   long fill_02[3]; /* B-Cache Corr Err Address Latch */
+unsigned long bcue;    long fill_03[3]; /* B-Cache Uncorrectable Error */
+unsigned long bcuea;   long fill_04[3]; /* B-Cache Uncorr Err Addr Latch */
+unsigned long dter;    long fill_05[3]; /* Duplicate Tag Error */
+unsigned long cbctl;   long fill_06[3]; /* CBus Control */
+unsigned long cbe;     long fill_07[3]; /* CBus Error */
+unsigned long cbeal;   long fill_08[3]; /* CBus Error Addr Latch low */
+unsigned long cbeah;   long fill_09[3]; /* CBus Error Addr Latch high */
+unsigned long pmbx;    long fill_10[3]; /* Processor Mailbox */
+unsigned long ipir;    long fill_11[3]; /* Inter-Processor Int Request */
+unsigned long sic;     long fill_12[3]; /* System Interrupt Clear */
+unsigned long adlk;    long fill_13[3]; /* Address Lock (LDxL/STxC) */
+unsigned long madrl;   long fill_14[3]; /* CBus Miss Address */
+unsigned long rev;     long fill_15[3]; /* CMIC Revision */
+};
+
+/*
+ * Data structure for handling T2 machine checks:
+ */
+struct el_t2_frame_header {
+       unsigned int    elcf_fid;       /* Frame ID (from above) */
+       unsigned int    elcf_size;      /* Size of frame in bytes */
+};
+
+struct el_t2_procdata_mcheck {
+       unsigned long   elfmc_paltemp[32];      /* PAL TEMP REGS. */
+       /* EV4-specific fields */
+       unsigned long   elfmc_exc_addr; /* Addr of excepting insn. */
+       unsigned long   elfmc_exc_sum;  /* Summary of arith traps. */
+       unsigned long   elfmc_exc_mask; /* Exception mask (from exc_sum). */
+       unsigned long   elfmc_iccsr;    /* IBox hardware enables. */
+       unsigned long   elfmc_pal_base; /* Base address for PALcode. */
+       unsigned long   elfmc_hier;     /* Hardware Interrupt Enable. */
+       unsigned long   elfmc_hirr;     /* Hardware Interrupt Request. */
+       unsigned long   elfmc_mm_csr;   /* D-stream fault info. */
+       unsigned long   elfmc_dc_stat;  /* D-cache status (ECC/Parity Err). */
+       unsigned long   elfmc_dc_addr;  /* EV3 Phys Addr for ECC/DPERR. */
+       unsigned long   elfmc_abox_ctl; /* ABox Control Register. */
+       unsigned long   elfmc_biu_stat; /* BIU Status. */
+       unsigned long   elfmc_biu_addr; /* BUI Address. */
+       unsigned long   elfmc_biu_ctl;  /* BIU Control. */
+       unsigned long   elfmc_fill_syndrome;    /* For correcting ECC errors. */
+       unsigned long   elfmc_fill_addr;/* Cache block which was being read. */
+       unsigned long   elfmc_va;       /* Effective VA of fault or miss. */
+       unsigned long   elfmc_bc_tag;   /* Backup Cache Tag Probe Results. */
+};
+
+/* 
+ * Sable processor specific Machine Check Data segment.
+ */
+
+struct el_t2_logout_header {
+       unsigned int    elfl_size;      /* size in bytes of logout area. */
+       int     elfl_sbz1:31;           /* Should be zero. */
+       char    elfl_retry:1;           /* Retry flag. */
+        unsigned int   elfl_procoffset;        /* Processor-specific offset. */
+       unsigned int    elfl_sysoffset;         /* Offset of system-specific. */
+       unsigned int    elfl_error_type;        /* PAL error type code. */
+       unsigned int    elfl_frame_rev;         /* PAL Frame revision. */
+};
+struct el_t2_sysdata_mcheck {
+       unsigned long    elcmc_bcc;           /* CSR 0 */
+       unsigned long    elcmc_bcce;          /* CSR 1 */
+       unsigned long    elcmc_bccea;      /* CSR 2 */
+       unsigned long    elcmc_bcue;          /* CSR 3 */
+       unsigned long    elcmc_bcuea;      /* CSR 4 */
+       unsigned long    elcmc_dter;          /* CSR 5 */
+       unsigned long    elcmc_cbctl;      /* CSR 6 */
+       unsigned long    elcmc_cbe;           /* CSR 7 */
+       unsigned long    elcmc_cbeal;      /* CSR 8 */
+       unsigned long    elcmc_cbeah;      /* CSR 9 */
+       unsigned long    elcmc_pmbx;          /* CSR 10 */
+       unsigned long    elcmc_ipir;          /* CSR 11 */
+       unsigned long    elcmc_sic;           /* CSR 12 */
+       unsigned long    elcmc_adlk;          /* CSR 13 */
+       unsigned long    elcmc_madrl;      /* CSR 14 */
+       unsigned long    elcmc_crrev4;     /* CSR 15 */
+};
+
+/*
+ * Sable memory error frame - sable pfms section 3.42
+ */
+struct el_t2_data_memory {
+       struct  el_t2_frame_header elcm_hdr;    /* ID$MEM-FERR = 0x08 */
+       unsigned int  elcm_module;      /* Module id. */
+       unsigned int  elcm_res04;       /* Reserved. */
+       unsigned long elcm_merr;        /* CSR0: Error Reg 1. */
+       unsigned long elcm_mcmd1;       /* CSR1: Command Trap 1. */
+       unsigned long elcm_mcmd2;       /* CSR2: Command Trap 2. */
+       unsigned long elcm_mconf;       /* CSR3: Configuration. */
+       unsigned long elcm_medc1;       /* CSR4: EDC Status 1. */
+       unsigned long elcm_medc2;       /* CSR5: EDC Status 2. */
+       unsigned long elcm_medcc;       /* CSR6: EDC Control. */
+       unsigned long elcm_msctl;       /* CSR7: Stream Buffer Control. */
+       unsigned long elcm_mref;        /* CSR8: Refresh Control. */
+       unsigned long elcm_filter;      /* CSR9: CRD Filter Control. */
+};
+
+
+/*
+ * Sable other cpu error frame - sable pfms section 3.43
+ */
+struct el_t2_data_other_cpu {
+       short         elco_cpuid;       /* CPU ID */
+       short         elco_res02[3];    
+       unsigned long elco_bcc; /* CSR 0 */
+       unsigned long elco_bcce;        /* CSR 1 */
+       unsigned long elco_bccea;       /* CSR 2 */
+       unsigned long elco_bcue;        /* CSR 3 */
+       unsigned long elco_bcuea;       /* CSR 4 */
+       unsigned long elco_dter;        /* CSR 5 */
+       unsigned long elco_cbctl;       /* CSR 6 */
+       unsigned long elco_cbe; /* CSR 7 */
+       unsigned long elco_cbeal;       /* CSR 8 */
+       unsigned long elco_cbeah;       /* CSR 9 */
+       unsigned long elco_pmbx;        /* CSR 10 */
+       unsigned long elco_ipir;        /* CSR 11 */
+       unsigned long elco_sic; /* CSR 12 */
+       unsigned long elco_adlk;        /* CSR 13 */
+       unsigned long elco_madrl;       /* CSR 14 */
+       unsigned long elco_crrev4;      /* CSR 15 */
+};
+
+/*
+ * Sable other cpu error frame - sable pfms section 3.44
+ */
+struct el_t2_data_t2{
+        struct el_t2_frame_header elct_hdr;    /* ID$T2-FRAME */
+       unsigned long elct_iocsr;       /* IO Control and Status Register */
+       unsigned long elct_cerr1;       /* Cbus Error Register 1 */
+       unsigned long elct_cerr2;       /* Cbus Error Register 2 */
+       unsigned long elct_cerr3;       /* Cbus Error Register 3 */
+       unsigned long elct_perr1;       /* PCI Error Register 1 */
+       unsigned long elct_perr2;       /* PCI Error Register 2 */
+       unsigned long elct_hae0_1;      /* High Address Extension Register 1 */
+       unsigned long elct_hae0_2;      /* High Address Extension Register 2 */
+       unsigned long elct_hbase;       /* High Base Register */
+       unsigned long elct_wbase1;      /* Window Base Register 1 */
+       unsigned long elct_wmask1;      /* Window Mask Register 1 */
+       unsigned long elct_tbase1;      /* Translated Base Register 1 */
+       unsigned long elct_wbase2;      /* Window Base Register 2 */
+       unsigned long elct_wmask2;      /* Window Mask Register 2 */
+       unsigned long elct_tbase2;      /* Translated Base Register 2 */
+       unsigned long elct_tdr0;        /* TLB Data Register 0 */
+       unsigned long elct_tdr1;        /* TLB Data Register 1 */
+       unsigned long elct_tdr2;        /* TLB Data Register 2 */
+       unsigned long elct_tdr3;        /* TLB Data Register 3 */
+       unsigned long elct_tdr4;        /* TLB Data Register 4 */
+       unsigned long elct_tdr5;        /* TLB Data Register 5 */
+       unsigned long elct_tdr6;        /* TLB Data Register 6 */
+       unsigned long elct_tdr7;        /* TLB Data Register 7 */
+};
+
+/*
+ * Sable error log data structure - sable pfms section 3.40
+ */
+struct el_t2_data_corrected {
+       unsigned long elcpb_biu_stat;
+       unsigned long elcpb_biu_addr;
+       unsigned long elcpb_biu_ctl;
+       unsigned long elcpb_fill_syndrome;
+       unsigned long elcpb_fill_addr;
+       unsigned long elcpb_bc_tag;
+};
+
+/* 
+ * Sable error log data structure
+ * Note there are 4 memory slots on sable (see t2.h)
+ */
+struct el_t2_frame_mcheck {
+        struct el_t2_frame_header elfmc_header;        /* ID$P-FRAME_MCHECK */
+       struct el_t2_logout_header elfmc_hdr;
+       struct el_t2_procdata_mcheck elfmc_procdata;
+       struct el_t2_sysdata_mcheck elfmc_sysdata;
+       struct el_t2_data_t2 elfmc_t2data;
+       struct el_t2_data_memory elfmc_memdata[4]; 
+        struct el_t2_frame_header elfmc_footer;        /* empty */
+};
+
+
+/* 
+ * Sable error log data structures on memory errors
+ */
+struct el_t2_frame_corrected {
+        struct el_t2_frame_header elfcc_header;        /* ID$P-BC-COR */
+       struct el_t2_logout_header elfcc_hdr;
+       struct el_t2_data_corrected elfcc_procdata; 
+/*     struct el_t2_data_t2 elfcc_t2data;              */
+/*     struct el_t2_data_memory elfcc_memdata[4];      */
+        struct el_t2_frame_header elfcc_footer;        /* empty */
+};
+
+
+#define RTC_PORT(x)    (0x70 + (x))
+#define RTC_ADDR(x)    (0x80 | (x))
+#define RTC_ALWAYS_BCD 0
+
+#endif /* __ALPHA_T2__H__ */
index 7f6da89fb7e67d3816466f191454c7dc4299959d..7b851a1bd3c75ec24d78559c642136f04b94dc2a 100644 (file)
@@ -40,6 +40,8 @@ extern int EISA_bus;
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE      (0xC0000000UL)
+#define MAX_USER_ADDR  TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
index a87ab5bf1f48937af570386673a7759069592197..ccfa1ddfb83ace65f0197d39f153bd61471d9900 100644 (file)
@@ -14,6 +14,8 @@
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE      (0xF0000000UL)
+#define MAX_USER_ADDR  TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Bus types
index b6ba4c03954c28de90cfd3d75f40edb4b71319c8..26048cdc1935cc8c94b6d16be1782f41d39eac30 100644 (file)
@@ -44,6 +44,8 @@ extern int EISA_bus;
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE      (0x80000000UL)
+#define MAX_USER_ADDR  TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /*
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
index dc653912aa3b5f3a760509cacaa5dda3640064c9..9e94b50e513dddc6fd8d96a9ac5acbd553c92ff9 100644 (file)
@@ -80,6 +80,8 @@ static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsign
  * "this is gonna have to change to 1gig for the sparc" - David S. Miller
  */
 #define TASK_SIZE      (0x80000000UL)
+#define MAX_USER_ADDR  TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 struct thread_struct 
    {
index b06e267c9a45ea20e8beec3dbb9cb1ab5a8f82e3..8e8e1fa69ab8c94a2c2ab73bedd033b16821211b 100644 (file)
@@ -31,6 +31,8 @@
 
 /* Whee, this is STACK_TOP and the lowest kernel address too... */
 #define TASK_SIZE      (KERNBASE)
+#define MAX_USER_ADDR  TASK_SIZE
+#define MMAP_SEARCH_START (TASK_SIZE/3)
 
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
index c0f49f57d672ae9126ee87a9c6ee33c5bbd962e3..8492c3657a9785fb97b4cac808977c8d09a7a0a1 100644 (file)
@@ -313,7 +313,7 @@ struct inode {
        unsigned char i_sock;
        unsigned char i_seek;
        unsigned char i_update;
-       unsigned char i_condemned;
+       unsigned char i_condemned;
        union {
                struct pipe_inode_info pipe_i;
                struct minix_inode_info minix_i;
index 535cdefdc5315fa3b477819c7797f80a024cda7f..8075af6a558a394e55a0c402393930236f028a95 100644 (file)
 #define CONFIG_SUN_PARTITION 1
 #endif
 
-/* These two have identical behaviour; use the second one if DOS fdisk gets
+/* These three have identical behaviour; use the second one if DOS fdisk gets
    confused about extended/logical partitions starting past cylinder 1023. */
 #define DOS_EXTENDED_PARTITION 5
 #define LINUX_EXTENDED_PARTITION 0x85
+#define WIN98_EXTENDED_PARTITION 0x0f
 
 #define DM6_PARTITION          0x54    /* has DDO: use xlated geom & offset */
 #define EZD_PARTITION          0x55    /* EZ-DRIVE:  same as DM6 (we think) */
index 335e3b65f7631aca59e6d0ef5a0cac036e0b436c..293b46870f37a5cfe19ddd36478cd9f819c108b8 100644 (file)
@@ -24,7 +24,7 @@ extern int get_ioport_list(char *);
 
 
 #define HAVE_AUTOIRQ
-extern void *irq2dev_map[16];          /* Use only if you own the IRQ. */
+extern void *irq2dev_map[];            /* Use only if you own the IRQ. */
 extern int autoirq_setup(int waittime);
 extern int autoirq_report(int waittime);
 
index 04f905aaf086158ef156ccc4044c2f69bedd27c5..6a2240a2059e44815b5addd04e0b361a730eaeca 100644 (file)
@@ -13,7 +13,7 @@
 
 #define DLIST_INIT(listnam)                                    \
        (listnam).dl_prev = &(listnam);                         \
-       (listnam).dl_last = &(listnam);
+       (listnam).dl_next = &(listnam);
 
 #define DLIST_NEXT(listnam)    listnam.dl_next
 #define DLIST_PREV(listnam)    listnam.dl_prev
        node->listnam.dl_next->listnam.dl_prev =                \
                node->listnam.dl_prev;                          \
        } while (0)
+
+/*
+ * queue-style operations, which have a head and tail
+ */
+
+#define QUEUE_INIT(head, listnam, ptype)                               \
+       (head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head);
+
+#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
+#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
+#define QUEUE_EMPTY(head, listnam) \
+       ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
+        ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) 
+
+#define QUEUE_ENTER(head, new, listnam, ptype) do {            \
+       (new)->listnam.dl_prev = (ptype)(head);                 \
+       (new)->listnam.dl_next = (head)->listnam.dl_next;       \
+       (head)->listnam.dl_next->listnam.dl_prev = (new);       \
+       (head)->listnam.dl_next = (new);                        \
+       } while (0)
+
+#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam)
index e870910c495841a53320bcea57513a895ce35a49..0a2efb6e930ddbe0044d808c181b2fd6b3c9795e 100644 (file)
@@ -142,6 +142,8 @@ struct rtc_time {
 #define RTC_SET_TIME   _IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
 #define RTC_IRQP_READ  _IOR('p', 0x0b, unsigned long)   /* Read IRQ rate   */
 #define RTC_IRQP_SET   _IOW('p', 0x0c, unsigned long)   /* Set IRQ rate    */
+#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long)   /* Read epoch      */
+#define RTC_EPOCH_SET  _IOW('p', 0x0e, unsigned long)   /* Set epoch       */
 
 
 #endif /* _MC146818RTC_H */
index 91538d2bde3c042a4688226017d6b7e25247fa39..14df1888dca48e1e0880399714735b23f4ef924f 100644 (file)
@@ -8,12 +8,16 @@
 /* Flags for bug emulation. These occupy the top three bytes. */
 #define STICKY_TIMEOUTS                0x4000000
 #define WHOLE_SECONDS          0x2000000
+#define ADDR_MAX_32BIT         0x1000000
+#define ADDR_MAX_31BIT         0x0800000
 
 /* Personality types. These go in the low byte. Avoid using the top bit,
  * it will conflict with error returns.
  */
 #define PER_MASK               (0x00ff)
 #define PER_LINUX              (0x0000)
+#define PER_LINUX_32BIT                (PER_LINUX | ADDR_MAX_32BIT)
+#define PER_LINUX_EM86         (PER_LINUX | ADDR_MAX_31BIT)
 #define PER_SVR4               (0x0001 | STICKY_TIMEOUTS)
 #define PER_SVR3               (0x0002 | STICKY_TIMEOUTS)
 #define PER_SCOSVR3            (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
index 6cfb7df0bb9da3aa7b9a9cf41e9c9b24c56c4e1c..47851e7a0d0971a96288077cb48145dcdee9eed7 100644 (file)
 
 #define SWAP_CLUSTER_MAX 32
 
+#define SWAP_MAP_MAX     0xfffe        /* max val of swapinfo->swap_map[n] */
+#define SWAP_MAP_RESERVED 0xffff       /* max val of swapinfo->swap_map[n] */
+
 struct swap_info_struct {
        unsigned int flags;
        kdev_t swap_device;
        struct inode * swap_file;
-       unsigned char * swap_map;
+       unsigned short * swap_map;
        unsigned char * swap_lockmap;
        int lowest_bit;
        int highest_bit;
index aa6577d741f9d16eeb578f828e2d7a9685e00db7..a90abf633ec8d2db3b1ca057f5d0026fc481b5cb 100644 (file)
@@ -19,6 +19,7 @@
 
 extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer);
 
 #endif
 
index a9750b55712defbb42790fbaabe6db5f7313c031..f940324976886779a2687e0e527cc7ebd8349a01 100644 (file)
@@ -454,7 +454,7 @@ static void ramdisk_start_setup(char *str, int *ints)
 static void load_ramdisk(char *str, int *ints)
 {
    if (ints[0] > 0 && ints[1] >= 0)
-      rd_doload = ints[1] & 1;
+      rd_doload = ints[1] & 3;
 }
 
 static void prompt_ramdisk(char *str, int *ints)
index c92914a0cc1c2dfb0bd5f6f0bbf1545183b4ed1f..8436259468b1db1e6724702fe7eca1ff9a9686f6 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -494,10 +494,10 @@ asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                        return -EINVAL;
        }
        /*
-        * Check if addr exceeds TASK_SIZE (from do_mmap)
+        * Check if addr exceeds MAX_USER_ADDR (from do_mmap)
         */
        len = PAGE_SIZE*shp->shm_npages;
-       if (addr >= TASK_SIZE || len > TASK_SIZE  || addr > TASK_SIZE - len)
+       if (addr >= MAX_USER_ADDR || len > MAX_USER_ADDR  || addr > MAX_USER_ADDR - len)
                return -EINVAL;
        /*
         * If shm segment goes below stack, make sure there is some
index 99552fc1771157db4a6b7b98ad86ae0f72f941f1..ae2bb35188578c6662aa5e448cc9443aeed9cdbc 100644 (file)
@@ -660,9 +660,14 @@ repeat:
                        if (p->pgrp != -pid)
                                continue;
                }
-               /* wait for cloned processes iff the __WCLONE flag is set */
-               if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
-                       continue;
+               /* If you are tracing a process, then you don't need to get the
+                * WCLONE bit right -- useful for strace and gdb
+                */
+               if (!(p->flags & (PF_PTRACED|PF_TRACESYS))) {
+                       /* wait for cloned processes iff the __WCLONE flag is set */
+                       if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+                               continue;
+               }
                flag = 1;
                switch (p->state) {
                        case TASK_STOPPED:
index 868f6a9d41cd9c563b5b49216b3682bc8dbf39f2..962e13d731f8d41de0818988cf31ff286e1a1564 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -45,7 +45,7 @@ pgprot_t protection_map[16] = {
  * Check that a process has enough memory to allocate a
  * new virtual mapping.
  */
-static inline int vm_enough_memory(long pages)
+int vm_enough_memory(long pages)
 {
        /*
         * stupid algorithm to decide if we have enough memory: while
@@ -147,7 +147,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
        if ((len = PAGE_ALIGN(len)) == 0)
                return addr;
 
-       if (len > TASK_SIZE || addr > TASK_SIZE-len)
+       if (len > MAX_USER_ADDR || addr > MAX_USER_ADDR-len)
                return -EINVAL;
 
        /* offset overflow? */
@@ -178,6 +178,9 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
                         */
                        if (locks_verify_locked(file->f_inode))
                                return -EAGAIN;
+                       /* cevans -- whoops another append-only file flaw */
+                       if (IS_APPEND(file->f_inode) && (prot & PROT_WRITE))
+                               return -EACCES;
                        /* fall through */
                case MAP_PRIVATE:
                        if (!(file->f_mode & 1))
@@ -306,15 +309,15 @@ unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
 {
        struct vm_area_struct * vmm;
 
-       if (len > TASK_SIZE)
+       if (len > MAX_USER_ADDR)
                return 0;
        if (!addr)
-               addr = TASK_SIZE / 3;
+               addr = MMAP_SEARCH_START;
        addr = PAGE_ALIGN(addr);
 
        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
                /* At this point:  (!vmm || addr < vmm->vm_end). */
-               if (TASK_SIZE - len < addr)
+               if (MAX_USER_ADDR - len < addr)
                        return 0;
                if (!vmm || addr + len <= vmm->vm_start)
                        return addr;
@@ -794,7 +797,7 @@ int do_munmap(unsigned long addr, size_t len)
 {
        struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
 
-       if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
+       if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr)
                return -EINVAL;
 
        if ((len = PAGE_ALIGN(len)) == 0)
index 3284e04bbef2b280f9d9f6c6cc325e4b7f4e4005..b483806350e1674c22d5199de038ffadd8f967b9 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 
+extern int vm_enough_memory(long pages);
+
 static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
 {
        pgd_t * pgd;
@@ -173,7 +175,7 @@ asmlinkage unsigned long sys_mremap(unsigned long addr,
         * Always allow a shrinking remap: that just unmaps
         * the unnecessary pages..
         */
-       if (old_len > new_len) {
+       if (old_len >= new_len) {
                do_munmap(addr+new_len, old_len - new_len);
                return addr;
        }
@@ -196,11 +198,16 @@ asmlinkage unsigned long sys_mremap(unsigned long addr,
        if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
            > current->rlim[RLIMIT_AS].rlim_cur)
                return -ENOMEM;
+       /* Private writable mapping? Check memory availability.. */
+       if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
+               if (!vm_enough_memory((new_len - old_len) >> PAGE_SHIFT))
+                       return -ENOMEM;
+       }
 
        /* old_len exactly to the end of the area.. */
        if (old_len == vma->vm_end - addr &&
            (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
-               unsigned long max_addr = TASK_SIZE;
+               unsigned long max_addr = MAX_USER_ADDR;
                if (vma->vm_next)
                        max_addr = vma->vm_next->vm_start;
                /* can we just expand the current mapping? */
index 9ca40ff9a7f53d851a4d8bb349d06b7129da9b5b..4f2fb2a625efdadbecdcedc54139594d419a0fc0 100644 (file)
@@ -81,6 +81,12 @@ unsigned long init_swap_cache(unsigned long mem_start,
        return (unsigned long) (swap_cache + swap_cache_size);
 }
 
+/* We shouldn't be able to have more processes sharing a swapped page than
+   we can count in the swap map */
+#if NR_TASKS > SWAP_MAP_MAX
+#error SWAP_MAP_MAX is too small
+#endif
+
 void swap_duplicate(unsigned long entry)
 {
        struct swap_info_struct * p;
@@ -98,14 +104,16 @@ void swap_duplicate(unsigned long entry)
        }
        p = type + swap_info;
        if (offset >= p->max) {
-               printk("swap_duplicate: weirdness\n");
-               return;
-       }
-       if (!p->swap_map[offset]) {
-               printk("swap_duplicate: trying to duplicate unused page\n");
+               printk("swap_duplicate: weirdness, entry %08lx\n", entry);
                return;
        }
-       p->swap_map[offset]++;
+       if (!p->swap_map[offset])
+               printk("swap_duplicate: trying to duplicate unused page, "
+                      "entry %08lx\n", entry);
+       else if (p->swap_map[offset] == SWAP_MAP_RESERVED)
+               printk("swap_duplicate: trying to duplicate reserved page, "
+                      "entry %08lx\n", entry);
+       else p->swap_map[offset]++;
        return;
 }
 
index 70d8703bf73163c01b0d9816bf1cff818a7d723b..15384cc8bb70dc23085262a6bc2960233ccfeb18 100644 (file)
@@ -145,9 +145,10 @@ void swap_free(unsigned long entry)
        if (offset > p->highest_bit)
                p->highest_bit = offset;
        if (!p->swap_map[offset])
-               printk("swap_free: swap-space map bad (entry %08lx)\n",entry);
-       else
-               if (!--p->swap_map[offset])
+               printk("swap_free: swap-space map null (entry %08lx)\n",entry);
+       else if (p->swap_map[offset] == SWAP_MAP_RESERVED)
+               printk("swap_free: swap-space reserved (entry %08lx)\n",entry);
+       else if (!--p->swap_map[offset])
                        nr_swap_pages++;
        if (p->prio > swap_info[swap_list.next].prio) {
            swap_list.next = swap_list.head;
@@ -503,7 +504,7 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
                error = -EINVAL;
                goto bad_swap;
        }
-       p->swap_map = (unsigned char *) vmalloc(p->max);
+       p->swap_map = (unsigned short *) vmalloc(p->max * sizeof(short));
        if (!p->swap_map) {
                error = -ENOMEM;
                goto bad_swap;
@@ -512,9 +513,9 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
                if (test_bit(i,p->swap_lockmap))
                        p->swap_map[i] = 0;
                else
-                       p->swap_map[i] = 0x80;
+                       p->swap_map[i] = SWAP_MAP_RESERVED;
        }
-       p->swap_map[0] = 0x80;
+       p->swap_map[0] = SWAP_MAP_RESERVED;
        memset(p->swap_lockmap,0,PAGE_SIZE);
        p->flags = SWP_WRITEOK;
        p->pages = j;
@@ -562,7 +563,7 @@ void si_swapinfo(struct sysinfo *val)
                        continue;
                for (j = 0; j < swap_info[i].max; ++j)
                        switch (swap_info[i].swap_map[j]) {
-                               case 128:
+                               case SWAP_MAP_RESERVED:
                                        continue;
                                case 0:
                                        ++val->freeswap;
index 4f83db95a24a3dd6bea47cf2937b96de75f0ad60..6cc59a8139a98e6c1f4dba081fc70c3e445fc6b5 100644 (file)
@@ -1534,7 +1534,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
        newsk = skb->sk;
        newsk->pair = NULL;
        newsk->socket = newsock;
-       newsk->sleep = &newsock->wait;
+       newsk->sleep = newsock->wait;
        sti();
 
        /* Now attach up the new socket */
index eeda476916d6e9101e1b4a209e5ddbdeef498c5f..bb8760331375a5998e36e2ed3ad1cd0a4bf03c7c 100644 (file)
@@ -72,6 +72,7 @@
  *                                     easier (suggested by Craig Metz).
  *             Michael Pall    :       SO_ERROR returns positive errno again
  *              Elliot Poger    :       Added support for SO_BINDTODEVICE.
+ *             Russell King    :       Add #ifdef CONFIG_INET to SO_BINDTODEVICE
  *
  * To Fix:
  *
@@ -247,13 +248,13 @@ int sock_setsockopt(struct sock *sk, int level, int optname,
                                if(err)
                                        return err;
                                memcpy_fromfs(&req,optval,sizeof(req));
-
+#ifdef CONFIG_INET
                                /* Remove any cached route for this socket. */
                                if (sk->ip_route_cache) {
                                        ip_rt_put(sk->ip_route_cache);
                                        sk->ip_route_cache=NULL;
                                }
-
+#endif
                                if (*(req.ifr_name) == '\0') {
                                        sk->bound_device = NULL;
                                } else {
index 61eb8f02b1451452367c515e1a79a5ec37527de3..d06dbb59a32891cc3476d6a565fdb444875ed2ce 100644 (file)
@@ -30,6 +30,8 @@
  *             Alan Cox        : Protect against forwarding explosions with
  *                               older network drivers and IFF_ALLMULTI.
  *     Christer Weinigel       : Better rebuild header message.
+ *             Russell King    : eth_header_cache_bind and eth_header_cache_update
+ *                               only compiled if CONFIG_INET is selected
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -218,6 +220,7 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
        return htons(ETH_P_802_2);
 }
 
+#ifdef CONFIG_INET
 /*
  * Upper level calls this function to bind hardware header cache entry.
  * If the call is successful, then corresponding Address Resolution Protocol
@@ -258,6 +261,7 @@ void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned c
        memcpy(hh->hh_data, haddr, ETH_ALEN);
        hh->hh_uptodate = 1;
 }
+#endif
 
 /*
  *     Copy from an ethernet device memory space to an sk_buff while checksumming if IP
index 4fe8a32c9d745c41ef48478818100b3e2fa820fd..76b52fc6dfb5c48a8e4104bef32e849392108eb4 100644 (file)
@@ -838,8 +838,6 @@ static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
                __u32 addr = sk->rcv_saddr;
                if (!addr) {
                        addr = sk->saddr;
-                       if (!addr)
-                               addr = ip_my_addr();
                }
                sin->sin_port = sk->dummy_th.source;
                sin->sin_addr.s_addr = addr;
index ac1f7ed35a10aed326ad07c6c641edc01557044a..dc8b276165a320c4fc0d9c9ca08cdc05fd26b812 100644 (file)
@@ -28,7 +28,9 @@
  * Fixes
  *     Alan Cox        :       Rarp delete on device down needed as
  *                             reported by Walter Wolfgang.
- *  Lawrence V. Stefani : Added FDDI support.
+ *  Lawrence V. Stefani :      Added FDDI support.
+ *      San Mehat      :       Fixed bug where rarp would fail to build
+ *                             if procfs was not compiled into the kernel
  */
 
 #include <linux/module.h>
index f598c993d62610c318c26e4114926a8874802fda..1e72c56c7ebc35d01eeda200e03cfc272dc04bec 100644 (file)
@@ -2067,9 +2067,11 @@ static struct sk_buff * wait_for_connect(struct sock * sk)
        add_wait_queue(sk->sleep, &wait);
        for (;;) {
                current->state = TASK_INTERRUPTIBLE;
+               end_bh_atomic();
                release_sock(sk);
                schedule();
                lock_sock(sk);
+               start_bh_atomic();
                skb = tcp_find_established(sk);
                if (skb)
                        break;
@@ -2101,7 +2103,7 @@ static struct sock *tcp_accept(struct sock *sk, int flags)
        if (sk->state != TCP_LISTEN)
                goto no_listen;
 
-       lock_sock(sk);
+       lock_sock(sk);start_bh_atomic();
 
        skb = tcp_find_established(sk);
        if (skb) {
@@ -2112,6 +2114,7 @@ got_new_connect:
                sk->ack_backlog--;
                error = 0;
 out:
+               end_bh_atomic();
                release_sock(sk);
 no_listen:
                sk->err = error;
index 0b910d58082196ea99ba24c528c5e3a48b44b3ac..2cd03603eaa533d8d3705429911b6a250ea05d7d 100644 (file)
@@ -370,7 +370,7 @@ void tcp_write_xmit(struct sock *sk)
                          * a packet that contains both old and new data. (Feh!)
                          * Soooo, we have this uglyness here.
                          */
-                       if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin))
+                       if (after(sk->rcv_ack_seq,skb->seq+th->syn))
                                tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
 
                        size = skb->len - (((unsigned char *) th) - skb->data);
@@ -487,6 +487,21 @@ void tcp_do_retransmit(struct sock *sk, int all)
 
                iph = (struct iphdr *)skb->data;
                th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2));
+
+               /* See if we need to shrink the leading packet on
+                * the retransmit queue. Strictly speaking, we
+                * should never need to do this, but some buggy TCP
+                * implementations get confused if you send them
+                * a packet that contains both old and new data. (Feh!)
+                * Soooo, we have this uglyness here.
+                *
+                * Is the && test needed here? If so, then it implies that
+                * we might be retransmitting an acked packet. This code is
+                * needed here to talk to Solaris 2.6 stack.
+                */
+               if (after(sk->rcv_ack_seq,skb->seq+th->syn) && before(sk->rcv_ack_seq, skb->end_seq))
+                       tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
+
                size = ntohs(iph->tot_len) - (iph->ihl<<2);
                
                /*
@@ -1399,6 +1414,10 @@ void tcp_send_probe0(struct sock *sk)
  * Needed to deal with buggy TCP implementations that can't deal
  * with seeing a packet that contains some data that has already
  * been received.
+ *
+ * Note that the SYN sequence number is at the start of the packet
+ * while the FIN is at the end. This means that we always clear out
+ * the SYN bit, and never clear out the FIN bit.
  */
 void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
 {
@@ -1416,9 +1435,9 @@ void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
        th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
 
        /* how much data are we droping from the tcp frame */
-       diff = ack - skb->seq;
+       diff = ack - (skb->seq + th->syn);
        /* how much data are we keeping in the tcp frame */
-       len = (skb->end_seq - (th->fin + th->syn)) - ack;
+       len = (skb->end_seq - th->fin) - ack;
 
        /* pointers to new start of remaining data, and old start */
        new = (unsigned char *)th + th->doff*4;
@@ -1427,6 +1446,7 @@ void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
        /* Update our starting seq number */
        skb->seq = ack;
        th->seq = htonl(ack);
+       th->syn = 0;            /* Turn SYN off as it is logically at the start of the packet */
 
        iph->tot_len = htons(ntohs(iph->tot_len)-diff);
        ip_send_check(iph);
index 9bb558d900251352d900ca325cbc69562d8fb5d1..b183d634b26e12f82c68aa30e9c149eb4d83cb89 100644 (file)
@@ -909,7 +909,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
        newsk = skb->sk;
        newsk->pair = NULL;
        newsk->socket = newsock;
-       newsk->sleep = &newsock->wait;
+       newsk->sleep = newsock->wait;
        sti();
 
        /* Now attach up the new socket */
index a25fe622dab967e35b1bef283bdafa2f597ed0d4..ed2086f569beb8cb2749b70f3ee2276ca62cb386 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
+#include <net/sock.h>
 
 #ifdef CONFIG_AX25
 #include <net/ax25.h>
index 01f4ccd1f6270ec33321558e0165288ab4660966..3bb14b3c0b9b7223d1e42ac74ce50de8f9606857 100644 (file)
@@ -28,6 +28,7 @@
  *             Nick Nevin      :       recvmsg bugfix.
  *             Alan Cox        :       Started proper garbage collector
  *             Heiko EiBfeldt  :       Missing verify_area check
+ *             Alan Cox        :       Shutdown() bug
  *
  * Known differences from reference BSD that was tested:
  *
@@ -1155,6 +1156,9 @@ static int unix_shutdown(struct socket *sock, int mode)
 {
        unix_socket *sk=(unix_socket *)sock->data;
        unix_socket *other=sk->protinfo.af_unix.other;
+       
+       mode++;
+       
        if(mode&SEND_SHUTDOWN)
        {
                sk->shutdown|=SEND_SHUTDOWN;