]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.27pre6 2.3.27pre6
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:28:33 +0000 (15:28 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:28:33 +0000 (15:28 -0500)
83 files changed:
CREDITS
MAINTAINERS
arch/alpha/mm/extable.c
arch/arm/mm/extable.c
arch/i386/mm/extable.c
arch/i386/mm/init.c
arch/m68k/math-emu/fp_emu.h
arch/m68k/mm/extable.c
arch/mips/mm/extable.c
arch/ppc/amiga/config.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/entry.S
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/process.c
arch/ppc/kernel/setup.c
arch/ppc/mm/extable.c
arch/sh/mm/extable.c
arch/sparc/mm/extable.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/mm/extable.c
drivers/block/nbd.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/cs8420.h [new file with mode: 0644]
drivers/char/drm/sigio.c
drivers/char/ibmmpeg2.h [new file with mode: 0644]
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/n_hdlc.c
drivers/char/pms.c
drivers/char/saa7121.h [new file with mode: 0644]
drivers/char/saa7146.h [new file with mode: 0644]
drivers/char/saa7146reg.h [new file with mode: 0644]
drivers/char/stradis.c [new file with mode: 0644]
drivers/char/videodev.c
drivers/i2o/README
drivers/i2o/README.ioctl
drivers/i2o/i2o_config.c
drivers/i2o/i2o_core.c
drivers/i2o/i2o_lan.c
drivers/i2o/i2o_lan.h
drivers/i2o/i2o_pci.c
drivers/i2o/i2o_proc.c
drivers/i2o/i2o_proc.h [deleted file]
drivers/i2o/i2o_scsi.c
drivers/net/3c507.c
drivers/net/Makefile
drivers/net/dmfe.c
drivers/net/es3210.c
drivers/net/ncr885e.c
drivers/net/pcmcia/ray_cs.c
drivers/net/sk_mca.c
drivers/scsi/Makefile
drivers/scsi/hosts.c
drivers/scsi/inia100.c
drivers/scsi/sd.c
drivers/scsi/sd_ioctl.c [deleted file]
drivers/usb/Makefile
drivers/usb/README.serial
drivers/usb/usb-serial.c
fs/buffer.c
fs/exec.c
fs/proc/kcore.c
fs/proc/procfs_syms.c
fs/udf/misc.c
fs/udf/udfdecl.h
include/asm-ppc/div64.h [new file with mode: 0644]
include/asm-ppc/fcntl.h
include/asm-ppc/processor.h
include/linux/highmem.h
include/linux/i2o.h
include/linux/mm.h
include/linux/module.h
include/linux/nbd.h
include/linux/pagemap.h
include/linux/swap.h
kernel/kmod.c
kernel/ksyms.c
kernel/module.c
mm/highmem.c
mm/mmap.c
mm/page_alloc.c
mm/vmscan.c

diff --git a/CREDITS b/CREDITS
index 851e85409d340e89bf569fdb5e06c2f472e08f7d..1ba9d2ae57533d7fb5ba04400ed64f14b45ec84f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -508,8 +508,8 @@ S: 4850 Moresnet
 S: Belgium
 
 N: Cort Dougan
-E: cort@cs.nmt.edu
-W: http://www.cs.nmt.edu/~cort/
+E: cort@ppc.kernel.org
+W: http://www.ppc.kernel.org/~cort/
 D: PowerPC
 S: Computer Science Department
 S: New Mexico Tech
index 118d5e64dafe5a1d3d0ddf5836ff0e65f9313095..57c707116bd7a8945b64cf4833485b1447fade54 100644 (file)
@@ -522,10 +522,10 @@ M:        eis@baty.hanse.de
 L:     linux-x25@vger.rutgers.edu
 S:     Maintained
 
-LINUX FOR POWERPC (PREP)
+LINUX FOR POWERPC
 P:     Cort Dougan
-M:     cort@cs.nmt.edu
-W:     http://linuxppc.cs.nmt.edu/
+M:     cort@ppc.kernel.org
+W:     http://www.ppc.kernel.org/
 S:     Maintained
 
 LINUX FOR POWER MACINTOSH
index ea1387f791d643677f806a2ee29025d8fcc61e56..12a1f4803fd1f47a175d60c00a896946ba7fbe83 100644 (file)
@@ -49,18 +49,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special. */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp ; mp = mp->next) {
                if (!mp->ex_table_start)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr - mp->gp);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index c98ba5a9e0295f38ec4cf6619c024cfeba2adf90..e603b6362041b228401380a1fcec7228555b52ff 100644 (file)
@@ -42,18 +42,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index 398a62fa1a73c178241d82fd5b1d13e152fc0511..ba34c0395812fdc712d3143fee0a22f29c09dd3b 100644 (file)
@@ -42,18 +42,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index 48b4b83ec06f6aeb3b32486aff280c092e0258e1..099696197020ade5b76ded6ef9bbe15586ca1bae 100644 (file)
@@ -422,11 +422,16 @@ void __init paging_init(void)
 #ifdef CONFIG_HIGHMEM
        kmap_init(); /* run after fixmap_init */
 #endif
-#ifdef CONFIG_HIGHMEM
-       free_area_init(highend_pfn);
-#else
-       free_area_init(max_low_pfn);
-#endif
+       {
+               unsigned int zones_size[3];
+
+               zones_size[0] = virt_to_phys((char *)MAX_DMA_ADDRESS)
+                                        >> PAGE_SHIFT;
+               zones_size[1] = max_low_pfn - zones_size[0];
+               zones_size[2] = highend_pfn - zones_size[0] - zones_size[1];
+
+               free_area_init(zones_size);
+       }
        return;
 }
 
@@ -541,7 +546,7 @@ void __init mem_init(void)
        totalram_pages += totalhigh_pages;
 #endif
        printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
-               (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
                max_mapnr << (PAGE_SHIFT-10),
                codepages << (PAGE_SHIFT-10),
                reservedpages << (PAGE_SHIFT-10),
@@ -587,10 +592,10 @@ void si_meminfo(struct sysinfo *val)
 {
        val->totalram = totalram_pages;
        val->sharedram = 0;
-       val->freeram = nr_free_pages;
+       val->freeram = nr_free_pages();
        val->bufferram = atomic_read(&buffermem_pages);
        val->totalhigh = totalhigh_pages;
-       val->freehigh = nr_free_highpages;
+       val->freehigh = nr_free_highpages();
        val->mem_unit = PAGE_SIZE;
        return;
 }
index 9344b939b09c5b62dfca6f26757b62e40fc07940..1a4e168020049a572e15242f79e8ba3bddcc501f 100644 (file)
 #ifndef _FP_EMU_H
 #define _FP_EMU_H
 
-#ifndef __ASSEMBLY__
-
+#include "../kernel/m68k_defs.h"
 #include <asm/math-emu.h>
 
+#ifndef __ASSEMBLY__
+
 #define IS_INF(a) ((a)->exp == 0x7fff)
 #define IS_ZERO(a) ((a)->mant.m64 == 0)
 
@@ -114,9 +115,6 @@ extern const struct fp_ext fp_Inf;
 
 #else /* __ASSEMBLY__ */
 
-#include "../kernel/m68k_defs.h"
-#include <asm/math-emu.h>
-
 /*
  * set, reset or clear a bit in the fp status register
  */
index 7cd5d5c644da3a5e63e2db648452210a531f19dc..1f8d9e8c3323997fd02f3a339d835bcd83cdfa37 100644 (file)
@@ -42,18 +42,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end-1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index 8a0febc3813657befc4e7d29e22b9a1a67037469..a92fdc482e9fb71cde6796825efdf8e0aa1231c3 100644 (file)
@@ -41,18 +41,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index c66e2359bf8292761c82cf56329818209de6bf7b..29b738eec055d619d52ea9ed81adec334493f038 100644 (file)
@@ -32,7 +32,6 @@ void (*mach_kbd_reset_setup) (char *, int) __initdata = 0;
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
-#include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
index e70ba4dcab3aba543286a8a20b2d274eb14d4bef..d0825ce8bddf1bcfa5de54d8334e1993dedbc82d 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/openpic.h>
 #include <linux/version.h>
 #include <linux/adb.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
 
@@ -576,9 +575,10 @@ void __init
        ppc_md.calibrate_decr = chrp_calibrate_decr;
 
 #ifdef CONFIG_VT
-#ifdef CONFIG_MAC_KEYBOAD
+#ifdef CONFIG_MAC_KEYBOARD
        if (adb_driver == NULL)
        {
+#endif /* CONFIG_MAC_KEYBOAD */
                ppc_md.kbd_setkeycode    = pckbd_setkeycode;
                ppc_md.kbd_getkeycode    = pckbd_getkeycode;
                ppc_md.kbd_translate     = pckbd_translate;
@@ -588,7 +588,8 @@ void __init
 #ifdef CONFIG_MAGIC_SYSRQ
                ppc_md.ppc_kbd_sysrq_xlate       = pckbd_sysrq_xlate;
                SYSRQ_KEY = 0x54;
-#endif         
+#endif /* CONFIG_MAGIC_SYSRQ */
+#ifdef CONFIG_MAC_KEYBOARD
        }
        else
        {
@@ -601,24 +602,13 @@ void __init
 #ifdef CONFIG_MAGIC_SYSRQ
                ppc_md.ppc_kbd_sysrq_xlate       = mackbd_sysrq_xlate;
                SYSRQ_KEY = 0x69;
-#endif         
+#endif /* CONFIG_MAGIC_SYSRQ */
        }
-#else
-       ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-       ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-       ppc_md.kbd_translate     = pckbd_translate;
-       ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-       ppc_md.kbd_leds          = pckbd_leds;
-       ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-       ppc_md.ppc_kbd_sysrq_xlate       = pckbd_sysrq_xlate;
-       SYSRQ_KEY = 0x54;
-#endif
+#endif /* CONFIG_MAC_KEYBOARD */
+#endif /* CONFIG_VT */
        if ( rtas_data )
                ppc_md.progress = chrp_progress;
-#endif
-#endif
-
+       
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
         ppc_ide_md.insw = chrp_ide_insw;
         ppc_ide_md.outsw = chrp_ide_outsw;
index 9c940a0373f2e6ca3da8d192c0e4aa3a339c2484..6133f32cafef018a59bf4651f2a46be71dfda3d3 100644 (file)
@@ -411,9 +411,9 @@ enter_rtas:
        addis   r7,r7,-KERNELBASE@h
        lis     r8,rtas_entry@ha
        lwz     r8,rtas_entry@l(r8)
-       addis   r5,r8,-KERNELBASE@h
        mfmsr   r9
        stw     r9,8(r1)
+       li      r0,0
        ori     r0,r0,MSR_EE|MSR_SE|MSR_BE
        andc    r0,r9,r0
        andi.   r9,r9,MSR_ME|MSR_RI
index acfe744ec9b96415a49893bb53c535c8ead602b3..f494b04c7e844bd4c62946f28952605d84c0d327 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/ide.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
index a6592f12817e2019ebd332c6746c7e552a67834c..adeeefe33d256ed9216d1b828b023b71e71fe32a 100644 (file)
@@ -585,8 +585,8 @@ void __init ll_puts(const char *s)
  */
 extern void scheduling_functions_start_here(void);
 extern void scheduling_functions_end_here(void);
-#define first_sched    ((unsigned long) scheduling_functions_start_here)
-#define last_sched     ((unsigned long) scheduling_functions_end_here)
+#define first_sched    ((unsigned long) scheduling_functions_start_here)
+#define last_sched     ((unsigned long) scheduling_functions_end_here)
 
 unsigned long get_wchan(struct task_struct *p)
 {
index ce9a230ac419967bf49d9a502b58e2b25eef0254..2cf9ee71410a58af4fed2598cd7a1119a3fd92f6 100644 (file)
@@ -389,12 +389,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 
        if ( have_of )
        {
-#ifdef CONFIG_MACH_SPECIFIC
                /* prom_init has already been called from __start */
                if (boot_infos)
                        relocate_nodes();
                finish_device_tree();
-#endif /* CONFIG_MACH_SPECIFIC */
                /*
                 * If we were booted via quik, r3 points to the physical
                 * address of the command-line parameters.
@@ -450,7 +448,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
        int_control.int_cli = __no_use_cli;
        int_control.int_save_flags = __no_use_save_flags;
        int_control.int_restore_flags = __no_use_restore_flags;
-       
+
        switch (_machine)
        {
        case _MACH_Pmac:
index dc57bf86845b38e4bc94ba5062a3260fbf9b6f16..afcf705e14a630314c4d86fa3f229809d9ecaf44 100644 (file)
@@ -43,18 +43,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index 7c677a970bfeafd238f2318d4a52b642309def62..dc77f57fe2438317a9de8ab0776bee0e8d2dd711 100644 (file)
@@ -45,18 +45,13 @@ search_exception_table(unsigned long addr)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end - 1, addr);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index e66e4c72a00304975b054e6f643384ee85c457ed..7fe26ad96edda0f499518fd6db79f9e96528e582 100644 (file)
@@ -56,18 +56,13 @@ search_exception_table(unsigned long addr, unsigned long *g2)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end-1, addr, g2);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index c25879850a6e330c4e94f5a489ef63849a2b01a1..a1e0f26dd9a6b115f6ce3ebfd9437e823e3df435 100644 (file)
@@ -2932,7 +2932,6 @@ put_mod_name(char *buf)
        free_page((unsigned long)buf);
 }
 
-/* caller must hold modlist_lock at least in read mode */
 static __inline__ struct module *find_module(const char *name)
 {
        struct module *mod;
@@ -3162,7 +3161,7 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne
        struct module *mod;
        int err;
 
-       read_lock(&modlist_lock);
+       lock_kernel();
        if (name_user == 0) {
                /* This finds "kernel_module" which is not exported. */
                for(mod = module_list; mod->next != NULL; mod = mod->next)
@@ -3212,7 +3211,7 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne
                break;
        }
 out:
-       read_unlock(&modlist_lock);
+       unlock_kernel();
        return err;
 }
 
index a8d4964df0b30f2cc2ba5ab54d378a131cb1d5ad..b2df0e169ac0763a96e4be2010eacab967cf644a 100644 (file)
@@ -56,18 +56,13 @@ search_exception_table(unsigned long addr, unsigned long *g2)
 #else
        /* The kernel is the last "module" -- no need to treat it special.  */
        struct module *mp;
-       read_lock(&modlist_lock);
        for (mp = module_list; mp != NULL; mp = mp->next) {
                if (mp->ex_table_start == NULL)
                        continue;
                ret = search_one_table(mp->ex_table_start,
                                       mp->ex_table_end-1, addr, g2);
-               if (ret) {
-                       read_unlock(&modlist_lock);
-                       return ret;
-               }
+               if (ret) return ret;
        }
-       read_unlock(&modlist_lock);
 #endif
 
        return 0;
index ab18b55b00a09e91c8005766c3ba0259e9d201e4..7c24449ac014eba820294ee47a4c6b9d564d7171 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/ioctl.h>
+#include <net/sock.h>
 
 #include <asm/segment.h>
 #include <asm/uaccess.h>
@@ -105,6 +106,7 @@ static int nbd_xmit(int send, struct socket *sock, char *buf, int size)
 
 
        do {
+               sock->sk->allocation = GFP_ATOMIC;
                iov.iov_base = buf;
                iov.iov_len = size;
                msg.msg_name = NULL;
index 540217fa227a686a0dd59e085598b077f2009116..52b4bbd17c65445adfc412ed4261f92835d0ec5b 100644 (file)
@@ -167,6 +167,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
         dep_tristate '  SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
       fi
    fi
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      dep_tristate '  Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV
+   fi
    dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
       hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
index f4a6944f28e323754ae06180923a275af5e44158..5b29bcafbe9150a9d1bfaba45d5bdfe7f0ec674d 100644 (file)
@@ -450,6 +450,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_VIDEO_STRADIS),y)
+O_OBJS += vino.o
+else
+  ifeq ($(CONFIG_VIDEO_STRADIS),m)
+  M_OBJS += stradis.o
+  endif
+endif
+
 ifeq ($(CONFIG_RADIO_AZTECH),y)
 O_OBJS += radio-aztech.o
 else
diff --git a/drivers/char/cs8420.h b/drivers/char/cs8420.h
new file mode 100644 (file)
index 0000000..2b22f3a
--- /dev/null
@@ -0,0 +1,50 @@
+/* cs8420.h - cs8420 initializations
+   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+#ifndef __CS8420_H__
+#define __CS8420_H__
+
+/* Initialization Sequence */
+        
+static __u8 init8420[] = {
+       1, 0x01,        2, 0x02,        3, 0x00,        4, 0x46,
+       5, 0x24,        6, 0x84,        18, 0x18,       19, 0x13,
+};
+
+#define INIT8420LEN    (sizeof(init8420)/2)
+
+static __u8 mode8420pro[] = {  /* professional output mode */
+       32, 0xa1,       33, 0x00,       34, 0x00,       35, 0x00,
+       36, 0x00,       37, 0x00,       38, 0x00,       39, 0x00,
+       40, 0x00,       41, 0x00,       42, 0x00,       43, 0x00,
+       44, 0x00,       45, 0x00,       46, 0x00,       47, 0x00,
+       48, 0x00,       49, 0x00,       50, 0x00,       51, 0x00,
+       52, 0x00,       53, 0x00,       54, 0x00,       55, 0x00,
+};
+#define MODE8420LEN    (sizeof(mode8420pro)/2)
+
+static __u8 mode8420con[] = {  /* consumer output mode */
+       32, 0x20,       33, 0x00,       34, 0x00,       35, 0x48,
+       36, 0x00,       37, 0x00,       38, 0x00,       39, 0x00,
+       40, 0x00,       41, 0x00,       42, 0x00,       43, 0x00,
+       44, 0x00,       45, 0x00,       46, 0x00,       47, 0x00,
+       48, 0x00,       49, 0x00,       50, 0x00,       51, 0x00,
+       52, 0x00,       53, 0x00,       54, 0x00,       55, 0x00,
+};
+
+#endif
index bb75087df2347a882a57e41db9e26d39f9e27c1a..30df60f66090ce0731dd433f04c47e8458de61d1 100644 (file)
@@ -35,7 +35,6 @@
 # include "xf86.h"
 # include "xf86drm.h"
 # include "xf86_OSlib.h"
-# include "xf86drm.h"
 #else
 # include <unistd.h>
 # include <signal.h>
diff --git a/drivers/char/ibmmpeg2.h b/drivers/char/ibmmpeg2.h
new file mode 100644 (file)
index 0000000..68e1038
--- /dev/null
@@ -0,0 +1,94 @@
+/* ibmmpeg2.h - IBM MPEGCD21 definitions */
+
+#ifndef __IBM_MPEG2__
+#define __IBM_MPEG2__
+
+/* Define all MPEG Decoder registers */
+/* Chip Control and Status */
+#define IBM_MP2_CHIP_CONTROL   0x200*2
+#define IBM_MP2_CHIP_MODE      0x201*2
+/* Timer Control and Status */
+#define IBM_MP2_SYNC_STC2      0x202*2
+#define IBM_MP2_SYNC_STC1      0x203*2
+#define IBM_MP2_SYNC_STC0      0x204*2
+#define IBM_MP2_SYNC_PTS2      0x205*2
+#define IBM_MP2_SYNC_PTS1      0x206*2
+#define IBM_MP2_SYNC_PTS0      0x207*2
+/* Video FIFO Control */
+#define IBM_MP2_FIFO           0x208*2
+#define IBM_MP2_FIFOW          0x100*2
+#define IBM_MP2_FIFO_STAT      0x209*2
+#define IBM_MP2_RB_THRESHOLD   0x22b*2
+/* Command buffer */
+#define IBM_MP2_COMMAND                0x20a*2
+#define IBM_MP2_CMD_DATA       0x20b*2
+#define IBM_MP2_CMD_STAT       0x20c*2
+#define IBM_MP2_CMD_ADDR       0x20d*2
+/* Internal Processor Control and Status */
+#define IBM_MP2_PROC_IADDR     0x20e*2
+#define IBM_MP2_PROC_IDATA     0x20f*2
+#define IBM_MP2_WR_PROT                0x235*2
+/* DRAM Access */
+#define IBM_MP2_DRAM_ADDR      0x210*2
+#define IBM_MP2_DRAM_DATA      0x212*2
+#define IBM_MP2_DRAM_CMD_STAT  0x213*2
+#define IBM_MP2_BLOCK_SIZE     0x23b*2
+#define IBM_MP2_SRC_ADDR       0x23c*2
+/* Onscreen Display */
+#define IBM_MP2_OSD_ADDR       0x214*2
+#define IBM_MP2_OSD_DATA       0x215*2
+#define IBM_MP2_OSD_MODE       0x217*2
+#define IBM_MP2_OSD_LINK_ADDR  0x229*2
+#define IBM_MP2_OSD_SIZE       0x22a*2
+/* Interrupt Control */
+#define IBM_MP2_HOST_INT       0x218*2
+#define IBM_MP2_MASK0          0x219*2
+#define IBM_MP2_HOST_INT1      0x23e*2
+#define IBM_MP2_MASK1          0x23f*2
+/* Audio Control */
+#define IBM_MP2_AUD_IADDR      0x21a*2
+#define IBM_MP2_AUD_IDATA      0x21b*2
+#define IBM_MP2_AUD_FIFO       0x21c*2
+#define IBM_MP2_AUD_FIFOW      0x101*2
+#define IBM_MP2_AUD_CTL                0x21d*2
+#define IBM_MP2_BEEP_CTL       0x21e*2
+#define IBM_MP2_FRNT_ATTEN     0x22d*2
+/* Display Control */
+#define IBM_MP2_DISP_MODE      0x220*2
+#define IBM_MP2_DISP_DLY       0x221*2
+#define IBM_MP2_VBI_CTL                0x222*2
+#define IBM_MP2_DISP_LBOR      0x223*2
+#define IBM_MP2_DISP_TBOR      0x224*2
+/* Polarity Control */
+#define IBM_MP2_INFC_CTL       0x22c*2
+
+/* control commands */
+#define IBM_MP2_PLAY           0
+#define IBM_MP2_PAUSE          1
+#define IBM_MP2_SINGLE_FRAME   2
+#define IBM_MP2_FAST_FORWARD   3
+#define IBM_MP2_SLOW_MOTION    4
+#define IBM_MP2_IMED_NORM_PLAY 5
+#define IBM_MP2_RESET_WINDOW   6
+#define IBM_MP2_FREEZE_FRAME   7
+#define IBM_MP2_RESET_VID_RATE 8
+#define IBM_MP2_CONFIG_DECODER 9
+#define IBM_MP2_CHANNEL_SWITCH 10
+#define IBM_MP2_RESET_AUD_RATE 11
+#define IBM_MP2_PRE_OP_CHN_SW  12
+#define IBM_MP2_SET_STILL_MODE 14
+
+/* Define Xilinx FPGA Internal Registers */
+
+/* general control register 0 */
+#define XILINX_CTL0            0x600
+/* genlock delay resister 1 */
+#define XILINX_GLDELAY         0x602
+/* send 16 bits to CS3310 port */
+#define XILINX_CS3310          0x604
+/* send 16 bits to CS3310 and complete */
+#define XILINX_CS3310_CMPLT    0x60c
+/* pulse width modulator control */
+#define XILINX_PWM             0x606
+
+#endif
index 991e7b510ec14ac4379c0a4ac929dfc8e33e9500..995f817eb7111f5f4efac075f5612a08cea94e7f 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/init.h>
-#include <linux/module.h>
 
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
index dd53a44b504cb02c1d63d0aa31b0187d9b8ec651..71fe66f5c268cbc2b179feb2eda80e0d24db612e 100644 (file)
@@ -56,6 +56,9 @@ extern void adbdev_init(void);
 #ifdef CONFIG_USB
 extern void usb_init(void);
 #endif
+#ifdef CONFIG_PPDEV
+extern int pp_init(void);
+#endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
                            const char * buf, size_t count, loff_t *ppos)
@@ -672,6 +675,9 @@ int __init chr_dev_init(void)
 #endif
 #ifdef CONFIG_VIDEO_DEV
        videodev_init();
+#endif
+#ifdef CONFIG_PPDEV
+       pp_init();
 #endif
        return 0;
 }
index 0717fa4182641a4e624a9975d43e0b91e967b6b4..b4f50243e90ebde1b4259261122f9b84d55cd47b 100644 (file)
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 #include <asm/system.h>
index c96570b73d2d654d5d17f0d67af06535344c96dc..1e50880a071350304fd5bc1456825fbe827e7c67 100644 (file)
@@ -624,7 +624,7 @@ static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
 {
        int y;
        int dw = 2*dev->width;
-       char *src = (char *)bus_to_virt(mem_base);
+       u32 src = mem_base;
 
        char tmp[dw+32]; /* using a temp buffer is faster than direct  */
        int cnt = 0;
@@ -639,8 +639,14 @@ static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
   
        for (y = 0; y < dev->height; y++ ) 
        {
-               *src = 0;  /* synchronisiert neue Zeile */
-               memcpy(tmp, src, dw+32); /* discard 16 word   */
+               isa_writeb(0, src);  /* synchronisiert neue Zeile */
+               
+               /*
+                *      This is in truth a fifo, be very careful as if you
+                *      forgot this odd things will occur 8)
+                */
+                
+               isa_memcpy_fromio(tmp, src, dw+32); /* discard 16 word   */
                cnt -= dev->height;
                while (cnt <= 0) 
                { 
diff --git a/drivers/char/saa7121.h b/drivers/char/saa7121.h
new file mode 100644 (file)
index 0000000..74e37d4
--- /dev/null
@@ -0,0 +1,132 @@
+/* saa7121.h - saa7121 initializations
+   Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+#ifndef __SAA7121_H__
+#define __SAA7121_H__
+
+#define NTSC_BURST_START       0x19    /* 28 */
+#define NTSC_BURST_END         0x1d    /* 29 */
+#define NTSC_CHROMA_PHASE      0x67    /* 5a */
+#define NTSC_GAINU             0x76    /* 5b */
+#define NTSC_GAINV             0xa5    /* 5c */
+#define NTSC_BLACK_LEVEL       0x2a    /* 5d */
+#define NTSC_BLANKING_LEVEL    0x2e    /* 5e */
+#define NTSC_VBI_BLANKING      0x2e    /* 5f */
+#define NTSC_DAC_CONTROL       0x11    /* 61 */
+#define NTSC_BURST_AMP         0x3f    /* 62 */
+#define NTSC_SUBC3             0x1f    /* 63 */
+#define NTSC_SUBC2             0x7c    /* 64 */
+#define NTSC_SUBC1             0xf0    /* 65 */
+#define NTSC_SUBC0             0x21    /* 66 */
+#define NTSC_HTRIG             0x72    /* 6c */
+#define NTSC_VTRIG             0x00    /* 6c */
+#define NTSC_MULTI             0x30    /* 6e */
+#define NTSC_CCTTX             0x11    /* 6f */
+#define NTSC_FIRST_ACTIVE      0x12    /* 7a */
+#define NTSC_LAST_ACTIVE       0x02    /* 7b */
+#define NTSC_MSB_VERTICAL      0x40    /* 7c */
+
+#define PAL_BURST_START                0x21    /* 28 */
+#define PAL_BURST_END          0x1d    /* 29 */
+#define PAL_CHROMA_PHASE       0x3f    /* 5a */
+#define PAL_GAINU              0x7d    /* 5b */
+#define PAL_GAINV              0xaf    /* 5c */
+#define PAL_BLACK_LEVEL                0x23    /* 5d */
+#define PAL_BLANKING_LEVEL     0x35    /* 5e */
+#define PAL_VBI_BLANKING       0x35    /* 5f */
+#define PAL_DAC_CONTROL                0x02    /* 61 */
+#define PAL_BURST_AMP          0x2f    /* 62 */
+#define PAL_SUBC3              0xcb    /* 63 */
+#define PAL_SUBC2              0x8a    /* 64 */
+#define PAL_SUBC1              0x09    /* 65 */
+#define PAL_SUBC0              0x2a    /* 66 */
+#define PAL_HTRIG              0x86    /* 6c */
+#define PAL_VTRIG              0x04    /* 6d */
+#define PAL_MULTI              0x20    /* 6e */
+#define PAL_CCTTX              0x15    /* 6f */
+#define PAL_FIRST_ACTIVE       0x16    /* 7a */
+#define PAL_LAST_ACTIVE                0x36    /* 7b */
+#define PAL_MSB_VERTICAL       0x40    /* 7c */
+
+/* Initialization Sequence */
+        
+static __u8 init7121ntsc[] = {
+       0x26, 0x0,      0x27, 0x0,
+       0x28, NTSC_BURST_START,         0x29, NTSC_BURST_END,
+       0x2a, 0x0,      0x2b, 0x0,      0x2c, 0x0,      0x2d, 0x0,
+       0x2e, 0x0,      0x2f, 0x0,      0x30, 0x0,      0x31, 0x0,
+       0x32, 0x0,      0x33, 0x0,      0x34, 0x0,      0x35, 0x0,
+       0x36, 0x0,      0x37, 0x0,      0x38, 0x0,      0x39, 0x0,
+       0x3a, 0x03,     0x3b, 0x0,      0x3c, 0x0,      0x3d, 0x0,
+       0x3e, 0x0,      0x3f, 0x0,      0x40, 0x0,      0x41, 0x0,
+       0x42, 0x0,      0x43, 0x0,      0x44, 0x0,      0x45, 0x0,
+       0x46, 0x0,      0x47, 0x0,      0x48, 0x0,      0x49, 0x0,
+       0x4a, 0x0,      0x4b, 0x0,      0x4c, 0x0,      0x4d, 0x0,
+       0x4e, 0x0,      0x4f, 0x0,      0x50, 0x0,      0x51, 0x0,
+       0x52, 0x0,      0x53, 0x0,      0x54, 0x0,      0x55, 0x0,
+       0x56, 0x0,      0x57, 0x0,      0x58, 0x0,      0x59, 0x0,
+       0x5a, NTSC_CHROMA_PHASE,        0x5b, NTSC_GAINU,
+       0x5c, NTSC_GAINV,               0x5d, NTSC_BLACK_LEVEL,
+       0x5e, NTSC_BLANKING_LEVEL,      0x5f, NTSC_VBI_BLANKING,
+       0x60, 0x0,                      0x61, NTSC_DAC_CONTROL,
+       0x62, NTSC_BURST_AMP,           0x63, NTSC_SUBC3,
+       0x64, NTSC_SUBC2,               0x65, NTSC_SUBC1,
+       0x66, NTSC_SUBC0,               0x67, 0x80,     0x68, 0x80,
+       0x69, 0x80,     0x6a, 0x80,     0x6b, 0x29,
+       0x6c, NTSC_HTRIG,               0x6d, NTSC_VTRIG,
+       0x6e, NTSC_MULTI,               0x6f, NTSC_CCTTX,
+       0x70, 0xc9,     0x71, 0x68,     0x72, 0x60,     0x73, 0x0,
+       0x74, 0x0,      0x75, 0x0,      0x76, 0x0,      0x77, 0x0,
+       0x78, 0x0,      0x79, 0x0,      0x7a, NTSC_FIRST_ACTIVE,
+       0x7b, NTSC_LAST_ACTIVE,         0x7c, NTSC_MSB_VERTICAL,
+       0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
+}; 
+#define INIT7121LEN    (sizeof(init7121ntsc)/2)
+
+static __u8 init7121pal[] = {
+       0x26, 0x0,      0x27, 0x0,
+       0x28, PAL_BURST_START,          0x29, PAL_BURST_END,
+       0x2a, 0x0,      0x2b, 0x0,      0x2c, 0x0,      0x2d, 0x0,
+       0x2e, 0x0,      0x2f, 0x0,      0x30, 0x0,      0x31, 0x0,
+       0x32, 0x0,      0x33, 0x0,      0x34, 0x0,      0x35, 0x0,
+       0x36, 0x0,      0x37, 0x0,      0x38, 0x0,      0x39, 0x0,
+       0x3a, 0x03,     0x3b, 0x0,      0x3c, 0x0,      0x3d, 0x0,
+       0x3e, 0x0,      0x3f, 0x0,      0x40, 0x0,      0x41, 0x0,
+       0x42, 0x0,      0x43, 0x0,      0x44, 0x0,      0x45, 0x0,
+       0x46, 0x0,      0x47, 0x0,      0x48, 0x0,      0x49, 0x0,
+       0x4a, 0x0,      0x4b, 0x0,      0x4c, 0x0,      0x4d, 0x0,
+       0x4e, 0x0,      0x4f, 0x0,      0x50, 0x0,      0x51, 0x0,
+       0x52, 0x0,      0x53, 0x0,      0x54, 0x0,      0x55, 0x0,
+       0x56, 0x0,      0x57, 0x0,      0x58, 0x0,      0x59, 0x0,
+       0x5a, PAL_CHROMA_PHASE,         0x5b, PAL_GAINU,
+       0x5c, PAL_GAINV,                0x5d, PAL_BLACK_LEVEL,
+       0x5e, PAL_BLANKING_LEVEL,       0x5f, PAL_VBI_BLANKING,
+       0x60, 0x0,                      0x61, PAL_DAC_CONTROL,
+       0x62, PAL_BURST_AMP,            0x63, PAL_SUBC3,
+       0x64, PAL_SUBC2,                0x65, PAL_SUBC1,
+       0x66, PAL_SUBC0,                0x67, 0x80,     0x68, 0x80,
+       0x69, 0x80,     0x6a, 0x80,     0x6b, 0x29,
+       0x6c, PAL_HTRIG,                0x6d, PAL_VTRIG,
+       0x6e, PAL_MULTI,                0x6f, PAL_CCTTX,
+       0x70, 0xc9,     0x71, 0x68,     0x72, 0x60,     0x73, 0x0,
+       0x74, 0x0,      0x75, 0x0,      0x76, 0x0,      0x77, 0x0,
+       0x78, 0x0,      0x79, 0x0,      0x7a, PAL_FIRST_ACTIVE,
+       0x7b, PAL_LAST_ACTIVE,          0x7c, PAL_MSB_VERTICAL,
+       0x7d, 0x0,      0x7e, 0x0,      0x7f, 0x0
+}; 
+#endif
diff --git a/drivers/char/saa7146.h b/drivers/char/saa7146.h
new file mode 100644 (file)
index 0000000..481308e
--- /dev/null
@@ -0,0 +1,117 @@
+/*  
+    saa7146.h - definitions philips saa7146 based cards
+    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __SAA7146__
+#define __SAA7146__
+
+#define SAA7146_VERSION_CODE 0x000101
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+
+#ifndef O_NONCAP  
+#define O_NONCAP       O_TRUNC
+#endif
+
+#define MAX_GBUFFERS   2
+#define FBUF_SIZE      0x190000
+
+#ifdef __KERNEL__
+
+struct saa7146_window 
+{
+       int x, y;
+       ushort width, height;
+       ushort bpp, bpl;
+       ushort swidth, sheight;
+       short cropx, cropy;
+       ushort cropwidth, cropheight;
+       unsigned long vidadr;
+       int color_fmt;
+       ushort depth;
+};
+
+/*  Per-open data for handling multiple opens on one device */
+struct device_open
+{
+       int          isopen;
+       int          noncapturing;
+       struct saa7146  *dev;
+};
+#define MAX_OPENS 3
+
+struct saa7146
+{
+       struct video_device video_dev;
+       struct video_picture picture;
+       struct video_audio audio_dev;
+       struct video_info vidinfo;
+       int user;
+       int cap;
+       int capuser;
+       int irqstate;           /* irq routine is state driven */
+       int writemode;
+       int playmode;
+        unsigned int nr;
+       unsigned long irq;          /* IRQ used by SAA7146 card */
+       unsigned short id;
+       struct i2c_bus i2c;
+       struct pci_dev *dev;
+       unsigned char revision;
+       unsigned char boardcfg[64];     /* 64 bytes of config from eeprom */
+       unsigned long saa7146_adr;   /* bus address of IO mem from PCI BIOS */
+       struct saa7146_window win;
+       unsigned char *saa7146_mem; /* pointer to mapped IO memory */
+       struct device_open open_data[MAX_OPENS];
+#define MAX_MARKS 16
+       /* for a/v sync */
+       int endmark[MAX_MARKS], endmarkhead, endmarktail;
+       u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2,
+               *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out,
+               *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in,
+               *pagea1out, *pagea2in, *pagea2out;
+       wait_queue_head_t i2cq, debiq, audq, vidq;
+       u8  *vidbuf, *audbuf, *osdbuf, *dmadebi;
+       int audhead, vidhead, osdhead, audtail, vidtail, osdtail;
+       spinlock_t lock;        /* the device lock */
+};
+#endif
+
+#ifdef _ALPHA_SAA7146
+#define saawrite(dat,adr)    writel((dat),(char *) (saa->saa7146_adr+(adr)))
+#define saaread(adr)         readl(saa->saa7146_adr+(adr))
+#else
+#define saawrite(dat,adr)    writel((dat), (char *) (saa->saa7146_mem+(adr)))
+#define saaread(adr)         readl(saa->saa7146_mem+(adr))
+#endif
+
+#define saaand(dat,adr)      saawrite((dat) & saaread(adr), adr)
+#define saaor(dat,adr)       saawrite((dat) | saaread(adr), adr)
+#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr)
+
+/* bitmask of attached hardware found */
+#define SAA7146_UNKNOWN                0x00000000
+#define SAA7146_SAA7111                0x00000001
+#define SAA7146_SAA7121                0x00000002
+#define SAA7146_IBMMPEG                0x00000004
+
+#endif
diff --git a/drivers/char/saa7146reg.h b/drivers/char/saa7146reg.h
new file mode 100644 (file)
index 0000000..6cc910f
--- /dev/null
@@ -0,0 +1,283 @@
+/*  
+    saa7146.h - definitions philips saa7146 based cards
+    Copyright (C) 1999 Nathan Laredo (laredo@gnu.org)
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __SAA7146_REG__
+#define __SAA7146_REG__
+#define SAA7146_BASE_ODD1      0x00
+#define SAA7146_BASE_EVEN1     0x04
+#define SAA7146_PROT_ADDR1     0x08
+#define SAA7146_PITCH1         0x0c
+#define SAA7146_PAGE1          0x10
+#define SAA7146_NUM_LINE_BYTE1 0x14
+#define SAA7146_BASE_ODD2      0x18
+#define SAA7146_BASE_EVEN2     0x1c
+#define SAA7146_PROT_ADDR2     0x20
+#define SAA7146_PITCH2         0x24
+#define SAA7146_PAGE2          0x28
+#define SAA7146_NUM_LINE_BYTE2 0x2c
+#define SAA7146_BASE_ODD3      0x30
+#define SAA7146_BASE_EVEN3     0x34
+#define SAA7146_PROT_ADDR3     0x38
+#define SAA7146_PITCH3         0x3c
+#define SAA7146_PAGE3          0x40
+#define SAA7146_NUM_LINE_BYTE3 0x44
+#define SAA7146_PCI_BT_V1      0x48
+#define SAA7146_PCI_BT_V2      0x49
+#define SAA7146_PCI_BT_V3      0x4a
+#define SAA7146_PCI_BT_DEBI    0x4b
+#define SAA7146_PCI_BT_A       0x4c
+#define SAA7146_DD1_INIT       0x50
+#define SAA7146_DD1_STREAM_B   0x54
+#define SAA7146_DD1_STREAM_A   0x56
+#define SAA7146_BRS_CTRL       0x58
+#define SAA7146_HPS_CTRL       0x5c
+#define SAA7146_HPS_V_SCALE    0x60
+#define SAA7146_HPS_V_GAIN     0x64
+#define SAA7146_HPS_H_PRESCALE 0x68
+#define SAA7146_HPS_H_SCALE    0x6c
+#define SAA7146_BCS_CTRL       0x70
+#define SAA7146_CHROMA_KEY_RANGE       0x74
+#define SAA7146_CLIP_FORMAT_CTRL       0x78
+#define SAA7146_DEBI_CONFIG    0x7c
+#define SAA7146_DEBI_COMMAND   0x80
+#define SAA7146_DEBI_PAGE      0x84
+#define SAA7146_DEBI_AD                0x88
+#define SAA7146_I2C_TRANSFER   0x8c
+#define SAA7146_I2C_STATUS     0x90
+#define SAA7146_BASE_A1_IN     0x94
+#define SAA7146_PROT_A1_IN     0x98
+#define SAA7146_PAGE_A1_IN     0x9C
+#define SAA7146_BASE_A1_OUT    0xa0
+#define SAA7146_PROT_A1_OUT    0xa4
+#define SAA7146_PAGE_A1_OUT    0xa8
+#define SAA7146_BASE_A2_IN     0xac
+#define SAA7146_PROT_A2_IN     0xb0
+#define SAA7146_PAGE_A2_IN     0xb4
+#define SAA7146_BASE_A2_OUT    0xb8
+#define SAA7146_PROT_A2_OUT    0xbc
+#define SAA7146_PAGE_A2_OUT    0xc0
+#define SAA7146_RPS_PAGE0      0xc4
+#define SAA7146_RPS_PAGE1      0xc8
+#define SAA7146_RPS_THRESH0    0xcc
+#define SAA7146_RPS_THRESH1    0xd0
+#define SAA7146_RPS_TOV0       0xd4
+#define SAA7146_RPS_TOV1       0xd8
+#define SAA7146_IER            0xdc
+#define SAA7146_GPIO_CTRL      0xe0
+#define SAA7146_EC1SSR         0xe4
+#define SAA7146_EC2SSR         0xe8
+#define SAA7146_ECT1R          0xec
+#define SAA7146_ECT2R          0xf0
+#define SAA7146_ACON1          0xf4
+#define SAA7146_ACON2          0xf8
+#define SAA7146_MC1            0xfc
+#define SAA7146_MC2            0x100
+#define SAA7146_RPS_ADDR0      0x104
+#define SAA7146_RPS_ADDR1      0x108
+#define SAA7146_ISR            0x10c
+#define SAA7146_PSR            0x110
+#define SAA7146_SSR            0x114
+#define SAA7146_EC1R           0x118
+#define SAA7146_EC2R           0x11c
+#define SAA7146_VDP1           0x120
+#define SAA7146_VDP2           0x124
+#define SAA7146_VDP3           0x128
+#define SAA7146_ADP1           0x12c
+#define SAA7146_ADP2           0x130
+#define SAA7146_ADP3           0x134
+#define SAA7146_ADP4           0x138
+#define SAA7146_DDP            0x13c
+#define SAA7146_LEVEL_REP      0x140
+#define SAA7146_FB_BUFFER1     0x144
+#define SAA7146_FB_BUFFER2     0x148
+#define SAA7146_A_TIME_SLOT1   0x180
+#define SAA7146_A_TIME_SLOT2   0x1C0
+
+/* bitfield defines */
+#define MASK_31                        0x80000000
+#define MASK_30                        0x40000000
+#define MASK_29                        0x20000000
+#define MASK_28                        0x10000000
+#define MASK_27                        0x08000000
+#define MASK_26                        0x04000000
+#define MASK_25                        0x02000000
+#define MASK_24                        0x01000000
+#define MASK_23                        0x00800000
+#define MASK_22                        0x00400000
+#define MASK_21                        0x00200000
+#define MASK_20                        0x00100000
+#define MASK_19                        0x00080000
+#define MASK_18                        0x00040000
+#define MASK_17                        0x00020000
+#define MASK_16                        0x00010000
+#define MASK_15                        0x00008000
+#define MASK_14                        0x00004000
+#define MASK_13                        0x00002000
+#define MASK_12                        0x00001000
+#define MASK_11                        0x00000800
+#define MASK_10                        0x00000400
+#define MASK_09                        0x00000200
+#define MASK_08                        0x00000100
+#define MASK_07                        0x00000080
+#define MASK_06                        0x00000040
+#define MASK_05                        0x00000020
+#define MASK_04                        0x00000010
+#define MASK_03                        0x00000008
+#define MASK_02                        0x00000004
+#define MASK_01                        0x00000002
+#define MASK_00                        0x00000001
+#define MASK_B0                        0x000000ff
+#define MASK_B1                        0x0000ff00
+#define MASK_B2                        0x00ff0000
+#define MASK_B3                        0xff000000
+#define MASK_W0                        0x0000ffff
+#define MASK_W1                        0xffff0000
+#define MASK_PA                        0xfffffffc
+#define MASK_PR                        0xfffffffe
+#define MASK_ER                        0xffffffff
+#define MASK_NONE              0x00000000
+
+#define SAA7146_PAGE_MAP_EN    MASK_11
+/* main control register 1 */
+#define SAA7146_MC1_MRST_N     MASK_15
+#define SAA7146_MC1_ERPS1      MASK_13
+#define SAA7146_MC1_ERPS0      MASK_12
+#define SAA7146_MC1_EDP                MASK_11
+#define SAA7146_MC1_EVP                MASK_10
+#define SAA7146_MC1_EAP                MASK_09
+#define SAA7146_MC1_EI2C       MASK_08
+#define SAA7146_MC1_TR_E_DEBI  MASK_07
+#define SAA7146_MC1_TR_E_1     MASK_06
+#define SAA7146_MC1_TR_E_2     MASK_05
+#define SAA7146_MC1_TR_E_3     MASK_04
+#define SAA7146_MC1_TR_E_A2_OUT        MASK_03
+#define SAA7146_MC1_TR_E_A2_IN MASK_02
+#define SAA7146_MC1_TR_E_A1_OUT        MASK_01
+#define SAA7146_MC1_TR_E_A1_IN MASK_00
+/* main control register 2 */
+#define SAA7146_MC2_RPS_SIG4   MASK_15
+#define SAA7146_MC2_RPS_SIG3   MASK_14
+#define SAA7146_MC2_RPS_SIG2   MASK_13
+#define SAA7146_MC2_RPS_SIG1   MASK_12
+#define SAA7146_MC2_RPS_SIG0   MASK_11
+#define SAA7146_MC2_UPLD_D1_B  MASK_10
+#define SAA7146_MC2_UPLD_D1_A  MASK_09
+#define SAA7146_MC2_UPLD_BRS   MASK_08
+#define SAA7146_MC2_UPLD_HPS_H MASK_06
+#define SAA7146_MC2_UPLD_HPS_V MASK_05
+#define SAA7146_MC2_UPLD_DMA3  MASK_04
+#define SAA7146_MC2_UPLD_DMA2  MASK_03
+#define SAA7146_MC2_UPLD_DMA1  MASK_02
+#define SAA7146_MC2_UPLD_DEBI  MASK_01
+#define SAA7146_MC2_UPLD_I2C   MASK_00
+/* Primary Status Register and Interrupt Enable/Status Registers */
+#define SAA7146_PSR_PPEF       MASK_31
+#define SAA7146_PSR_PABO       MASK_30
+#define SAA7146_PSR_PPED       MASK_29
+#define SAA7146_PSR_RPS_I1     MASK_28
+#define SAA7146_PSR_RPS_I0     MASK_27
+#define SAA7146_PSR_RPS_LATE1  MASK_26
+#define SAA7146_PSR_RPS_LATE0  MASK_25
+#define SAA7146_PSR_RPS_E1     MASK_24
+#define SAA7146_PSR_RPS_E0     MASK_23
+#define SAA7146_PSR_RPS_TO1    MASK_22
+#define SAA7146_PSR_RPS_TO0    MASK_21
+#define SAA7146_PSR_UPLD       MASK_20
+#define SAA7146_PSR_DEBI_S     MASK_19
+#define SAA7146_PSR_DEBI_E     MASK_18
+#define SAA7146_PSR_I2C_S      MASK_17
+#define SAA7146_PSR_I2C_E      MASK_16
+#define SAA7146_PSR_A2_IN      MASK_15
+#define SAA7146_PSR_A2_OUT     MASK_14
+#define SAA7146_PSR_A1_IN      MASK_13
+#define SAA7146_PSR_A1_OUT     MASK_12
+#define SAA7146_PSR_AFOU       MASK_11
+#define SAA7146_PSR_V_PE       MASK_10
+#define SAA7146_PSR_VFOU       MASK_09
+#define SAA7146_PSR_FIDA       MASK_08
+#define SAA7146_PSR_FIDB       MASK_07
+#define SAA7146_PSR_PIN3       MASK_06
+#define SAA7146_PSR_PIN2       MASK_05
+#define SAA7146_PSR_PIN1       MASK_04
+#define SAA7146_PSR_PIN0       MASK_03
+#define SAA7146_PSR_ECS                MASK_02
+#define SAA7146_PSR_EC3S       MASK_01
+#define SAA7146_PSR_EC0S       MASK_00
+/* Secondary Status Register */
+#define SAA7146_SSR_PRQ                MASK_31
+#define SAA7146_SSR_PMA                MASK_30
+#define SAA7146_SSR_RPS_RE1    MASK_29
+#define SAA7146_SSR_RPS_PE1    MASK_28
+#define SAA7146_SSR_RPS_A1     MASK_27
+#define SAA7146_SSR_RPS_RE0    MASK_26
+#define SAA7146_SSR_RPS_PE0    MASK_25
+#define SAA7146_SSR_RPS_A0     MASK_24
+#define SAA7146_SSR_DEBI_TO    MASK_23
+#define SAA7146_SSR_DEBI_EF    MASK_22
+#define SAA7146_SSR_I2C_EA     MASK_21
+#define SAA7146_SSR_I2C_EW     MASK_20
+#define SAA7146_SSR_I2C_ER     MASK_19
+#define SAA7146_SSR_I2C_EL     MASK_18
+#define SAA7146_SSR_I2C_EF     MASK_17
+#define SAA7146_SSR_V3P                MASK_16
+#define SAA7146_SSR_V2P                MASK_15
+#define SAA7146_SSR_V1P                MASK_14
+#define SAA7146_SSR_VF3                MASK_13
+#define SAA7146_SSR_VF2                MASK_12
+#define SAA7146_SSR_VF1                MASK_11
+#define SAA7146_SSR_AF2_IN     MASK_10
+#define SAA7146_SSR_AF2_OUT    MASK_09
+#define SAA7146_SSR_AF1_IN     MASK_08
+#define SAA7146_SSR_AF1_OUT    MASK_07
+#define SAA7146_SSR_VGT                MASK_05
+#define SAA7146_SSR_LNQG       MASK_04
+#define SAA7146_SSR_EC5S       MASK_03
+#define SAA7146_SSR_EC4S       MASK_02
+#define SAA7146_SSR_EC2S       MASK_01
+#define SAA7146_SSR_EC1S       MASK_00
+/* I2C status register */
+#define SAA7146_I2C_ABORT      MASK_07
+#define SAA7146_I2C_SPERR      MASK_06
+#define SAA7146_I2C_APERR      MASK_05
+#define SAA7146_I2C_DTERR      MASK_04
+#define SAA7146_I2C_DRERR      MASK_03
+#define SAA7146_I2C_AL         MASK_02
+#define SAA7146_I2C_ERR                MASK_01
+#define SAA7146_I2C_BUSY       MASK_00
+/* output formats */
+#define SAA7146_YUV422 0
+#define SAA7146_RGB16  0
+#define SAA7146_YUV444 1
+#define SAA7146_RGB24  1
+#define SAA7146_ARGB32 2
+#define SAA7146_YUV411 3
+#define SAA7146_ARGB15  3
+#define SAA7146_YUV2   4
+#define SAA7146_RGAB15 4
+#define SAA7146_Y8     6
+#define SAA7146_YUV8   7
+#define SAA7146_RGB8   7
+#define SAA7146_YUV444p        8
+#define SAA7146_YUV422p        9
+#define SAA7146_YUV420p        10
+#define SAA7146_YUV1620        11
+#define SAA7146_Y1     13
+#define SAA7146_Y2     14
+#define SAA7146_YUV1   15
+#endif
diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c
new file mode 100644 (file)
index 0000000..d0675a0
--- /dev/null
@@ -0,0 +1,2287 @@
+/* 
+ * stradis.c - stradis 4:2:2 mpeg decoder driver
+ *
+ * Stradis 4:2:2 MPEG-2 Decoder Driver
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+
+#include "saa7146.h"
+#include "saa7146reg.h"
+#include "ibmmpeg2.h"
+#include "saa7121.h"
+#include "cs8420.h"
+
+#define DEBUG(x)               /* debug driver */
+#undef  IDEBUG(x)              /* debug irq handler */
+#undef  MDEBUG(x)              /* debug memory management */
+
+#define SAA7146_MAX 6
+
+static struct saa7146 saa7146s[SAA7146_MAX];
+
+static int saa_num = 0;                /* number of SAA7146s in use */
+
+#define nDebNormal     0x00480000
+#define nDebNoInc      0x00480000
+#define nDebVideo      0xd0480000
+#define nDebAudio      0xd0400000
+#define nDebDMA                0x02c80000
+
+#define oDebNormal     0x13c80000
+#define oDebNoInc      0x13c80000
+#define oDebVideo      0xd1080000
+#define oDebAudio      0xd1080000
+#define oDebDMA                0x03080000
+
+#define NewCard                (saa->boardcfg[3])
+#define ChipControl    (saa->boardcfg[1])
+#define NTSCFirstActive        (saa->boardcfg[4])
+#define PALFirstActive (saa->boardcfg[5])
+#define NTSCLastActive (saa->boardcfg[54])
+#define PALLastActive  (saa->boardcfg[55])
+#define Have2MB                (saa->boardcfg[18] & 0x40)
+#define HaveCS8420     (saa->boardcfg[18] & 0x04)
+#define IBMMPEGCD20    (saa->boardcfg[18] & 0x20)
+#define HaveCS3310     (saa->boardcfg[18] & 0x01)
+#define CS3310MaxLvl   ((saa->boardcfg[30] << 8) | saa->boardcfg[31])
+#define HaveCS4341     (saa->boardcfg[40] == 2)
+#define SDIType                (saa->boardcfg[27])
+#define CurrentMode    (saa->boardcfg[2])
+
+#define debNormal      (NewCard ? nDebNormal : oDebNormal)
+#define debNoInc       (NewCard ? nDebNoInc : oDebNoInc)
+#define debVideo       (NewCard ? nDebVideo : oDebVideo)
+#define debAudio       (NewCard ? nDebAudio : oDebAudio)
+#define debDMA         (NewCard ? nDebDMA : oDebDMA)
+
+#ifdef DEBUG
+int stradis_driver(void)       /* for the benefit of ksymoops */
+{
+       return 1;
+}
+#endif
+
+#ifdef USE_RESCUE_EEPROM_SDM275
+static unsigned char rescue_eeprom[64] = {
+0x00,0x01,0x04,0x13,0x26,0x0f,0x10,0x00,0x00,0x00,0x43,0x63,0x22,0x01,0x29,0x15,0x73,0x00,0x1f, 'd', 'e', 'c', 'x', 'l', 'd', 'v', 'a',0x02,0x00,0x01,0x00,0xcc,0xa4,0x63,0x09,0xe2,0x10,0x00,0x0a,0x00,0x02,0x02, 'd', 'e', 'c', 'x', 'l', 'a',0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Hardware I2C functions */
+static void I2CWipe(struct saa7146 *saa)
+{
+       int i;
+       /* set i2c to ~=100kHz, abort transfer, clear busy */
+       saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+                SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+       /* wait for i2c registers to be programmed */
+       for (i = 0; i < 1000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+               schedule();
+       saawrite(0x600, SAA7146_I2C_STATUS);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+                SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+       /* wait for i2c registers to be programmed */
+       for (i = 0; i < 1000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+               schedule();
+       saawrite(0x600, SAA7146_I2C_STATUS);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+                SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+       /* wait for i2c registers to be programmed */
+       for (i = 0; i < 1000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+               schedule();
+}
+/* read I2C */
+static int I2CRead(struct i2c_bus *bus, unsigned char addr,
+                  unsigned char subaddr, int dosub)
+{
+       struct saa7146 *saa = (struct saa7146 *) bus->data;
+       int i;
+
+
+       if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+               I2CWipe(saa);
+       for (i = 0; i < 1000 &&
+            (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+               schedule();
+       if (i == 1000)
+               I2CWipe(saa);
+       if (dosub)
+               saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
+                 ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
+       else
+               saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
+                        0xf1, SAA7146_I2C_TRANSFER);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+                SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+       /* wait for i2c registers to be programmed */
+       for (i = 0; i < 1000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+               schedule();
+       /* wait for valid data */
+       for (i = 0; i < 1000 &&
+            (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+               schedule();
+       if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
+               return -1;
+       if (i == 1000) 
+               printk("i2c setup read timeout\n");
+       saawrite(0x41, SAA7146_I2C_TRANSFER);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+                SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+       /* wait for i2c registers to be programmed */
+       for (i = 0; i < 1000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+               schedule();
+       /* wait for valid data */
+       for (i = 0; i < 1000 &&
+            (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
+               schedule();
+       if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
+               return -1;
+       if (i == 1000) 
+               printk("i2c read timeout\n");
+       return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
+}
+static int I2CReadOld(struct i2c_bus *bus, unsigned char addr)
+{
+       return I2CRead(bus, addr, 0, 0);
+}
+
+/* set both to write both bytes, reset it to write only b1 */
+
+static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
+                   unsigned char b2, int both)
+{
+       struct saa7146 *saa = (struct saa7146 *) bus->data;
+       int i;
+       u32 data;
+
+       if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+               I2CWipe(saa);
+       for (i = 0; i < 1000 &&
+            (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+               schedule();
+       if (i == 1000)
+               I2CWipe(saa);
+       data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
+       if (both)
+               data |= ((b2 & 0xff) << 8) | 0xe5;
+       else
+               data |= 0xd1;
+       saawrite(data, SAA7146_I2C_TRANSFER);
+       saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
+                SAA7146_MC2);
+       return 0;
+}
+
+static void attach_inform(struct i2c_bus *bus, int id)
+{
+       struct saa7146 *saa = (struct saa7146 *) bus->data;
+       int i;
+
+       DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr, id));
+       if (id == 0xa0) { /* we have rev2 or later board, fill in info */
+               for (i = 0; i < 64; i++)
+                       saa->boardcfg[i] = I2CRead(bus, 0xa0, i, 1);
+#ifdef USE_RESCUE_EEPROM_SDM275
+               if (saa->boardcfg[0] != 0) {
+                       printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE BEEN IGNORED\n", saa->nr);
+                       for (i = 0; i < 64; i++)
+                               saa->boardcfg[i] = rescue_eeprom[i];
+               }
+#endif
+               printk("stradis%d: config =", saa->nr);
+               for (i = 0; i < 51; i++) {
+                       printk(" %02x",saa->boardcfg[i]);
+               }
+               printk("\n");
+       }
+}
+
+static void detach_inform(struct i2c_bus *bus, int id)
+{
+       struct saa7146 *saa = (struct saa7146 *) bus->data;
+       int i;
+       i = saa->nr;
+}
+
+static void I2CBusScan(struct i2c_bus *bus)
+{
+       int i;
+       for (i = 0; i < 0xff; i += 2)
+               if ((I2CRead(bus, i, 0, 0)) >= 0)
+                       attach_inform(bus, i);
+}
+
+static struct i2c_bus saa7146_i2c_bus_template =
+{
+       "saa7146",
+       I2C_BUSID_BT848,
+       NULL,
+       SPIN_LOCK_UNLOCKED,
+       attach_inform,
+       detach_inform,
+       NULL,
+       NULL,
+       I2CReadOld,
+       I2CWrite,
+};
+
+static int debiwait_maxwait = 0;
+
+static int wait_for_debi_done(struct saa7146 *saa)
+{
+       int i;
+
+       /* wait for registers to be programmed */
+       for (i = 0; i < 100000 &&
+            !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
+               saaread(SAA7146_MC2);
+       /* wait for transfer to complete */
+       for (i = 0; i < 500000 &&
+            (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
+               saaread(SAA7146_MC2);
+       if (i > debiwait_maxwait)
+               printk("wait-for-debi-done maxwait: %d\n",
+                       debiwait_maxwait = i);
+       
+       if (i == 500000)
+               return -1;
+       return 0;
+}
+
+static int debiwrite(struct saa7146 *saa, u32 config, int addr,
+                     u32 val, int count)
+{
+       u32 cmd;
+       if (count <= 0 || count > 32764)
+               return -1;
+       if (wait_for_debi_done(saa) < 0)
+               return -1;
+       saawrite(config, SAA7146_DEBI_CONFIG);
+       if (count <= 4)         /* immediate transfer */
+               saawrite(val, SAA7146_DEBI_AD);
+       else                    /* block transfer */
+               saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+       saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
+       saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+                SAA7146_MC2);
+       return 0;
+}
+
+static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
+{
+       u32 result = 0;
+
+       if (count > 32764 || count <= 0)
+               return 0;
+       if (wait_for_debi_done(saa) < 0)
+               return 0;
+       saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+       saawrite((count << 17) | 0x10000 | (addr & 0xffff),
+                SAA7146_DEBI_COMMAND);
+       saawrite(config, SAA7146_DEBI_CONFIG);
+       saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+                SAA7146_MC2);
+       if (count > 4)          /* not an immediate transfer */
+               return count;
+       wait_for_debi_done(saa);
+       result = saaread(SAA7146_DEBI_AD);
+       if (count == 1)
+               result &= 0xff;
+       if (count == 2)
+               result &= 0xffff;
+       if (count == 3)
+               result &= 0xffffff;
+       return result;
+}
+
+/* MUST be a multiple of 8 bytes and 8-byte aligned and < 32768 bytes */
+/* data copied into saa->dmadebi buffer, caller must re-enable interrupts */
+static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes)
+{
+       int i, j;
+       u32 *buf;
+       buf = (u32 *) saa->dmadebi;
+       if (bytes > 0x7000)
+               bytes = 0x7000;
+       saawrite(0, SAA7146_IER);       /* disable interrupts */
+       for (i=0; i < 10000 &&
+               (debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2)
+               & 0x8000); i++)
+               saaread(SAA7146_MC2);
+       if (i == 10000)
+               printk(KERN_ERR "stradis%d: dram_busy never cleared\n",
+                       saa->nr);
+       debiwrite(saa, debNormal, IBM_MP2_SRC_ADDR, (address<<16) |
+               (address>>16), 4);
+       debiwrite(saa, debNormal, IBM_MP2_BLOCK_SIZE, bytes, 2);
+       debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 0x8a10, 2);
+       for (j = 0; j < bytes/4; j++) {
+               for (i = 0; i < 10000 &&
+                       (!(debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2)
+                       & 0x4000)); i++)
+                       saaread(SAA7146_MC2);
+               if (i == 10000)
+                       printk(KERN_ERR "stradis%d: dram_ready never set\n",
+                               saa->nr);
+               buf[j] = debiread(saa, debNormal, IBM_MP2_DRAM_DATA, 4);
+       }
+}
+
+static void do_irq_send_data(struct saa7146 *saa)
+{
+       int split, audbytes, vidbytes;
+
+       saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
+       /* if special feature mode in effect, disable audio sending */
+       if (saa->playmode != VID_PLAY_NORMAL)
+               saa->audtail = saa->audhead = 0;
+       if (saa->audhead <= saa->audtail)
+               audbytes = saa->audtail - saa->audhead;
+       else
+               audbytes = 65536 - (saa->audhead - saa->audtail);
+       if (saa->vidhead <= saa->vidtail)
+               vidbytes = saa->vidtail - saa->vidhead;
+       else
+               vidbytes = 524288 - (saa->vidhead - saa->vidtail);
+       if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
+               saawrite(0, SAA7146_IER);
+               return;
+       }
+       /* if at least 1 block audio waiting and audio fifo isn't full */
+       if (audbytes >= 2048 && (debiread(saa, debNormal,
+               IBM_MP2_AUD_FIFO, 2) & 0xff) < 60) {
+               if (saa->audhead > saa->audtail)
+                       split = 65536 - saa->audhead;
+               else
+                       split = 0;
+               audbytes = 2048;
+               if (split > 0 && split < 2048) {
+                       memcpy(saa->dmadebi, saa->audbuf + saa->audhead,
+                               split);
+                       saa->audhead = 0;
+                       audbytes -= split;
+               } else
+                       split = 0;
+               memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
+                       audbytes);
+               saa->audhead += audbytes;
+               saa->audhead &= 0xffff;
+               debiwrite(saa, debAudio, (NewCard? IBM_MP2_AUD_FIFO :
+                         IBM_MP2_AUD_FIFOW), 0, 2048);
+               wake_up_interruptible(&saa->audq);
+       /* if at least 1 block video waiting and video fifo isn't full */
+       } else if (vidbytes >= 30720 && (debiread(saa, debNormal,
+               IBM_MP2_FIFO, 2)) < 16384) {
+               if (saa->vidhead > saa->vidtail)
+                       split = 524288 - saa->vidhead;
+               else
+                       split = 0;
+               vidbytes = 30720;
+               if (split > 0 && split < 30720) {
+                       memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead,
+                               split);
+                       saa->vidhead = 0;
+                       vidbytes -= split;
+               } else
+                       split = 0;
+               memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
+                       vidbytes);
+               saa->vidhead += vidbytes;
+               saa->vidhead &= 0x7ffff;
+               debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
+                         IBM_MP2_FIFOW), 0, 30720);
+               wake_up_interruptible(&saa->vidq);
+       }
+       saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
+}
+
+static void send_osd_data(struct saa7146 *saa)
+{
+       int size = saa->osdtail - saa->osdhead;
+       if (size > 30720)
+               size = 30720;
+       /* ensure some multiple of 8 bytes is transferred */
+       size = 8 * ((size + 8)>>3);
+       if (size) {
+               debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
+                         (saa->osdhead>>3), 2);
+               memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
+               saa->osdhead += size;
+               /* block transfer of next 8 bytes to ~32k bytes */
+               debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
+       }
+       if (saa->osdhead >= saa->osdtail) {
+               saa->osdhead = saa->osdtail = 0;
+               debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+       }
+}
+
+static void saa7146_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev_id;
+       u32 stat, astat;
+       int count;
+
+       count = 0;
+       while (1) {
+               /* get/clear interrupt status bits */
+               stat = saaread(SAA7146_ISR);
+               astat = stat & saaread(SAA7146_IER);
+               if (!astat)
+                       return;
+               saawrite(astat, SAA7146_ISR);
+               if (astat & SAA7146_PSR_DEBI_S) {
+                       do_irq_send_data(saa);
+               }
+               if (astat & SAA7146_PSR_PIN1) {
+                       int istat;
+                       /* the following read will trigger DEBI_S */
+                       istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+                       if (istat & 1) {
+                               saawrite(0, SAA7146_IER);
+                               send_osd_data(saa);
+                               saawrite(SAA7146_PSR_DEBI_S |
+                                        SAA7146_PSR_PIN1, SAA7146_IER);
+                       }
+                       if (istat & 0x20) {     /* Video Start */
+                               saa->vidinfo.frame_count++;
+                       }
+                       if (istat & 0x400) {    /* Picture Start */
+                               /* update temporal reference */
+                       }
+                       if (istat & 0x200) {    /* Picture Resolution Change */
+                               /* read new resolution */
+                       }
+                       if (istat & 0x100) {    /* New User Data found */
+                               /* read new user data */
+                       }
+                       if (istat & 0x1000) {   /* new GOP/SMPTE */
+                               /* read new SMPTE */
+                       }
+                       if (istat & 0x8000) {   /* Sequence Start Code */
+                               /* reset frame counter, load sizes */
+                               saa->vidinfo.frame_count = 0;
+                               saa->vidinfo.h_size = 704;
+                               saa->vidinfo.v_size = 480;
+#if 0
+                               if (saa->endmarkhead != saa->endmarktail) {
+                                       saa->audhead = 
+                                               saa->endmark[saa->endmarkhead];
+                                       saa->endmarkhead++;
+                                       if (saa->endmarkhead >= MAX_MARKS)
+                                               saa->endmarkhead = 0;
+                               }
+#endif
+                       }
+                       if (istat & 0x4000) {   /* Sequence Error Code */
+                               if (saa->endmarkhead != saa->endmarktail) {
+                                       saa->audhead = 
+                                               saa->endmark[saa->endmarkhead];
+                                       saa->endmarkhead++;
+                                       if (saa->endmarkhead >= MAX_MARKS)
+                                               saa->endmarkhead = 0;
+                               }
+                       }
+               }
+#ifdef IDEBUG
+               if (astat & SAA7146_PSR_PPEF) {
+                       IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_PABO) {
+                       IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_PPED) {
+                       IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_I1) {
+                       IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_I0) {
+                       IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_LATE1) {
+                       IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_LATE0) {
+                       IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_E1) {
+                       IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_E0) {
+                       IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_TO1) {
+                       IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_RPS_TO0) {
+                       IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_UPLD) {
+                       IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_DEBI_E) {
+                       IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_I2C_S) {
+                       IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_I2C_E) {
+                       IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_A2_IN) {
+                       IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_A2_OUT) {
+                       IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_A1_IN) {
+                       IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_A1_OUT) {
+                       IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_AFOU) {
+                       IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_V_PE) {
+                       IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_VFOU) {
+                       IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_FIDA) {
+                       IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_FIDB) {
+                       IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_PIN3) {
+                       IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_PIN2) {
+                       IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_PIN0) {
+                       IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_ECS) {
+                       IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_EC3S) {
+                       IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
+               }
+               if (astat & SAA7146_PSR_EC0S) {
+                       IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
+               }
+#endif
+               count++;
+               if (count > 15)
+                       printk(KERN_WARNING "stradis%d: irq loop %d\n",
+                              saa->nr, count);
+               if (count > 20) {
+                       saawrite(0, SAA7146_IER);
+                       printk(KERN_ERR
+                              "stradis%d: IRQ loop cleared\n", saa->nr);
+               }
+       }
+}
+
+static int ibm_send_command(struct saa7146 *saa,
+                           int command, int data, int chain)
+{
+       int i;
+
+       if (chain)
+               debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1) | 1, 2);
+       else
+               debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
+       debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
+       debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
+       for (i = 0; i < 100 &&
+            (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
+               schedule();
+       if (i == 100)
+               return -1;
+       return 0;
+}
+
+static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
+{
+       I2CWrite(&(saa->i2c), 0x22, 0x03,
+                left > 94 ? 94 : left, 2);
+       I2CWrite(&(saa->i2c), 0x22, 0x04,
+                right > 94 ? 94 : right, 2);
+}
+
+static void initialize_cs4341(struct saa7146 *saa)
+{
+       int i;
+       for (i = 0; i < 200; i++) {
+               /* auto mute off, power on, no de-emphasis */
+               /* I2S data up to 24-bit 64xFs internal SCLK */
+               I2CWrite(&(saa->i2c), 0x22, 0x01, 0x11, 2);
+               /* ATAPI mixer setings */
+               I2CWrite(&(saa->i2c), 0x22, 0x02, 0x49, 2);
+               /* attenuation left 3db */
+               I2CWrite(&(saa->i2c), 0x22, 0x03, 0x00, 2);
+               /* attenuation right 3db */
+               I2CWrite(&(saa->i2c), 0x22, 0x04, 0x00, 2);
+               I2CWrite(&(saa->i2c), 0x22, 0x01, 0x10, 2);
+               if (I2CRead(&(saa->i2c), 0x22, 0x02, 1) == 0x49)
+                       break;
+               schedule();
+       }
+       printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
+       return;
+}
+
+static void initialize_cs8420(struct saa7146 *saa, int pro)
+{
+       int i;
+       u8 *sequence;
+       if (pro)
+               sequence = mode8420pro;
+       else
+               sequence = mode8420con;
+       for (i = 0; i < INIT8420LEN; i++)
+               I2CWrite(&(saa->i2c), 0x20, init8420[i * 2],
+                        init8420[i * 2 + 1], 2);
+       for (i = 0; i < MODE8420LEN; i++)
+               I2CWrite(&(saa->i2c), 0x20, sequence[i * 2],
+                        sequence[i * 2 + 1], 2);
+       printk("stradis%d: CS8420 initialized\n", saa->nr);
+}
+
+static void initialize_saa7121(struct saa7146 *saa, int dopal)
+{
+       int i, mod;
+       u8 *sequence;
+       if (dopal)
+               sequence = init7121pal;
+       else
+               sequence = init7121ntsc;
+       mod = saaread(SAA7146_PSR) & 0x08;
+       /* initialize PAL/NTSC video encoder */
+       for (i = 0; i < INIT7121LEN; i++) {
+               if (NewCard) {  /* handle new card encoder differences */
+                       if (sequence[i*2] == 0x3a)
+                               I2CWrite(&(saa->i2c), 0x88, 0x3a, 0x13, 2);
+                       else if (sequence[i*2] == 0x6b)
+                               I2CWrite(&(saa->i2c), 0x88, 0x6b, 0x20, 2);
+                       else if (sequence[i*2] == 0x6c)
+                               I2CWrite(&(saa->i2c), 0x88, 0x6c,
+                                        dopal ? 0x09 : 0xf5, 2);
+                       else if (sequence[i*2] == 0x6d)
+                               I2CWrite(&(saa->i2c), 0x88, 0x6d,
+                                        dopal ? 0x20 : 0x00, 2);
+                       else if (sequence[i*2] == 0x7a)
+                               I2CWrite(&(saa->i2c), 0x88, 0x7a,
+                                        dopal ? (PALFirstActive - 1) :
+                                        (NTSCFirstActive - 4), 2);
+                       else if (sequence[i*2] == 0x7b)
+                               I2CWrite(&(saa->i2c), 0x88, 0x7b,
+                                        dopal ? PALLastActive :
+                                        NTSCLastActive, 2);
+                       else I2CWrite(&(saa->i2c), 0x88, sequence[i * 2],
+                                sequence[i * 2 + 1], 2);
+               } else {
+                       if (sequence[i*2] == 0x6b && mod)
+                               I2CWrite(&(saa->i2c), 0x88, 0x6b, 
+                                       (sequence[i * 2 + 1] ^ 0x09), 2);
+                       else if (sequence[i*2] == 0x7a)
+                               I2CWrite(&(saa->i2c), 0x88, 0x7a,
+                                        dopal ? (PALFirstActive - 1) :
+                                        (NTSCFirstActive - 4), 2);
+                       else if (sequence[i*2] == 0x7b)
+                               I2CWrite(&(saa->i2c), 0x88, 0x7b,
+                                        dopal ? PALLastActive :
+                                        NTSCLastActive, 2);
+                       else
+                               I2CWrite(&(saa->i2c), 0x88, sequence[i * 2],
+                                        sequence[i * 2 + 1], 2);
+               }
+       }
+}
+
+static void set_genlock_offset(struct saa7146 *saa, int noffset)
+{
+       int nCode;
+       int PixelsPerLine = 858;
+       if (CurrentMode == VIDEO_MODE_PAL)
+               PixelsPerLine = 864;
+       if (noffset > 500)
+               noffset = 500;
+       else if (noffset < -500)
+               noffset = -500;
+       nCode = noffset + 0x100;
+       if (nCode == 1)
+               nCode = 0x401;
+       else if (nCode < 1) nCode = 0x400 + PixelsPerLine + nCode;
+       debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
+}
+
+static void set_out_format(struct saa7146 *saa, int mode)
+{
+       initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
+       saa->boardcfg[2] = mode;
+       /* do not adjust analog video parameters here, use saa7121 init */
+       /* you will affect the SDI output on the new card */
+       if (mode == VIDEO_MODE_PAL) {           /* PAL */
+               debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
+               mdelay(50);
+               saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
+               if (NewCard) {
+                       debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+                                 0xe100, 2);
+                       mdelay(50);
+               }
+               debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+                         NewCard ? 0xe500: 0x6500, 2);
+               debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+                         (1 << 8) |
+                         (NewCard ? PALFirstActive : PALFirstActive-6), 2);
+       } else {                /* NTSC */
+               debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
+               mdelay(50);
+               saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
+               debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+                         NewCard ? 0xe100: 0x6100, 2);
+               debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+                         (1 << 8) |
+                         (NewCard ? NTSCFirstActive : NTSCFirstActive-6), 2);
+       }
+}
+
+
+/* Intialize bitmangler to map from a byte value to the mangled word that
+ * must be output to program the Xilinx part through the DEBI port.
+ * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
+ * transfer FPGA code, init IBM chip, transfer IBM microcode
+ * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
+ */
+static u16 bitmangler[256];
+
+static int initialize_fpga(struct video_code *bitdata)
+{
+       int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
+       u16 *dmabuf;
+       u8 *newdma;
+       struct saa7146 *saa;
+
+       /* verify fpga code */
+       for (startindex = 0; startindex < bitdata->datasize; startindex++)
+               if (bitdata->data[startindex] == 255)
+                       break;
+       if (startindex == bitdata->datasize) {
+               printk(KERN_INFO "stradis: bad fpga code\n");
+               return -1;
+       }
+       /* initialize all detected cards */
+       for (num = 0; num < saa_num; num++) {
+               saa = &saa7146s[num];
+               if (saa->boardcfg[0] > 20)
+                               continue;       /* card was programmed */
+               loadtwo = (saa->boardcfg[18] & 0x10);
+               if (!NewCard)   /* we have an old board */
+                       for (i = 0; i < 256; i++)
+                           bitmangler[i] = ((i & 0x01) << 15) |
+                               ((i & 0x02) << 6) | ((i & 0x04) << 4) |
+                               ((i & 0x08) << 9) | ((i & 0x10) << 7) |
+                               ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+                               ((i & 0x80) >> 7);
+               else    /* else we have a new board */
+                       for (i = 0; i < 256; i++)
+                           bitmangler[i] = ((i & 0x01) << 7) |
+                               ((i & 0x02) << 5) | ((i & 0x04) << 3) |
+                               ((i & 0x08) << 1) | ((i & 0x10) >> 1) |
+                               ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+                               ((i & 0x80) >> 7);
+
+               dmabuf = (u16 *) saa->dmadebi;
+               newdma = (u8 *) saa->dmadebi;
+               if (NewCard) {  /* SDM2xxx */
+                       if (!strncmp(bitdata->loadwhat, "decoder2", 8))
+                               continue;       /* fpga not for this card */
+                       if (!strncmp(&saa->boardcfg[42],
+                                    bitdata->loadwhat, 8)) {
+                               loadfile = 1;
+                       } else if (loadtwo && !strncmp(&saa->boardcfg[19],
+                                  bitdata->loadwhat, 8)) {
+                               loadfile = 2;
+                       } else if (!saa->boardcfg[42] &&        /* special */
+                                  !strncmp("decxl", bitdata->loadwhat, 8)) {
+                               loadfile = 1;
+                       } else
+                               continue;       /* fpga not for this card */
+                       if (loadfile != 1 && loadfile != 2) {
+                               continue;       /* skip to next card */
+                       }
+                       if (saa->boardcfg[0] && loadfile == 1 )
+                               continue;       /* skip to next card */
+                       if (saa->boardcfg[0] != 1 && loadfile == 2)
+                               continue;       /* skip to next card */
+                       saa->boardcfg[0]++;     /* mark fpga handled */
+                       printk("stradis%d: loading %s\n", saa->nr,
+                               bitdata->loadwhat);
+                       if (loadtwo && loadfile == 2)
+                               goto send_fpga_stuff;
+                       /* turn on the Audio interface to set PROG low */
+                       saawrite(0x00400040, SAA7146_GPIO_CTRL);
+                       saaread(SAA7146_PSR);   /* ensure posted write */
+                       /* wait for everyone to reset */
+                       mdelay(10);
+                       saawrite(0x00400000, SAA7146_GPIO_CTRL);
+               } else {        /* original card */
+                       if (strncmp(bitdata->loadwhat, "decoder2", 8))
+                               continue;       /* fpga not for this card */
+                       /* Pull the Xilinx PROG signal WS3 low */
+                       saawrite(0x02000200, SAA7146_MC1);
+                       /* Turn on the Audio interface so can set PROG low */
+                       saawrite(0x000000c0, SAA7146_ACON1);
+                       /* Pull the Xilinx INIT signal (GPIO2) low */
+                       saawrite(0x00400000, SAA7146_GPIO_CTRL);
+                       /* Make sure everybody resets */
+                       saaread(SAA7146_PSR);   /* ensure posted write */
+                       mdelay(10);
+                       /* Release the Xilinx PROG signal */
+                       saawrite(0x00000000, SAA7146_ACON1);
+                       /* Turn off the Audio interface */
+                       saawrite(0x02000000, SAA7146_MC1);
+               }
+               /* Release Xilinx INIT signal (WS2) */
+               saawrite(0x00000000, SAA7146_GPIO_CTRL);
+               /* Wait for the INIT to go High */
+               for (i = 0; i < 10000 &&
+                    !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++)
+                       schedule();
+               if (i == 1000) {
+                       printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
+                       return -1;
+               }
+send_fpga_stuff:
+               if (NewCard) {
+                       for (i = startindex; i < bitdata->datasize; i++)
+                               newdma[i - startindex] =
+                                       bitmangler[bitdata->data[i]];
+                       debiwrite(saa, 0x01420000, 0, 0,
+                               ((bitdata->datasize - startindex) + 5));
+                       if (loadtwo) {
+                               if (loadfile == 1) {
+                                       printk("stradis%d: "
+                                               "awaiting 2nd FPGA bitfile\n",
+                                               saa->nr);
+                                       continue;       /* skip to next card */
+                               }
+
+                       }
+               } else {
+                       for (i = startindex; i < bitdata->datasize; i++)
+                               dmabuf[i - startindex] =
+                                       bitmangler[bitdata->data[i]];
+                       debiwrite(saa, 0x014a0000, 0, 0,
+                               ((bitdata->datasize - startindex) + 5) * 2);
+               }
+               for (i = 0; i < 1000 &&
+                    !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++)
+                       schedule();
+               if (i == 1000) {
+                       printk(KERN_INFO "stradis%d: FPGA load failed\n",
+                              saa->nr);
+                       failure++;
+                       continue;
+               }
+               if (!NewCard) {
+                       /* Pull the Xilinx INIT signal (GPIO2) low */
+                       saawrite(0x00400000, SAA7146_GPIO_CTRL);
+                       saaread(SAA7146_PSR);   /* ensure posted write */
+                       mdelay(2);
+                       saawrite(0x00000000, SAA7146_GPIO_CTRL);
+                       mdelay(2);
+               }
+               printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
+               saa->boardcfg[0] = 26;  /* mark fpga programmed */
+               /* set VXCO to its lowest frequency */
+               debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
+               if (NewCard) {
+                       /* mute CS3310 */
+                       if (HaveCS3310)
+                               debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+                                         0, 2);
+                       /* set VXCO to PWM mode, release reset, blank on */
+                       debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
+                       mdelay(10);
+                       /* unmute CS3310 */
+                       if (HaveCS3310)
+                               debiwrite(saa, debNormal, XILINX_CTL0,
+                                         0x2020, 2);
+               }
+               /* set source Black */
+               debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+               saa->boardcfg[4] = 22;  /* set NTSC First Active Line */
+               saa->boardcfg[5] = 23;  /* set PAL First Active Line */
+               saa->boardcfg[54] = 2;  /* set NTSC Last Active Line - 256 */
+               saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */
+               set_out_format(saa, VIDEO_MODE_NTSC);
+               mdelay(50);
+               /* begin IBM chip init */
+               debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+               saaread(SAA7146_PSR);   /* wait for reset */
+               mdelay(5);
+               debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+               debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+               debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
+               debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
+               debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+               if (NewCard) {
+                       mdelay(5);
+                       /* set i2s rate converter to 48KHz */
+                       debiwrite(saa, debNormal, 0x80c0, 6, 2);
+                       /* we must init CS8420 first since rev b pulls i2s */
+                       /* master clock low and CS4341 needs i2s master to */
+                       /* run the i2c port. */
+                       if (HaveCS8420) {
+                               /* 0=consumer, 1=pro */
+                               initialize_cs8420(saa, 0);
+                       }
+                       mdelay(5);
+                       if (HaveCS4341)
+                               initialize_cs4341(saa);
+               }
+               debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+               debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+               debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+               debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+               if (NewCard)
+                       set_genlock_offset(saa, 0);
+               debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+#if 0
+               /* enable genlock */
+               debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
+#else
+               /* disable genlock */
+               debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
+#endif
+       }
+       return failure;
+}
+
+static int do_ibm_reset(struct saa7146 *saa)
+{
+       /* failure if decoder not previously programmed */
+       if (saa->boardcfg[0] < 37)
+               return -EIO;
+       /* mute CS3310 */
+       if (HaveCS3310)
+               debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
+       /* disable interrupts */
+       saawrite(0, SAA7146_IER);
+       saa->audhead = saa->audtail = 0;
+       saa->vidhead = saa->vidtail = 0;
+       /* tristate debi bus, disable debi transfers */
+       saawrite(0x00880000, SAA7146_MC1);
+       /* ensure posted write */
+       saaread(SAA7146_MC1);
+       mdelay(50);
+       /* re-enable debi transfers */
+       saawrite(0x00880088, SAA7146_MC1);
+       /* set source Black */
+       debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+       /* begin IBM chip init */
+       set_out_format(saa, CurrentMode);
+       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+       saaread(SAA7146_PSR);   /* wait for reset */
+       mdelay(5);
+       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+       debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+       debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+       if (NewCard) {
+               mdelay(5);
+               /* set i2s rate converter to 48KHz */
+               debiwrite(saa, debNormal, 0x80c0, 6, 2);
+               /* we must init CS8420 first since rev b pulls i2s */
+               /* master clock low and CS4341 needs i2s master to */
+               /* run the i2c port. */
+               if (HaveCS8420) {
+                       /* 0=consumer, 1=pro */
+                       initialize_cs8420(saa, 1);
+               }
+               mdelay(5);
+               if (HaveCS4341)
+                       initialize_cs4341(saa);
+       }
+       debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+       debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+       debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+       debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+       if (NewCard)
+               set_genlock_offset(saa, 0);
+       debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+       debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+       debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+       if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+               (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
+               printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
+       }
+       if (HaveCS3310) {
+               int i = CS3310MaxLvl;
+               debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i<<8)|i), 2);
+       }
+       /* start video decoder */
+       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+       /* 256k vid, 3520 bytes aud */
+       debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
+       debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+       ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+       /* enable buffer threshold irq */
+       debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+       /* clear pending interrupts */
+       debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+       debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+       return 0;
+}
+
+/* load the decoder microcode */
+static int initialize_ibmmpeg2(struct video_code *microcode)
+{
+       int i, num;
+       struct saa7146 *saa;
+
+       for (num = 0; num < saa_num; num++) {
+               saa = &saa7146s[num];
+               /* check that FPGA is loaded */
+               debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
+               if ((i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2)) !=
+                    0xa55a) {
+                       printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
+                               saa->nr, i);
+#if 0
+                       return -1;
+#endif
+               }
+               if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
+                       if (saa->boardcfg[0] > 27)
+                               continue;       /* skip to next card */
+                       /* load video control store */
+                       saa->boardcfg[1] = 0x13;  /* no-sync default */
+                       debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+                       for (i = 0; i < microcode->datasize / 2; i++)
+                               debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
+                                       (microcode->data[i * 2] << 8) |
+                                        microcode->data[i * 2 + 1], 2);
+                       debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+                                 ChipControl, 2);
+                       saa->boardcfg[0] = 28;
+               }
+               if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
+                       if (saa->boardcfg[0] > 35)
+                               continue;       /* skip to next card */
+                       /* load audio control store */
+                       debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+                       for (i = 0; i < microcode->datasize; i++)
+                               debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
+                                       microcode->data[i], 1);
+                       debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+                       if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+                           0xe000, 1)) {
+                               printk(KERN_ERR
+                                      "stradis%d: IBM config failed\n",
+                                      saa->nr);
+                               return -1;
+                       }
+                       /* set PWM to center value */
+                       if (NewCard) {
+                               debiwrite(saa, debNormal, XILINX_PWM,
+                                         saa->boardcfg[14] +
+                                         (saa->boardcfg[13]<<8), 2);
+                       } else
+                               debiwrite(saa, debNormal, XILINX_PWM,
+                                         0x46, 2);
+                       if (HaveCS3310) {
+                               i = CS3310MaxLvl;
+                               debiwrite(saa, debNormal,
+                                       XILINX_CS3310_CMPLT, ((i<<8)|i), 2);
+                       }
+                       printk(KERN_INFO
+                              "stradis%d: IBM MPEGCD%d Initialized\n",
+                              saa->nr, 18 + (debiread(saa, debNormal,
+                              IBM_MP2_CHIP_CONTROL, 2) >> 12));
+                       /* start video decoder */
+                       debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
+                               ChipControl, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD,
+                               0x4037, 2);     /* 256k vid, 3520 bytes aud */
+                       debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
+                       ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
+                       /* enable buffer threshold irq */
+                       debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+                       debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+                       /* enable gpio irq */
+                       saawrite(0x00002000, SAA7146_GPIO_CTRL);
+                       /* enable decoder output to HPS */
+                       debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
+                       saa->boardcfg[0] = 37;
+               }
+       }
+       return 0;
+}
+
+static u32 palette2fmt[] =
+{                              /* some of these YUV translations are wrong */
+  0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
+  0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
+  0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
+};
+static int bpp2fmt[4] =
+{
+       VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
+       VIDEO_PALETTE_RGB32
+};
+
+/* I wish I could find a formula to calculate these... */
+static u32 h_prescale[64] =
+{
+  0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
+  0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
+  0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
+  0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
+  0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
+  0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
+  0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
+  0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
+  0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
+  0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
+  0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
+};
+static u32 v_gain[64] =
+{
+  0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
+  0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
+  0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+  0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
+};
+
+
+static void saa7146_set_winsize(struct saa7146 *saa)
+{
+       u32 format;
+       int offset, yacl, ysci;
+       saa->win.color_fmt = format =
+           (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
+           palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
+       offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
+       saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
+       saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
+       saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
+       saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
+                SAA7146_PROT_ADDR1);
+       saawrite(0, SAA7146_PAGE1);
+       saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL);
+       offset = (704 / (saa->win.width - 1)) & 0x3f;
+       saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
+       offset = (720896 / saa->win.width) / (offset + 1);
+       saawrite((offset<<12)|0x0c, SAA7146_HPS_H_SCALE);
+       if (CurrentMode == VIDEO_MODE_NTSC) {
+               yacl = /*(480 / saa->win.height - 1) & 0x3f*/ 0;
+               ysci = 1024 - (saa->win.height * 1024 / 480);
+       } else {
+               yacl = /*(576 / saa->win.height - 1) & 0x3f*/ 0;
+               ysci = 1024 - (saa->win.height * 1024 / 576);
+       }
+       saawrite((1<<31)|(ysci<<21)|(yacl<<15), SAA7146_HPS_V_SCALE);
+       saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
+       saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
+                  SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
+                  SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H),
+                  SAA7146_MC2);
+}
+
+/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
+ * bitmap is fixed width, 128 bytes (1024 pixels represented) 
+ * arranged most-sigificant-bit-left in 32-bit words 
+ * based on saa7146 clipping hardware, it swaps bytes if LE 
+ * much of this makes up for egcs brain damage -- so if you
+ * are wondering "why did he do this?" it is because the C
+ * was adjusted to generate the optimal asm output without
+ * writing non-portable __asm__ directives.
+ */
+
+static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
+{
+       register int startword, endword;
+       register u32 bitsleft, bitsright;
+       u32 *temp;
+       if (x < 0) {
+               w += x;
+               x = 0;
+       }
+       if (y < 0) {
+               h += y;
+               y = 0;
+       }
+       if (w <= 0 || h <= 0 || x > 1023 || y > 639)
+               return;         /* throw away bad clips */
+       if (x + w > 1024)
+               w = 1024 - x;
+       if (y + h > 640)
+               h = 640 - y;
+       startword = (x >> 5);
+       endword = ((x + w) >> 5);
+       bitsleft = (0xffffffff >> (x & 31));
+       bitsright = (0xffffffff << (~((x + w) - (endword<<5))));
+       temp = &clipmap[(y<<5) + startword];
+       w = endword - startword;
+       if (!w) {
+               bitsleft |= bitsright;
+               for (y = 0; y < h; y++) {
+                       *temp |= bitsleft;
+                       temp += 32;
+               }
+       } else {
+               for (y = 0; y < h; y++) {
+                       *temp++ |= bitsleft;
+                       for (x = 1; x < w; x++)
+                               *temp++ = 0xffffffff;
+                       *temp |= bitsright;
+                       temp += (32 - w);
+               }
+       }
+}
+
+static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
+{
+       int i, width, height;
+       u32 *clipmap;
+
+       clipmap = saa->dmavid2;
+       if((width=saa->win.width)>1023)
+               width = 1023;           /* sanity check */
+       if((height=saa->win.height)>640)
+               height = 639;           /* sanity check */
+       if (ncr > 0) {  /* rectangles pased */
+               /* convert rectangular clips to a bitmap */
+               memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
+               for (i = 0; i < ncr; i++)
+                       clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
+                               cr[i].width, cr[i].height);
+       }
+       /* clip against viewing window AND screen 
+          so we do not have to rely on the user program
+        */
+       clip_draw_rectangle(clipmap,(saa->win.x+width>saa->win.swidth) ?
+               (saa->win.swidth-saa->win.x) : width, 0, 1024, 768);
+       clip_draw_rectangle(clipmap,0,(saa->win.y+height>saa->win.sheight) ?
+               (saa->win.sheight-saa->win.y) : height,1024,768);
+       if (saa->win.x<0)
+               clip_draw_rectangle(clipmap, 0, 0, -(saa->win.x), 768);
+       if (saa->win.y<0)
+               clip_draw_rectangle(clipmap, 0, 0, 1024, -(saa->win.y));
+}
+
+static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev;
+       switch (cmd) {
+       case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+                       strcpy(b.name, saa->video_dev.name);
+                       b.type = VID_TYPE_CAPTURE |
+                           VID_TYPE_OVERLAY |
+                           VID_TYPE_CLIPPING |
+                           VID_TYPE_FRAMERAM |
+                           VID_TYPE_SCALES;
+                       b.channels = 1;
+                       b.audios = 1;
+                       b.maxwidth = 768;
+                       b.maxheight = 576;
+                       b.minwidth = 32;
+                       b.minheight = 32;
+                       if (copy_to_user(arg, &b, sizeof(b)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCGPICT:
+               {
+                       struct video_picture p = saa->picture;
+                       if (saa->win.depth == 8)
+                               p.palette = VIDEO_PALETTE_HI240;
+                       if (saa->win.depth == 15)
+                               p.palette = VIDEO_PALETTE_RGB555;
+                       if (saa->win.depth == 16)
+                               p.palette = VIDEO_PALETTE_RGB565;
+                       if (saa->win.depth == 24)
+                               p.palette = VIDEO_PALETTE_RGB24;
+                       if (saa->win.depth == 32)
+                               p.palette = VIDEO_PALETTE_RGB32;
+                       if (copy_to_user(arg, &p, sizeof(p)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCSPICT:
+               {
+                       struct video_picture p;
+                       u32 format;
+                       if (copy_from_user(&p, arg, sizeof(p)))
+                               return -EFAULT;
+                       if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+                               format = palette2fmt[p.palette];
+                               saa->win.color_fmt = format;
+                               saawrite(format|0x60, SAA7146_CLIP_FORMAT_CTRL);
+                       }
+                       saawrite(((p.brightness & 0xff00) << 16) |
+                                ((p.contrast & 0xfe00) << 7) |
+                            ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
+                       saa->picture = p;
+                       /* upload changed registers */
+                       saawrite(((SAA7146_MC2_UPLD_HPS_H |
+                                SAA7146_MC2_UPLD_HPS_V) << 16) |
+                               SAA7146_MC2_UPLD_HPS_H | SAA7146_MC2_UPLD_HPS_V,
+                                SAA7146_MC2);
+                       return 0;
+               }
+       case VIDIOCSWIN:
+               {
+                       struct video_window vw;
+                       struct video_clip *vcp = NULL;
+
+                       if (copy_from_user(&vw, arg, sizeof(vw)))
+                               return -EFAULT;
+
+                       if (vw.flags || vw.width < 16 || vw.height < 16) {      /* stop capture */
+                               saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
+                               return -EINVAL;
+                       }
+                       if (saa->win.bpp < 4) {         /* 32-bit align start and adjust width */
+                               int i = vw.x;
+                               vw.x = (vw.x + 3) & ~3;
+                               i = vw.x - i;
+                               vw.width -= i;
+                       }
+                       saa->win.x = vw.x;
+                       saa->win.y = vw.y;
+                       saa->win.width = vw.width;
+                       if (saa->win.width > 768)
+                               saa->win.width = 768;
+                       saa->win.height = vw.height;
+                       if (CurrentMode == VIDEO_MODE_NTSC) {
+                               if (saa->win.height > 480)
+                                       saa->win.height = 480;
+                       } else {
+                               if (saa->win.height > 576)
+                                       saa->win.height = 576;
+                       }
+
+                       /* stop capture */
+                       saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
+                       saa7146_set_winsize(saa);
+
+                       /*
+                        *    Do any clips.
+                        */
+                       if (vw.clipcount < 0) {
+                               if (copy_from_user(saa->dmavid2, vw.clips,
+                                                  VIDEO_CLIPMAP_SIZE))
+                                       return -EFAULT;
+                       } else if (vw.clipcount > 0) {
+                               if ((vcp = vmalloc(sizeof(struct video_clip) *
+                                               (vw.clipcount))) == NULL)
+                                        return -ENOMEM;
+                               if (copy_from_user(vcp, vw.clips,
+                                             sizeof(struct video_clip) *
+                                                  vw.clipcount)) {
+                                       vfree(vcp);
+                                       return -EFAULT;
+                               }
+                       } else  /* nothing clipped */
+                               memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
+                       make_clip_tab(saa, vcp, vw.clipcount);
+                       if (vw.clipcount > 0)
+                               vfree(vcp);
+
+                       /* start capture & clip dma if we have an address */
+                       if ((saa->cap & 3) && saa->win.vidadr != 0)
+                               saawrite(((SAA7146_MC1_TR_E_1 |
+                                       SAA7146_MC1_TR_E_2) << 16) | 0xffff,
+                                       SAA7146_MC1);
+                       return 0;
+               }
+       case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+                       vw.x = saa->win.x;
+                       vw.y = saa->win.y;
+                       vw.width = saa->win.width;
+                       vw.height = saa->win.height;
+                       vw.chromakey = 0;
+                       vw.flags = 0;
+                       if (copy_to_user(arg, &vw, sizeof(vw)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCCAPTURE:
+               {
+                       int v;
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       if (v == 0) {
+                               saa->cap &= ~1;
+                               saawrite((SAA7146_MC1_TR_E_1 << 16),
+                                        SAA7146_MC1);
+                       } else {
+                               if (saa->win.vidadr == 0 || saa->win.width == 0
+                                   || saa->win.height == 0)
+                                       return -EINVAL;
+                               saa->cap |= 1;
+                               saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
+                                        SAA7146_MC1);
+                       }
+                       return 0;
+               }
+       case VIDIOCGFBUF:
+               {
+                       struct video_buffer v;
+                       v.base = (void *) saa->win.vidadr;
+                       v.height = saa->win.sheight;
+                       v.width = saa->win.swidth;
+                       v.depth = saa->win.depth;
+                       v.bytesperline = saa->win.bpl;
+                       if (copy_to_user(arg, &v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+
+               }
+       case VIDIOCSFBUF:
+               {
+                       struct video_buffer v;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
+                       v.depth != 24 && v.depth != 32 && v.width > 16 &&
+                           v.height > 16 && v.bytesperline > 16)
+                               return -EINVAL;
+                       if (v.base)
+                               saa->win.vidadr = (unsigned long) v.base;
+                       saa->win.sheight = v.height;
+                       saa->win.swidth = v.width;
+                       saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
+                       saa->win.depth = v.depth;
+                       saa->win.bpl = v.bytesperline;
+
+                       DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
+                                    v.base, v.width, v.height, saa->win.bpp, saa->win.bpl));
+                       saa7146_set_winsize(saa);
+                       return 0;
+               }
+       case VIDIOCKEY:
+               {
+                       /* Will be handled higher up .. */
+                       return 0;
+               }
+
+       case VIDIOCGAUDIO:
+               {
+                       struct video_audio v;
+                       v = saa->audio_dev;
+                       v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
+                       v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
+                       strcpy(v.name, "MPEG");
+                       v.mode = VIDEO_SOUND_STEREO;
+                       if (copy_to_user(arg, &v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCSAUDIO:
+               {
+                       struct video_audio v;
+                       int i;
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       i = (~(v.volume>>8))&0xff;
+                       if (!HaveCS4341) {
+                               if (v.flags & VIDEO_AUDIO_MUTE) {
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_FRNT_ATTEN,
+                                               0xffff, 2);
+                               }
+                               if (!(v.flags & VIDEO_AUDIO_MUTE))
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_FRNT_ATTEN,
+                                                 0x0000, 2);
+                               if (v.flags & VIDEO_AUDIO_VOLUME)
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_FRNT_ATTEN,
+                                               (i<<8)|i, 2);
+                       } else {
+                               if (v.flags & VIDEO_AUDIO_MUTE)
+                                       cs4341_setlevel(saa, 0xff, 0xff);
+                               if (!(v.flags & VIDEO_AUDIO_MUTE))
+                                       cs4341_setlevel(saa, 0, 0);
+                               if (v.flags & VIDEO_AUDIO_VOLUME)
+                                       cs4341_setlevel(saa, i, i);
+                       }
+                       saa->audio_dev = v;
+                       return 0;
+               }
+
+       case VIDIOCGUNIT:
+               {
+                       struct video_unit vu;
+                       vu.video = saa->video_dev.minor;
+                       vu.vbi = VIDEO_NO_UNIT;
+                       vu.radio = VIDEO_NO_UNIT;
+                       vu.audio = VIDEO_NO_UNIT;
+                       vu.teletext = VIDEO_NO_UNIT;
+                       if (copy_to_user((void *) arg, (void *) &vu, sizeof(vu)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCSPLAYMODE:
+               {
+                       struct video_play_mode pmode;
+                       if (copy_from_user((void *) &pmode, arg,
+                               sizeof(struct video_play_mode)))
+                               return -EFAULT;
+                       switch (pmode.mode) {
+                               case VID_PLAY_VID_OUT_MODE:
+                                       if (pmode.p1 != VIDEO_MODE_NTSC &&
+                                               pmode.p1 != VIDEO_MODE_PAL)
+                                               return -EINVAL;
+                                       set_out_format(saa, pmode.p1);
+                                       return 0;
+                               case VID_PLAY_GENLOCK:
+                                       debiwrite(saa, debNormal,
+                                                 XILINX_CTL0,
+                                                 (pmode.p1 ? 0x8000 : 0x8080),
+                                                 2);
+                                       if (NewCard)
+                                               set_genlock_offset(saa,
+                                                       pmode.p2);
+                                       return 0;
+                               case VID_PLAY_NORMAL:
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_CHIP_CONTROL,
+                                               ChipControl, 2);
+                                       ibm_send_command(saa,
+                                               IBM_MP2_PLAY, 0, 0);
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_PAUSE:
+                                       /* IBM removed the PAUSE command */
+                                       /* they say use SINGLE_FRAME now */
+                               case VID_PLAY_SINGLE_FRAME:
+                                       ibm_send_command(saa,
+                                                       IBM_MP2_SINGLE_FRAME,
+                                                       0, 0);
+                                       if (saa->playmode == pmode.mode) {
+                                               debiwrite(saa, debNormal,
+                                                       IBM_MP2_CHIP_CONTROL,
+                                                       ChipControl, 2);
+                                       }
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_FAST_FORWARD:
+                                       ibm_send_command(saa,
+                                               IBM_MP2_FAST_FORWARD, 0, 0);
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_SLOW_MOTION:
+                                       ibm_send_command(saa,
+                                               IBM_MP2_SLOW_MOTION,
+                                               pmode.p1, 0);
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_IMMEDIATE_NORMAL:
+                                       /* ensure transfers resume */
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_CHIP_CONTROL,
+                                               ChipControl, 2);
+                                       ibm_send_command(saa,
+                                               IBM_MP2_IMED_NORM_PLAY, 0, 0);
+                                       saa->playmode = VID_PLAY_NORMAL;
+                                       return 0;
+                               case VID_PLAY_SWITCH_CHANNELS:
+                                       saa->audhead = saa->audtail = 0;
+                                       saa->vidhead = saa->vidtail = 0;
+                                       ibm_send_command(saa,
+                                               IBM_MP2_FREEZE_FRAME, 0, 1);
+                                       ibm_send_command(saa,
+                                               IBM_MP2_RESET_AUD_RATE, 0, 1);
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_CHIP_CONTROL, 0, 2);
+                                       ibm_send_command(saa,
+                                               IBM_MP2_CHANNEL_SWITCH, 0, 1);
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_CHIP_CONTROL,
+                                               ChipControl, 2);
+                                       ibm_send_command(saa,
+                                               IBM_MP2_PLAY, 0, 0);
+                                       saa->playmode = VID_PLAY_NORMAL;
+                                       return 0;
+                               case VID_PLAY_FREEZE_FRAME:
+                                       ibm_send_command(saa,
+                                               IBM_MP2_FREEZE_FRAME, 0, 0);
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_STILL_MODE:
+                                       ibm_send_command(saa,
+                                               IBM_MP2_SET_STILL_MODE, 0, 0);
+                                       saa->playmode = pmode.mode;
+                                       return 0;
+                               case VID_PLAY_MASTER_MODE:
+                                       if (pmode.p1 == VID_PLAY_MASTER_NONE)
+                                               saa->boardcfg[1] = 0x13;
+                                       else if (pmode.p1 ==
+                                               VID_PLAY_MASTER_VIDEO)
+                                               saa->boardcfg[1] = 0x23;
+                                       else if (pmode.p1 ==
+                                               VID_PLAY_MASTER_AUDIO)
+                                               saa->boardcfg[1] = 0x43;
+                                       else
+                                               return -EINVAL;
+                                       debiwrite(saa, debNormal,
+                                               IBM_MP2_CHIP_CONTROL,
+                                               ChipControl, 2);
+                                       return 0;
+                               case VID_PLAY_ACTIVE_SCANLINES:
+                                       if (CurrentMode == VIDEO_MODE_PAL) {
+                                               if (pmode.p1 < 1 ||
+                                                       pmode.p2 > 625)
+                                                       return -EINVAL;
+                                               saa->boardcfg[5] = pmode.p1;
+                                               saa->boardcfg[55] = (pmode.p1 +
+                                                       (pmode.p2/2) - 1) &     
+                                                       0xff;
+                                       } else {
+                                               if (pmode.p1 < 4 ||
+                                                       pmode.p2 > 525)
+                                                       return -EINVAL;
+                                               saa->boardcfg[4] = pmode.p1;
+                                               saa->boardcfg[54] = (pmode.p1 +
+                                                       (pmode.p2/2) - 4) &
+                                                       0xff;
+                                       }
+                                       set_out_format(saa, CurrentMode);
+                               case VID_PLAY_RESET:
+                                       return do_ibm_reset(saa);
+                               case VID_PLAY_END_MARK:
+                                       if (saa->endmarktail <  
+                                               saa->endmarkhead) {
+                                               if (saa->endmarkhead -
+                                                       saa->endmarktail < 2)
+                                                       return -ENOSPC;
+                                       } else if (saa->endmarkhead <=
+                                               saa->endmarktail) {
+                                               if (saa->endmarktail -
+                                                       saa->endmarkhead >
+                                                       (MAX_MARKS - 2))
+                                                       return -ENOSPC;
+                                       } else
+                                               return -ENOSPC;
+                                       saa->endmark[saa->endmarktail] =
+                                               saa->audtail;
+                                       saa->endmarktail++;
+                                       if (saa->endmarktail >= MAX_MARKS)
+                                               saa->endmarktail = 0;
+                       }
+                       return -EINVAL;
+               }
+       case VIDIOCSWRITEMODE:
+               {
+                       int mode;
+                       if (copy_from_user((void *) &mode, arg, sizeof(int)))
+                                return -EFAULT;
+                       if (mode == VID_WRITE_MPEG_AUD ||
+                           mode == VID_WRITE_MPEG_VID ||
+                           mode == VID_WRITE_CC ||
+                           mode == VID_WRITE_TTX ||
+                           mode == VID_WRITE_OSD) {
+                               saa->writemode = mode;
+                               return 0;
+                       }
+                       return -EINVAL;
+               }
+       case VIDIOCSMICROCODE:
+               {
+                       struct video_code ucode;
+                       __u8 *udata;
+                       int i;
+                       if (copy_from_user((void *) &ucode, arg,
+                           sizeof(ucode)))
+                               return -EFAULT;
+                       if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
+                           strncmp(ucode.loadwhat, "dec", 3))
+                               return -EINVAL;
+                       if ((udata = vmalloc(ucode.datasize)) == NULL)
+                               return -ENOMEM;
+                       if (copy_from_user((void *) udata, ucode.data,
+                           ucode.datasize)) {
+                               vfree(udata);
+                               return -EFAULT;
+                       }
+                       ucode.data = udata;
+                       if (!strncmp(ucode.loadwhat, "decoder.aud", 11)
+                               || !strncmp(ucode.loadwhat, "decoder.vid", 11))
+                               i = initialize_ibmmpeg2(&ucode);
+                       else
+                               i = initialize_fpga(&ucode);
+                       vfree(udata);
+                       if (i)
+                               return -EINVAL;
+                       return 0;
+
+               }
+       case VIDIOCGCHAN:       /* this makes xawtv happy */
+               {
+                       struct video_channel v;
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       v.flags = VIDEO_VC_AUDIO;
+                       v.tuners = 0;
+                       v.type = VID_TYPE_MPEG_DECODER;
+                       v.norm = CurrentMode;
+                       strcpy(v.name, "MPEG2");
+                       if (copy_to_user(arg, &v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+               }
+       case VIDIOCSCHAN:       /* this makes xawtv happy */
+               {
+                       struct video_channel v;
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       /* do nothing */
+                       return 0;
+               }
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int saa_init_done(struct video_device *dev)
+{
+       return 0;
+}
+
+static int saa_mmap(struct video_device *dev, const char *adr,
+                   unsigned long size)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev;
+       printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
+       return -EINVAL;
+}
+
+static long saa_read(struct video_device *dev, char *buf,
+                    unsigned long count, int nonblock)
+{
+       return -EINVAL;
+}
+
+static long saa_write(struct video_device *dev, const char *buf,
+                     unsigned long count, int nonblock)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev;
+       unsigned long todo = count;
+       int blocksize, split;
+       unsigned long flags;
+
+       while (todo > 0) {
+               if (saa->writemode == VID_WRITE_MPEG_AUD) {
+                       spin_lock_irqsave(&saa->lock, flags);
+                       if (saa->audhead <= saa->audtail)
+                               blocksize = 65536-(saa->audtail - saa->audhead);
+                       else
+                               blocksize = saa->audhead - saa->audtail;
+                       spin_unlock_irqrestore(&saa->lock, flags);
+                       if (blocksize < 16384) {
+                               saawrite(SAA7146_PSR_DEBI_S |
+                                        SAA7146_PSR_PIN1, SAA7146_IER);
+                               saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+                               /* wait for buffer space to open */
+                               interruptible_sleep_on(&saa->audq);
+                       }
+                       spin_lock_irqsave(&saa->lock, flags);
+                       if (saa->audhead <= saa->audtail) {
+                               blocksize = 65536-(saa->audtail - saa->audhead);
+                               split = 65536 - saa->audtail;
+                       } else {
+                               blocksize = saa->audhead - saa->audtail;
+                               split = 65536;
+                       }
+                       spin_unlock_irqrestore(&saa->lock, flags);
+                       blocksize--;
+                       if (blocksize > todo)
+                               blocksize = todo;
+                       /* double check that we really have space */
+                       if (!blocksize)
+                               return -ENOSPC;
+                       if (split < blocksize) {
+                               if (copy_from_user(saa->audbuf +
+                                       saa->audtail, buf, split)) 
+                                       return -EFAULT;
+                               buf += split;
+                               todo -= split;
+                               blocksize -= split;
+                               saa->audtail = 0;
+                       }
+                       if (copy_from_user(saa->audbuf + saa->audtail, buf,
+                               blocksize)) 
+                               return -EFAULT;
+                       saa->audtail += blocksize;
+                       todo -= blocksize;
+                       buf += blocksize;
+                       saa->audtail &= 0xffff;
+               } else if (saa->writemode == VID_WRITE_MPEG_VID) {
+                       spin_lock_irqsave(&saa->lock, flags);
+                       if (saa->vidhead <= saa->vidtail)
+                               blocksize=524288-(saa->vidtail - saa->vidhead);
+                       else
+                               blocksize = saa->vidhead - saa->vidtail;
+                       spin_unlock_irqrestore(&saa->lock, flags);
+                       if (blocksize < 65536) {
+                               saawrite(SAA7146_PSR_DEBI_S |
+                                        SAA7146_PSR_PIN1, SAA7146_IER);
+                               saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+                               /* wait for buffer space to open */
+                               interruptible_sleep_on(&saa->vidq);
+                       }
+                       spin_lock_irqsave(&saa->lock, flags);
+                       if (saa->vidhead <= saa->vidtail) {
+                               blocksize=524288-(saa->vidtail - saa->vidhead);
+                               split = 524288 - saa->vidtail;
+                       } else {
+                               blocksize = saa->vidhead - saa->vidtail;
+                               split = 524288;
+                       }
+                       spin_unlock_irqrestore(&saa->lock, flags);
+                       blocksize--;
+                       if (blocksize > todo)
+                               blocksize = todo;
+                       /* double check that we really have space */
+                       if (!blocksize)
+                               return -ENOSPC;
+                       if (split < blocksize) {
+                               if (copy_from_user(saa->vidbuf +
+                                       saa->vidtail, buf, split)) 
+                                       return -EFAULT;
+                               buf += split;
+                               todo -= split;
+                               blocksize -= split;
+                               saa->vidtail = 0;
+                       }
+                       if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
+                               blocksize)) 
+                               return -EFAULT;
+                       saa->vidtail += blocksize;
+                       todo -= blocksize;
+                       buf += blocksize;
+                       saa->vidtail &= 0x7ffff;
+               } else if (saa->writemode == VID_WRITE_OSD) {
+                       if (count > 131072)
+                               return -ENOSPC;
+                       if (copy_from_user(saa->osdbuf, buf, count))
+                               return -EFAULT;
+                       buf += count;
+                       saa->osdhead = 0;
+                       saa->osdtail = count;
+                       debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
+                       debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+                                 debiread(saa, debNormal,
+                                 IBM_MP2_DISP_MODE, 2) | 1, 2);
+                       /* trigger osd data transfer */
+                       saawrite(SAA7146_PSR_DEBI_S |
+                                SAA7146_PSR_PIN1, SAA7146_IER);
+                       saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
+               }
+       }
+       return count;
+}
+
+static int saa_open(struct video_device *dev, int flags)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev;
+
+       saa->video_dev.busy = 0;
+       saa->user++;
+       if (saa->user > 1)
+               return 0;       /* device open already, don't reset */
+       saa->writemode = VID_WRITE_MPEG_VID;    /* default to video */
+       return 0;
+}
+
+static void saa_close(struct video_device *dev)
+{
+       struct saa7146 *saa = (struct saa7146 *) dev;
+       saa->user--;
+       saa->video_dev.busy = 0;
+       if (saa->user > 0)      /* still someone using device */
+               return;
+       saawrite(0x007f0000, SAA7146_MC1);      /* stop all overlay dma */
+}
+
+/* template for video_device-structure */
+static struct video_device saa_template =
+{
+       "SAA7146A",
+       VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
+       VID_HARDWARE_SAA7146,
+       saa_open,
+       saa_close,
+       saa_read,
+       saa_write,
+       NULL,                   /* poll */
+       saa_ioctl,
+       saa_mmap,
+       saa_init_done,
+       NULL,
+       0,
+       0
+};
+
+static int configure_saa7146(struct pci_dev *dev, int num)
+{
+       int result;
+       struct saa7146 *saa;
+
+       saa = &saa7146s[num];
+       
+       saa->endmarkhead = saa->endmarktail = 0;
+       saa->win.x = saa->win.y = 0;
+       saa->win.width = saa->win.cropwidth = 720;
+       saa->win.height = saa->win.cropheight = 480;
+       saa->win.cropx = saa->win.cropy = 0;
+       saa->win.bpp = 2;
+       saa->win.depth = 16;
+       saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
+       saa->win.bpl = 1024 * saa->win.bpp;
+       saa->win.swidth = 1024;
+       saa->win.sheight = 768;
+       saa->picture.brightness = 32768;
+       saa->picture.contrast = 38768;
+       saa->picture.colour = 32768;
+       saa->cap = 0;
+       saa->dev = dev;
+       saa->nr = num;
+       saa->playmode = VID_PLAY_NORMAL;
+       memset(saa->boardcfg, 0, 64);   /* clear board config area */
+       saa->saa7146_mem = NULL;
+       saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
+           saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
+           saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
+           saa->pagea1out = saa->pagea2in = saa->pagea2out =
+           saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
+           saa->pageRPS2 = NULL;
+       saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
+       saa->audhead = saa->vidtail = 0;
+
+       init_waitqueue_head(&saa->i2cq);
+       init_waitqueue_head(&saa->audq);
+       init_waitqueue_head(&saa->debiq);
+       init_waitqueue_head(&saa->vidq);
+       spin_lock_init(&saa->lock);
+       
+       saa->id = dev->device;
+       saa->irq = dev->irq;
+       saa->video_dev.minor = -1;
+       saa->saa7146_adr = dev->resource[0].start;
+       pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision);
+       saa->saa7146_mem = ioremap(((saa->saa7146_adr) &
+               PCI_BASE_ADDRESS_MEM_MASK), 0x200);
+       memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus));
+       memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
+       sprintf(saa->i2c.name, "stradis%d", num);
+       saa->i2c.data = saa;
+       saawrite(0, SAA7146_IER);       /* turn off all interrupts */
+       result = request_irq(saa->irq, saa7146_irq,
+                      SA_SHIRQ | SA_INTERRUPT, "stradis", (void *) saa);
+       if (result == -EINVAL)
+               printk(KERN_ERR "stradis%d: Bad irq number or handler\n",
+                      num);
+       if (result == -EBUSY)
+               printk(KERN_ERR "stradis%d: IRQ %ld busy, change your PnP"
+                      " config in BIOS\n", num, saa->irq);
+       if (result < 0)
+               return result;
+       pci_set_master(dev);
+       if (video_register_device(&saa->video_dev, VFL_TYPE_GRABBER) < 0)
+               return -1;
+#if 0
+       /* i2c generic interface is currently BROKEN */
+       i2c_register_bus(&saa->i2c);
+#endif
+       return 0;
+}
+
+static int init_saa7146(int i)
+{
+       struct saa7146 *saa = &saa7146s[i];
+
+       saa->user = 0;
+       /* reset the saa7146 */
+       saawrite(0xffff0000, SAA7146_MC1);
+       mdelay(5);
+       /* enable debi and i2c transfers and pins */
+       saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
+                  SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
+       /* ensure proper state of chip */
+       saawrite(0x00000000, SAA7146_PAGE1);
+       saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
+       saawrite(0x00000000, SAA7146_PAGE2);
+       saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
+       saawrite(0x00000000, SAA7146_DD1_INIT);
+       saawrite(0x00000000, SAA7146_DD1_STREAM_B);
+       saawrite(0x00000000, SAA7146_DD1_STREAM_A);
+       saawrite(0x00000000, SAA7146_BRS_CTRL);
+       saawrite(0x80400040, SAA7146_BCS_CTRL);
+       saawrite(0x0000e000 /*| (1<<29)*/, SAA7146_HPS_CTRL);
+       saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
+       saawrite(0x00000000, SAA7146_ACON1);
+       saawrite(0x00000000, SAA7146_ACON2);
+       saawrite(0x00000600, SAA7146_I2C_STATUS);
+       saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
+                  SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
+                  SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
+          SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
+                SAA7146_MC2);
+       /* setup arbitration control registers */
+       saawrite(0x1412121a, SAA7146_PCI_BT_V1);
+
+       /* allocate 32k dma buffer + 4k for page table */
+       if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "stradis%d: debi kmalloc failed\n", i);
+               return -1;
+       }
+#if 0
+       saa->pagedebi = saa->dmadebi + 32768;   /* top 4k is for mmu */
+       saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
+       for (i = 0; i < 12; i++)        /* setup mmu page table */
+               saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
+#endif
+       saa->audhead = saa->vidhead = saa->osdhead = 0;
+       saa->audtail = saa->vidtail = saa->osdtail = 0;
+       if (saa->vidbuf == NULL)
+               if ((saa->vidbuf = vmalloc(524288)) == NULL) {
+                       printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr);
+                       return -ENOMEM;
+               }
+       if (saa->audbuf == NULL)
+               if ((saa->audbuf = vmalloc(65536)) == NULL) {
+                       printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr);
+                       vfree(saa->vidbuf);
+                       saa->vidbuf = NULL;
+                       return -ENOMEM;
+               }
+       if (saa->osdbuf == NULL)
+               if ((saa->osdbuf = vmalloc(131072)) == NULL) {
+                       printk(KERN_ERR "stradis%d: malloc failed\n", saa->nr);
+                       vfree(saa->vidbuf);
+                       vfree(saa->audbuf);
+                       saa->vidbuf = saa->audbuf = NULL;
+                       return -ENOMEM;
+               }
+       /* allocate 81920 byte buffer for clipping */
+       if ((saa->dmavid2 = kmalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "stradis%d: clip kmalloc failed\n", saa->nr);
+               vfree(saa->vidbuf);
+               vfree(saa->audbuf);
+               vfree(saa->osdbuf);
+               saa->vidbuf = saa->audbuf = saa->osdbuf = NULL;
+               saa->dmavid2 = NULL;
+               return -1;
+       }
+       memset(saa->dmavid2, 0x00, VIDEO_CLIPMAP_SIZE); /* clip everything */
+       /* setup clipping registers */
+       saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
+       saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
+       saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
+               SAA7146_PROT_ADDR2);
+       saawrite(256, SAA7146_PITCH2);
+       saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */
+       saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
+                SAA7146_MC2);
+       I2CBusScan(&(saa->i2c));
+       return 0;
+}
+
+static void release_saa(void)
+{
+       u8 command;
+       int i;
+       struct saa7146 *saa;
+
+       for (i = 0; i < saa_num; i++) {
+               saa = &saa7146s[i];
+
+               /* turn off all capturing, DMA and IRQs */
+               saawrite(0xffff0000, SAA7146_MC1);      /* reset chip */
+               saawrite(0, SAA7146_MC2);
+               saawrite(0, SAA7146_IER);
+               saawrite(0xffffffffUL, SAA7146_ISR);
+#if 0
+               /* unregister i2c_bus */
+               i2c_unregister_bus((&saa->i2c));
+#endif
+
+               /* disable PCI bus-mastering */
+               pci_read_config_byte(saa->dev, PCI_COMMAND, &command);
+               /* Should this be &=~ ?? */
+               command &= ~PCI_COMMAND_MASTER;
+               pci_write_config_byte(saa->dev, PCI_COMMAND, command);
+               /* unmap and free memory */
+               saa->audhead = saa->audtail = saa->osdhead = 0;
+               saa->vidhead = saa->vidtail = saa->osdtail = 0;
+               if (saa->vidbuf)
+                       vfree(saa->vidbuf);
+               if (saa->audbuf)
+                       vfree(saa->audbuf);
+               if (saa->osdbuf)
+                       vfree(saa->osdbuf);
+               if (saa->dmavid2)
+                       kfree((void *) saa->dmavid2);
+               saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
+               saa->dmavid2 = NULL;
+               if (saa->dmadebi)
+                       kfree((void *) saa->dmadebi);
+               if (saa->dmavid1)
+                       kfree((void *) saa->dmavid1);
+               if (saa->dmavid2)
+                       kfree((void *) saa->dmavid2);
+               if (saa->dmavid3)
+                       kfree((void *) saa->dmavid3);
+               if (saa->dmaa1in)
+                       kfree((void *) saa->dmaa1in);
+               if (saa->dmaa1out)
+                       kfree((void *) saa->dmaa1out);
+               if (saa->dmaa2in)
+                       kfree((void *) saa->dmaa2in);
+               if (saa->dmaa2out)
+                       kfree((void *) saa->dmaa2out);
+               if (saa->dmaRPS1)
+                       kfree((void *) saa->dmaRPS1);
+               if (saa->dmaRPS2)
+                       kfree((void *) saa->dmaRPS2);
+               free_irq(saa->irq, saa);
+               if (saa->saa7146_mem)
+                       iounmap(saa->saa7146_mem);
+               if (saa->video_dev.minor != -1)
+                       video_unregister_device(&saa->video_dev);
+       }
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+#else
+int init_stradis_cards(struct video_init *unused)
+{
+#endif
+       struct pci_dev *dev = pci_devices;
+       int result = 0, i;
+       u32 newcard;
+
+       saa_num = 0;
+
+       while (dev) {
+               if (dev->vendor == PCI_VENDOR_ID_PHILIPS)
+                       if (dev->device == PCI_DEVICE_ID_PHILIPS_SAA7146) {
+                               pci_read_config_dword(dev,
+                                       PCI_SUBSYSTEM_VENDOR_ID, &newcard);
+                               if (!newcard)
+                                       printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
+                               else
+                                       printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); 
+                               result = configure_saa7146(dev, saa_num++);
+                       }
+               if (result)
+                       return result;
+               dev = dev->next;
+       }
+       if (saa_num)
+               printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num);
+       else
+               return -EINVAL;
+       for (i = 0; i < saa_num; i++)
+               if (init_saa7146(i) < 0) {
+                       release_saa();
+                       return -EIO;
+               }
+       return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+       release_saa();
+       printk(KERN_INFO "stradis: module cleanup complete\n");
+}
+
+#endif
index 5f02b26e1ad5e1a6c2870df31990256d53dc895b..05f2eeeeaeadc5ff3988cfcb81d0b7b6f27a009d 100644 (file)
@@ -60,6 +60,9 @@ static struct video_init video_init_list[]={
        {"i2c-tuner", i2c_tuner_init},
        {"bttv", init_bttv_cards},
 #endif 
+#ifdef CONFIG_VIDEO_STRADIS
+       {"stradis", init_stradis_cards},
+#endif 
 #ifdef CONFIG_VIDEO_BWQCAM
        {"bw-qcam", init_bw_qcams},
 #endif 
index de2d393b31da440f394f05e376e21646f7865a90..4efb923fb7b336894abd98c0ebfb08b33e41f478 100644 (file)
@@ -9,13 +9,13 @@
 
 AUTHORS (so far)
 
-Alan Cox,      Building Number Three Ltd.
+Alan Cox, Building Number Three Ltd.
        Core code, SCSI and Block OSMs
 
-Steve Ralston, LSI Logic Corp.
+Steve Ralston, LSI Logic Corp.
        Debugging SCSI and Block OSM
 
-Deepak Saxena, Intel Corp.
+Deepak Saxena, Intel Corp.
        /proc interface, bug fixes
        Ioctl interfaces for control
        Debugging LAN OSM
@@ -23,18 +23,21 @@ Deepak Saxena,      Intel Corp.
 Philip Rumpf
        Fixed assorted dumb SMP locking bugs
 
-Juha Sievanen,  University of Helsinki Finland
+Juha Sievanen, University of Helsinki Finland
        LAN OSM code
        /proc interface to LAN class
        Bug fixes
        Core code extensions
 
-Auvo Häkkinen,  University of Helsinki Finland
+Auvo Häkkinen, University of Helsinki Finland
        LAN OSM code
        /Proc interface to LAN class
        Bug fixes
        Core code extensions
 
+Taneli Vähäkangas, University of Helsinki Finland
+       Fixes to i2o_config
+
 CREDITS
 
        This work was made possible by 
@@ -75,6 +78,7 @@ o     Long term message flow control
 o      PCI IOP's without interrupts are not supported yet
 o      Push FAIL handling into the core
 o      DDM control interfaces for module load etc
+o      Event handling
 
 Block:
 o      Real error handler
@@ -87,7 +91,8 @@ SCSI:
 o      Find the right way to associate drives/luns/busses
 
 Lan:   Batch mode sends
-       Fix the "killing interrupt handler" in i2o_set_multicast_list
+       Performance tuning
+       Event handling
 
 Tape:
 o      Anyone seen anything implementing this ?
index 49f34c078db79a333b804a586ddeeb37fe626906..3c1dd462ecfe54328d1c0713b2eca605c8459f11 100644 (file)
@@ -208,18 +208,16 @@ VIII. Downloading Software
 
    DESCRIPTION
 
-   This function downloads the software pointed by sw->buf to the
-   iop identified by sw->iop. The DownloadFlags, SwID, SwType and SwSize 
-   fields of the ExecSwDownload message are filled in with the values of 
-   sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
-
-   Once the ioctl() is called and software transfer begins, the 
-   user can read the value *(sw->maxfrag) and *(sw->curfrag) to
-   determine the status of the software transfer. As the IOP
-   is very slow when it comes to SW transfers, this can be
-   used by a separate thread to report status to the user. The
-   user _should not_ write to this memory location until the ioctl()
-   has returned.
+   This function downloads a software fragment pointed by sw->buf
+   to the iop identified by sw->iop. The DownloadFlags, SwID, SwType
+   and SwSize fields of the ExecSwDownload message are filled in with
+   the values of sw->flags, sw->sw_id, sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be sent in order and be 8K in size. The last
+   fragment _may_ be shorter, however. The kernel will compute its
+   size based on information in the sw->swlen field.
+
+   Please note that SW transfers can take a long time.
 
    RETURNS
 
@@ -234,7 +232,7 @@ VIII. Downloading Software
 IX. Uploading Software
    
    SYNOPSIS 
+
    ioctl(fd, I2OSWUL, struct i2o_sw_xfer *sw);
 
       struct i2o_sw_xfer
@@ -251,19 +249,17 @@ IX. Uploading Software
 
    DESCRIPTION
 
-   This function uploads software from the IOP identified by sw->iop
-   and places it in the buffer pointed to by sw->buf. The length of the
-   buffer is given in *(sw->swlen). The UploadFlags, SwID and SwType
-   fields of the ExecSwUpload message are filled in 
-   with the values of sw->flags, sw->sw_id and sw->sw_type. 
-
-   Once the ioctl() is called and software transfer begins, the 
-   user can read the value *(sw->maxfrag) and *(sw->curfrag) to
-   determine the status of the software transfer.  As the IOP
-   is very slow when it comes to SW transfers, this can be
-   used by a separate thread to report status to the user. The
-   user _should not_ write to this memory location until the ioctl()
-   has returned.
+   This function uploads a software fragment from the IOP identified
+   by sw->iop, sw->sw_type, sw->sw_id and optionally sw->swlen fields.
+   The UploadFlags, SwID, SwType and SwSize fields of the ExecSwUpload
+   message are filled in with the values of sw->flags, sw->sw_id,
+   sw->sw_type and *(sw->swlen).
+
+   The fragments _must_ be requested in order and be 8K in size. The
+   user is responsible for allocating memory pointed by sw->buf. The
+   last fragment _may_ be shorter.
+
+   Please note that SW transfers can take a long time.
 
    RETURNS
 
index c8682f077b2a01fa7f25494bb3df8d31246f2944..96d9c17e17aeeaddf8f058c47302bba0f4161d44 100644 (file)
  *         - Added software download ioctl (still testing)
  *     Modified 09/10/1999 by Auvo Häkkinen
  *        - Changes to i2o_cfg_reply(), ioctl_parms()
- *        - Added ioct_validate() (not yet tested)
+ *        - Added ioct_validate()
+ *     Modified 09/30/1999 by Taneli Vähäkangas
+ *        - Fixed ioctl_swdl()
+ *     Modified 10/04/1999 by Taneli Vähäkangas
+ *        - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -33,8 +37,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include "i2o_proc.h"
-
 static int i2o_cfg_token = 0;
 static int i2o_cfg_context = -1;
 static void *page_buf;
@@ -196,7 +198,7 @@ int ioctl_gethrt(unsigned long arg)
        struct i2o_controller *c;
        struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
        struct i2o_cmd_hrtlct kcmd;
-       pi2o_hrt hrt;
+       i2o_hrt *hrt;
        int len;
        u32 reslen;
        int ret = 0;
@@ -214,7 +216,7 @@ int ioctl_gethrt(unsigned long arg)
        if(!c)
                return -ENXIO;
                
-       hrt = (pi2o_hrt)c->hrt;
+       hrt = (i2o_hrt *)c->hrt;
 
        i2o_unlock_controller(c);
 
@@ -235,7 +237,7 @@ int ioctl_getlct(unsigned long arg)
        struct i2o_controller *c;
        struct i2o_cmd_hrtlct *cmd = (struct i2o_cmd_hrtlct*)arg;
        struct i2o_cmd_hrtlct kcmd;
-       pi2o_lct lct;
+       i2o_lct *lct;
        int len;
        int ret = 0;
        u32 reslen;
@@ -253,7 +255,7 @@ int ioctl_getlct(unsigned long arg)
        if(!c)
                return -ENXIO;
 
-       lct = (pi2o_lct)c->lct;
+       lct = (i2o_lct *)c->lct;
        i2o_unlock_controller(c);
 
        len = (unsigned int)lct->table_size << 2;
@@ -317,14 +319,14 @@ static int ioctl_parms(unsigned long arg, unsigned int type)
                return -ENOMEM;
        }
 
-        len = i2o_issue_params(i2o_cmd, c, kcmd.tid,
-                               ops, kcmd.oplen, res, 65536);
+        len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
+                               ops, kcmd.oplen, res, sizeof(res));
         i2o_unlock_controller(c);
        kfree(ops);
         
-       if (len) {
+       if (len < 0) {
                kfree(res);
-               return len; /* -DetailedStatus || -ETIMEDOUT */
+               return len; /* -DetailedStatus */
        }
 
        put_user(len, kcmd.reslen);
@@ -414,7 +416,7 @@ int ioctl_html(unsigned long arg)
        }
 
        token = i2o_post_wait(c, msg, 9*4, 10);
-       if(token)
+       if(token != I2O_POST_WAIT_OK)
        {
                i2o_unlock_controller(c);
                kfree(res);
@@ -437,139 +439,175 @@ int ioctl_html(unsigned long arg)
 
        return ret;
 }
-
 int ioctl_swdl(unsigned long arg)
 {
        struct i2o_sw_xfer kxfer;
        struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
-       unsigned char maxfrag = 0, curfrag = 0;
-       unsigned char buffer[8192];
+       unsigned char maxfrag = 0, curfrag = 1;
+       unsigned char *buffer;
        u32 msg[9];
-       unsigned int token = 0, diff = 0, swlen = 0, swxfer = 0;
+       unsigned int status = 0, swlen = 0, fragsize = 8192;
        struct i2o_controller *c;
-       int foo = 0;
 
-       printk("*** foo%d ***\n", foo++);
        if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
-       {
-               printk( "i2o_config: can't copy i2o_sw cmd @ %p\n", pxfer);
                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
 
-       printk("Attempting to copy swlen from %p\n", kxfer.swlen);
        if(get_user(swlen, kxfer.swlen) < 0)
-       {
-               printk( "i2o_config: can't copy swlen\n");
                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
 
-       maxfrag = swlen >> 13;  // Transfer in 8k fragments
-
-       printk("Attempting to write maxfrag @ %p\n", kxfer.maxfrag);
-       if(put_user(maxfrag, kxfer.maxfrag) < 0)
-       {
-               printk( "i2o_config: can't write maxfrag\n");
+       if(get_user(maxfrag, kxfer.maxfrag) < 0)
                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
 
-       printk("Attempting to write curfrag @ %p\n", kxfer.curfrag);
-       if(put_user(curfrag, kxfer.curfrag) < 0)
-       {
-               printk( "i2o_config: can't write curfrag\n");
+       if(get_user(curfrag, kxfer.curfrag) < 0)
                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
 
-       if(!kxfer.buf)
-       {
-               printk( "i2o_config: NULL software buffer\n");
+       if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+
+       if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))
                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
        
-       // access_ok doesn't check for NULL...
-       if(!access_ok(VERIFY_READ, kxfer.buf, swlen))
-       {
-                printk( "i2o_config: Cannot read sw buffer\n");
-                return -EFAULT;
-       }
-       printk("*** foo%d ***\n", foo++);
-
        c = i2o_find_controller(kxfer.iop);
        if(!c)
                return -ENXIO;
-       printk("*** foo%d ***\n", foo++);
+
+       buffer=kmalloc(fragsize, GFP_KERNEL);
+       if (buffer==NULL)
+       {
+               i2o_unlock_controller(c);
+               return -ENOMEM;
+       }
+       __copy_from_user(buffer, kxfer.buf, fragsize);
 
        msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
        msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
        msg[2]= (u32)cfg_handler.context;
        msg[3]= 0;
-       msg[4]= ((u32)kxfer.flags)<<24|((u32)kxfer.sw_type)<<16|((u32)maxfrag)<<8|((u32)curfrag);
+       msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) |
+               (((u32)maxfrag)<<8) | (((u32)curfrag));
        msg[5]= swlen;
        msg[6]= kxfer.sw_id;
-       msg[7]= (0xD0000000 | 8192);
+       msg[7]= (0xD0000000 | fragsize);
        msg[8]= virt_to_phys(buffer);
 
-       printk("*** foo%d ***\n", foo++);
-
-       //
-       // Loop through all fragments but last and transfer them...
-       // We already checked memory, so from now we assume it's all good
-       //
-       for(curfrag = 0; curfrag < maxfrag-1; curfrag++)
-       {
-               printk("Transfering fragment %d\n", curfrag);
+//     printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+       status = i2o_post_wait(c, msg, sizeof(msg), 60);
 
-               msg[4] |= (u32)curfrag;
-
-               __copy_from_user(buffer, kxfer.buf, 8192);
-               swxfer += 8192;
-
-               // Yes...that's one minute, but the spec states that
-               // transfers take a long time, and I've seen just how
-               // long they can take.
-               token = i2o_post_wait(c, msg, sizeof(msg), 60);
-               if (token)      // Something very wrong
-               {
-                       i2o_unlock_controller(c);
-                       printk("Timeout downloading software");
-                       return -ETIMEDOUT;
-               }
-
-               __put_user(curfrag, kxfer.curfrag);
-       }
-
-       // Last frag is special case since it's not exactly 8K
-       diff = swlen - swxfer;
-       msg[4] |= (u32)maxfrag;
-       msg[7] = (0xD0000000 | diff);
-       __copy_from_user(buffer, kxfer.buf, 8192);
-       token = i2o_post_wait(c, msg, sizeof(msg), 60);
-       if(token)       // Something very wrong
+       i2o_unlock_controller(c);
+       kfree(buffer);
+       
+       if (status != I2O_POST_WAIT_OK)
        {
-               i2o_unlock_controller(c);
-               printk("Timeout downloading software");
+               // it fails if you try and send frags out of order
+               // and for some yet unknown reasons too
+               printk("i2o_config: swdl failed, DetailedStatus = %d\n", status);
                return -ETIMEDOUT;
        }
-       __put_user(curfrag, kxfer.curfrag);
-       i2o_unlock_controller(c);
 
        return 0;
 }
 
-/* To be written */
 int ioctl_swul(unsigned long arg)
 {
-       return -EINVAL;
+       struct i2o_sw_xfer kxfer;
+       struct i2o_sw_xfer *pxfer = (struct i2o_sw_xfer *)arg;
+       unsigned char maxfrag = 0, curfrag = 1;
+       unsigned char *buffer;
+       u32 msg[9];
+       unsigned int status = 0, swlen = 0, fragsize = 8192;
+       struct i2o_controller *c;
+       
+       if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+               return -EFAULT;
+               
+       if(get_user(swlen, kxfer.swlen) < 0)
+               return -EFAULT;
+               
+       if(get_user(maxfrag, kxfer.maxfrag) < 0)
+               return -EFAULT;
+               
+       if(get_user(curfrag, kxfer.curfrag) < 0)
+               return -EFAULT;
+       
+       if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192;
+       
+       if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize))
+               return -EFAULT;
+               
+       c = i2o_find_controller(kxfer.iop);
+       if(!c)
+               return -ENXIO;
+               
+       buffer=kmalloc(fragsize, GFP_KERNEL);
+       if (buffer==NULL)
+       {
+               i2o_unlock_controller(c);
+               return -ENOMEM;
+       }
+       
+       msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7;
+       msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID;
+       msg[2]= (u32)cfg_handler.context;
+       msg[3]= 0;
+       msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag;
+       msg[5]= swlen;
+       msg[6]= kxfer.sw_id;
+       msg[7]= (0xD0000000 | fragsize);
+       msg[8]= virt_to_bus(buffer);
+       
+//     printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
+       status = i2o_post_wait(c, msg, sizeof(msg), 60);
+       i2o_unlock_controller(c);
+       
+       if (status != I2O_POST_WAIT_OK)
+       {
+               kfree(buffer);
+               printk("i2o_config: swul failed, DetailedStatus = %d\n", status);
+               return -ETIMEDOUT;
+       }
+       
+       __copy_to_user(kxfer.buf, buffer, fragsize);
+       kfree(buffer);
+       
+       return 0;
 }
 
-/* To be written */
 int ioctl_swdel(unsigned long arg)
 {
-       return -EINVAL;
+       struct i2o_controller *c;
+       struct i2o_sw_xfer kxfer, *pxfer = (struct i2o_sw_xfer *)arg;
+       u32 msg[7];
+       unsigned int swlen;
+       int token;
+       
+       if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
+               return -EFAULT;
+               
+       if (get_user(swlen, kxfer.swlen) < 0)
+               return -EFAULT;
+               
+       c = i2o_find_controller(kxfer.iop);
+       if (!c)
+               return -ENXIO;
+
+       msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0;
+       msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID;
+       msg[2] = (u32)i2o_cfg_context;
+       msg[3] = 0;
+       msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16;
+       msg[5] = swlen;
+       msg[6] = kxfer.sw_id;
+
+       token = i2o_post_wait(c, msg, sizeof(msg), 10);
+       i2o_unlock_controller(c);
+       
+       if (token != I2O_POST_WAIT_OK)
+       {
+               printk("i2o_config: swdel failed, DetailedStatus = %d\n", token);
+               return -ETIMEDOUT;
+       }
+       
+       return 0;
 }
 
 int ioctl_validate(unsigned long arg)
@@ -591,7 +629,7 @@ int ioctl_validate(unsigned long arg)
         token = i2o_post_wait(c, msg, sizeof(msg), 10);
         i2o_unlock_controller(c);
 
-        if (token)
+        if (token != I2O_POST_WAIT_OK)
         {
                 printk("Can't validate configuration, ErrorStatus = %d\n",
                        token);
@@ -644,7 +682,7 @@ int init_module(void)
 int __init i2o_config_init(void)
 #endif
 {
-       printk(KERN_INFO "i2o configuration manager v 0.02\n");
+       printk(KERN_INFO "i2o configuration manager v 0.03\n");
        
        if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
        {
index c8a6db4a4dddd3849f8235eb04ac7a5ebd5542cd..8642540c0588ba1b262319910cbb98b185561813 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/bitops.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/timer.h>
 
 #include <asm/io.h>
@@ -927,7 +928,7 @@ static int i2o_parse_lct(struct i2o_controller *c)
        u32 *p;
        struct i2o_device *d;
        char str[22];
-       pi2o_lct lct = c->lct;
+       i2o_lct *lct = c->lct;
 
        max = lct->table_size;
        
@@ -1168,6 +1169,9 @@ static int i2o_reset_controller(struct i2o_controller *c)
 
        /* Wait for a reply */
        time=jiffies;
+       
+       /* DPT driver claims they need this */
+       mdelay(5);
 
 #ifdef DRIVERDEBUG
        printk(KERN_INFO "Reset posted, waiting...\n");
@@ -1192,7 +1196,7 @@ static int i2o_reset_controller(struct i2o_controller *c)
        {
                /* 
                 * Once the reset is sent, the IOP goes into the INIT state 
-                * which is inditerminate.  We need to wait until the IOP 
+                * which is indeterminate.  We need to wait until the IOP 
                 * has rebooted before we can let the system talk to 
                 * it. We read the inbound Free_List until a message is 
                 * available.  If we can't read one in the given ammount of 
@@ -1230,6 +1234,7 @@ int i2o_status_get(struct i2o_controller *c)
        u32 m;
        u32 *msg;
        u8 *status_block;
+       int i;
 
 #ifdef DRIVERDEBUG
        printk(KERN_INFO "Getting status block for iop%d\n", c->unit);
@@ -1238,7 +1243,7 @@ int i2o_status_get(struct i2o_controller *c)
                kfree(c->status_block);
 
        c->status_block = 
-               (pi2o_status_block)kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
+               (i2o_status_block *)kmalloc(sizeof(i2o_status_block),GFP_KERNEL);
        if(c->status_block == NULL)
        {
 #ifdef DRIVERDEBUG
@@ -1248,45 +1253,53 @@ int i2o_status_get(struct i2o_controller *c)
        }
 
        status_block = (u8*)c->status_block;
+       
+       for(i=0;i<5;i++)
+       {
+               m=i2o_wait_message(c, "StatusGet");
+               if(m==0xFFFFFFFF)
+                       return -ETIMEDOUT;
+               
+               memset(status_block, 0, sizeof(i2o_status_block));
+       
+               msg=(u32 *)(c->mem_offset+m);
+
+               __raw_writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
+               __raw_writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]);
+               __raw_writel(0, &msg[2]);
+               __raw_writel(0, &msg[3]);
+               __raw_writel(0, &msg[4]);
+               __raw_writel(0, &msg[5]);
+               __raw_writel(virt_to_bus(c->status_block), &msg[6]);
+               __raw_writel(0, &msg[7]);       /* 64bit host FIXME */
+               __raw_writel(sizeof(i2o_status_block), &msg[8]);
+               
+               printk("SB is %d bytes.\n", sizeof(i2o_status_block));
 
-       m=i2o_wait_message(c, "StatusGet");
-       if(m==0xFFFFFFFF)
-               return -ETIMEDOUT;
-
-       msg=(u32 *)(c->mem_offset+m);
-
-       msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
-       msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2]=core_context;
-       msg[3]=0;
-       msg[4]=0;
-       msg[5]=0;
-       msg[6]=virt_to_phys(c->status_block);
-       msg[7]=0;       /* 64bit host FIXME */
-       msg[8]=88;
-
-       i2o_post_message(c,m);
-
-       /* Wait for a reply */
-       time=jiffies;
+               i2o_post_message(c,m);
+               
+               /* DPT work around */
+               mdelay(5);
 
-       while(status_block[87]!=0xFF)
-       {
-               if((jiffies-time)>=5*HZ)
+               /* Wait for a reply */
+               time=jiffies;
+       
+               while((jiffies-time)<=HZ)
                {
+                       if(status_block[87]!=0)
+                       {
+                               /* Ok the reply has arrived. Fill in the important stuff */
+                               c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
+                               return 0;
+                       }
+                       schedule();
+                       barrier();
+               }
 #ifdef DRIVERDEBUG
-                       printk(KERN_ERR "IOP get status timeout.\n");
+               printk(KERN_ERR "IOP get status timeout.\n");
 #endif
-                       return -ETIMEDOUT;
-               }
-               schedule();
-               barrier();
        }
-       
-       /* Ok the reply has arrived. Fill in the important stuff */
-       c->inbound_size = (status_block[12]|(status_block[13]<<8))*4;
-
-       return 0;
+       return 0;//-ETIMEDOUT;
 }
 
 
@@ -1354,7 +1367,7 @@ static int i2o_systab_send(struct i2o_controller* iop)
  */
 static void __init i2o_sys_init()
 {
-       struct i2o_controller *iop;
+       struct i2o_controller *iop, *niop;
        int ret;
        u32 m;
 
@@ -1362,18 +1375,30 @@ static void __init i2o_sys_init()
        printk(KERN_INFO "This may take a few minutes if there are many devices\n");
 
        /* Get the status for each IOP */
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
        {
+               niop = iop->next;
 #ifdef DRIVERDEBUG
                printk(KERN_INFO "Getting initial status for iop%d\n", iop->unit);
 #endif
-               i2o_status_get(iop);
+               if(i2o_status_get(iop)<0)
+               {
+                       printk("Unable to obtain status of IOP, attempting a reset.\n");
+                       i2o_reset_controller(iop);
+                       if(i2o_status_get(iop)<0)
+                       {
+                               printk("IOP not responding.\n");
+                               i2o_delete_controller(iop);
+                               continue;
+                       }
+               }
 
                if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED)
                {
                        printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
                                        iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
 
                if(iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
@@ -1384,7 +1409,7 @@ static void __init i2o_sys_init()
                        int msg[256];
 
 #ifdef DRIVERDEBUG
-                       printk(KERN_INFO "iop%d already running...trying to reboot",
+                       printk(KERN_INFO "iop%d already running...trying to reboot\n",
                                        iop->unit);
 #endif
                        i2o_init_outbound_q(iop);
@@ -1396,6 +1421,7 @@ static void __init i2o_sys_init()
                        {
                                printk(KERN_CRIT "Failed to initialize iop%d\n", iop->unit);
                                i2o_delete_controller(iop);
+                               continue;
                        }
                }
        }
@@ -1403,9 +1429,11 @@ static void __init i2o_sys_init()
        /*
         * Now init the outbound queue for each one.
         */
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
        {
                int i;
+               
+               niop = iop->next;
 
                if((ret=i2o_init_outbound_q(iop)))
                {
@@ -1413,6 +1441,7 @@ static void __init i2o_sys_init()
                                "IOP%d initialization failed: Could not initialize outbound q\n",
                                iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
                iop->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
 
@@ -1438,18 +1467,20 @@ static void __init i2o_sys_init()
        /*
         * OK..parse the HRT
         */
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
        {
+               niop = iop->next;
                if(i2o_hrt_get(iop))
                {
                        printk(KERN_CRIT "iop%d: Could not get HRT!\n", iop->unit);
                        i2o_delete_controller(iop);
-                       break;
+                       continue;
                }
                if(i2o_parse_hrt(iop))
                {
                        printk(KERN_CRIT "iop%d: Could not parse HRT!\n", iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
        }
 
@@ -1466,15 +1497,17 @@ static void __init i2o_sys_init()
                return;
        }
 
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
 #ifdef DRIVERDEBUG
        {
+               niop = iop->next;
                printk(KERN_INFO "Sending system table to iop%d\n", iop->unit);
 #endif
                if(i2o_systab_send(iop))
                {
                        printk(KERN_CRIT "iop%d: Error sending system table\n", iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
 #ifdef DRIVERDEBUG
        }
@@ -1483,8 +1516,9 @@ static void __init i2o_sys_init()
        /*
         * Enable
         */
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
        {
+               niop = iop->next;
 #ifdef DRIVERDEBUG
                printk(KERN_INFO "Enableing iop%d\n", iop->unit);
 #endif
@@ -1492,14 +1526,16 @@ static void __init i2o_sys_init()
                {
                        printk(KERN_ERR "Could not enable iop%d\n", iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
        }
 
        /*
         * OK..one last thing and we're ready to go!
         */
-       for(iop = i2o_controller_chain; iop; iop = iop->next)
+       for(iop = i2o_controller_chain; iop; iop = niop)
        {
+               niop = iop->next;
 #ifdef DRIVERDEBUG
                printk(KERN_INFO "Getting LCT for iop%d\n", iop->unit);
 #endif
@@ -1507,6 +1543,7 @@ static void __init i2o_sys_init()
                {
                        printk(KERN_ERR "Could not get LCT from iop%d\n", iop->unit);
                        i2o_delete_controller(iop);
+                       continue;
                }
                else    
                        i2o_parse_lct(iop);
@@ -1667,7 +1704,7 @@ int i2o_init_outbound_q(struct i2o_controller *c)
        msg[4]= 4096;                   /* Host page frame size */
        msg[5]= MSG_FRAME_SIZE<<16|0x80;        /* Outbound msg frame size and Initcode */
        msg[6]= 0xD0000004;             /* Simple SG LE, EOB */
-       msg[7]= virt_to_phys(workspace);
+       msg[7]= virt_to_bus(workspace);
        *((u32 *)workspace)=0;
 
        /*
@@ -1685,7 +1722,6 @@ int i2o_init_outbound_q(struct i2o_controller *c)
                {
                        printk(KERN_ERR "i2o/iop%d: IOP outbound initialise failed.\n",
                                                c->unit);
-                       kfree(workspace);
                        return -ETIMEDOUT;
                }
                schedule();
@@ -2419,7 +2455,7 @@ static void i2o_report_util_cmd(u8 cmd)
        case I2O_CMD_UTIL_DEVICE_RELEASE:
                printk("UTIL_DEVICE_RELEASE, ");
                break;
-       case I2O_CMD_UTIL_ACK:
+       case I2O_CMD_UTIL_EVT_ACK:
                printk("UTIL_EVENT_ACKNOWLEDGE, ");
                break;
        case I2O_CMD_UTIL_EVT_REGISTER:
index 60798606a4e031e1cc59fab89e4e72cdc58ea87c..c9516286333d367c01eacb321b889703350d3e09 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     linux/drivers/i2o/i2o_lan.c
  *
- *     I2O LAN CLASS OSM       Prototyping, September 17th 1999
+ *     I2O LAN CLASS OSM       Prototyping, November 8th 1999
  *
  *     (C) Copyright 1999      University of Helsinki,
  *                             Department of Computer Science
@@ -11,7 +11,7 @@
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
  *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.    
+ *     2 of the License, or (at your option) any later version.
  *
  *     Authors:        Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
  *                     Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
@@ -20,9 +20,7 @@
  *     Tested:         in FDDI environment (using SysKonnect's DDM)
  *                     in Ethernet environment (using Intel 82558 DDM proto)
  *
- *     TODO:           batch mode networking
- *                     - we've not been able to test batch replies and 
- *                       batch receives
+ *     TODO:           batch mode sends
  *                     error checking / timeouts
  *                     code / test for other LAN classes
  */
@@ -39,6 +37,7 @@
 #include <linux/trdevice.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/tqueue.h>
 #include <asm/io.h>
 
 #include <linux/errno.h>
 #include <linux/i2o.h>
 #include "i2o_lan.h"
 
-//#define DRIVERDEBUG
+#define DRIVERDEBUG
 #ifdef DRIVERDEBUG
 #define dprintk(s, args...) printk(s, ## args)
 #else
 #define dprintk(s, args...)
 #endif
 
-#define MAX_LAN_CARDS 4
+/* Module params */
+
+static u32 bucketpost   = I2O_BUCKET_COUNT;
+static u32 bucketthresh = I2O_BUCKET_THRESH;
+static u32 rx_copybreak = 200;
+
+#define MAX_LAN_CARDS 16
 static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];
 static int unit = -1;                  /* device unit number */
 
 struct i2o_lan_local {
        u8 unit;
        struct i2o_device *i2o_dev;
-       int reply_flag;                 /* needed by scalar/table queries */
-       struct fddi_statistics stats;   /* see also struct net_device_stats */ 
+       struct fddi_statistics stats;   /* see also struct net_device_stats */
        unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
-       /* 
-        * Due to way that interrupts can pile up, we need to keep track
-        * of buckets ourselves.  Otherwise we'll end up flooding
-        * the DDM with buckets.
-        */
-       u32     bucket_count;
-
-   /*
-    * Keep track of no. of outstanding TXes
-    */
-   u32   tx_count;
-   u32   max_tx;
-   u32   tx_full;
-
-   spinlock_t lock;
+       u32 bucket_count;               /* nbr of buckets sent to DDM */
+       u32 tx_count;                   /* nbr of outstanding TXes */
+       u32 max_tx;                     /* DDM's Tx queue len */
 
+       spinlock_t lock;
 };
 
-/* function prototypes */
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
+                          struct i2o_message *m); 
+static void i2o_lan_event_reply(struct net_device *dev, u32 *msg); 
 static int i2o_lan_receive_post(struct net_device *dev, u32 count);
 static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg);
 static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);
 
-/*
- * Module params
- */
-static u32 bucketpost = I2O_BUCKET_COUNT;
-static u32 bucketthresh = I2O_BUCKET_THRESH;
-static u32 rx_copybreak = 200;
+static struct i2o_handler i2o_lan_handler = {
+       i2o_lan_reply,
+       "I2O Lan OSM",
+       0,              // context
+       I2O_CLASS_LAN
+};
+static int lan_context;  
 
-static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, 
+
+static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                          struct i2o_message *m)
-{  
+{
        u32 *msg = (u32 *)m;
        u8 unit  = (u8)(msg[2]>>16); // InitiatorContext
        struct net_device *dev = i2o_landevs[unit];
 
-       if (msg[0] & (1<<13)) // Fail bit is set
-       {
-               printk(KERN_ERR "IOP failed to process the msg:\n");
+       if (msg[0] & (1<<13)) { // Fail bit is set
+               printk(KERN_ERR "%s: IOP failed to process the msg:\n",dev->name);
                printk(KERN_ERR "  Cmd = 0x%02X, InitiatorTid = %d, TargetTid = %d\n",
                        (msg[1] >> 24) & 0xFF, (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
                printk(KERN_ERR "  FailureCode = 0x%02X\n  Severity = 0x%02X\n  "
                        "LowestVersion = 0x%02X\n  HighestVersion = 0x%02X\n",
-                        msg[4] >> 24, (msg[4] >> 16) & 0xFF, 
+                        msg[4] >> 24, (msg[4] >> 16) & 0xFF,
                        (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
                printk(KERN_ERR "  FailingHostUnit = 0x%04X\n  FailingIOP = 0x%03X\n",
                        msg[5] >> 16, msg[5] & 0xFFF);
@@ -115,23 +111,21 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
        }       
 
 #ifndef DRIVERDEBUG
-       if (msg[4] >> 24)       /* ReqStatus != SUCCESS */
+       if (msg[4] >> 24)       /* ReqStatus != SUCCESS */
 #endif
                i2o_report_status(KERN_INFO, dev->name, msg);
-
+       
        switch (msg[1] >> 24) {
        case LAN_RECEIVE_POST: 
        {
-               if (dev->start)
-               {
-                       if(!(msg[4]>>24))
-                       {
+               if (dev->start) {
+                       if(!(msg[4]>>24)) {
                                i2o_lan_receive_post_reply(dev,msg);
                                break;
                        }
 
                        // Something VERY wrong if this is happening
-                       printk( KERN_WARNING "i2olan: Device %s rejected bucket post\n", dev->name);
+                       printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name);
                }
 
                // Getting unused buckets back
@@ -146,15 +140,16 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
                u8 trl_count  = msg[3] & 0x000000FF;    
                
-               do {    // The HDM has handled the outgoing packet
+               while (trl_count) {     
+                       // The HDM has handled the outgoing packet
                        dev_kfree_skb((struct sk_buff *)msg[4 + trl_count]);
-                       dprintk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
+                       printk(KERN_INFO "%s: Request skb freed (trl_count=%d).\n",
                                dev->name,trl_count);
                        priv->tx_count--;
-               } while (--trl_count);
+                       trl_count--;
+               }
                
-               if(dev->tbusy)
-               {
+               if (dev->tbusy) {
                        clear_bit(0,(void*)&dev->tbusy);
                        mark_bh(NET_BH); /* inform upper layers */
                }
@@ -162,45 +157,135 @@ static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
                break;  
        }
 
-       default: 
-               if (msg[2] & 0x80000000)  // reply to a UtilParamsGet/Set
-               {       
-                       int *flag = (int *)msg[3]; // flag for i2o_post_wait
-                       if (msg[4] >> 24) // ReqStatus != SUCCESS
-                               *flag = -(msg[4] & 0xFFFF); // DetailedStatus
-                       else
-                               *flag = I2O_POST_WAIT_OK;
-               }
+       case LAN_RESET:
+       case LAN_SUSPEND:
+               break;
+
+       case I2O_CMD_UTIL_EVT_REGISTER:
+        case I2O_CMD_UTIL_EVT_ACK:
+               i2o_lan_event_reply(dev, msg);
+               break;
+
+       default:
+               printk(KERN_ERR "%s: Sorry, no handler for the reply.\n", dev->name);
+               i2o_report_status(KERN_INFO, dev->name, msg);           
        }
 }
 
+
+static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
+{
+        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+        struct i2o_device *i2o_dev = priv->i2o_dev;
+        struct i2o_controller *iop = i2o_dev->controller;
+        struct i2o_reply {
+                u8  version_offset;
+                u8  msg_flags;
+                u16 msg_size;
+                u32 tid:12;
+                u32 initiator:12;
+                u32 function:8;
+                u32 initiator_context;
+                u32 transaction_context;
+                u32 evt_indicator;
+                u32 evt_data[(iop->inbound_size - 20) / 4];     /* max */
+        } *evt = (struct i2o_reply *)msg;
+
+        int evt_data_len = (evt->msg_size - 5) * 4;             /* real */
+
+        if (evt->function == I2O_CMD_UTIL_EVT_REGISTER) {
+                printk(KERN_INFO "%s: I2O event - ", dev->name);
+
+                switch (evt->evt_indicator) {
+                        case I2O_EVT_IND_STATE_CHANGE:
+                                printk("State chance 0x%08X.\n",
+                                        evt->evt_data[0]);
+                                break;
+                        case I2O_EVT_IND_GENERAL_WARNING:
+                                printk("General warning 0x%02X.\n",
+                                        evt->evt_data[0]);
+                                break;
+                        case I2O_EVT_IND_CONFIGURATION_FLAG:
+                                printk("Configuration requested.\n");
+                                break;
+                        case I2O_EVT_IND_LOCK_RELEASE:
+                                printk("Lock released.\n");
+                                break;
+                        case I2O_EVT_IND_CAPABILITY_CHANGE:
+                                printk("Capability change 0x%02X.\n",
+                                        evt->evt_data[0]);
+                                break;
+                        case I2O_EVT_IND_DEVICE_RESET:
+                                printk("Device reset.\n");
+                                break;                            
+                        case I2O_EVT_IND_EVT_MASK_MODIFIED:
+                                printk("Event mask modified, 0x%08X.\n",
+                                        evt->evt_data[0]);
+                                break;
+                        case I2O_EVT_IND_FIELD_MODIFIED: {
+                                u16 *work16 = (u16 *)evt->evt_data;
+                                printk("Group 0x%04X, field %d changed.\n",
+                                        work16[0], work16[1]);
+                                break;
+                        }
+                        case I2O_EVT_IND_VENDOR_EVT: {
+                                int i;
+                                printk("Vendor event:\n");
+                                for (i = 0; i < evt_data_len / 4; i++)
+                                        printk("   0x%08X\n", evt->evt_data[i]);
+                                break;
+                        }
+                        case I2O_EVT_IND_DEVICE_STATE:
+                                printk("Device state changed 0x%08X.\n",
+                                        evt->evt_data[0]);
+                                break;
+                        case I2O_LAN_EVT_LINK_DOWN:
+                                printk("Link to the physical device is lost.\n");
+                                break;
+                        case I2O_LAN_EVT_LINK_UP:
+                                printk("Link to the physical device is (re)established.\n");
+                                break;
+                        case I2O_LAN_EVT_MEDIA_CHANGE:
+                                printk("Media change.\n");
+                                break;
+                        default:
+                                printk("Event Indicator = 0x%08X.\n",
+                                        evt->evt_indicator);
+                }
+
+                /*
+                 * EventAck necessary only for events that cause the device
+                 * to syncronize with the user
+                 *
+                 *if (i2o_event_ack(iop, i2o_dev->lct_data->tid,
+                 *               priv->unit << 16 | lan_context,
+                 *               evt->evt_indicator,
+                 *               evt->evt_data, evt_data_len) < 0)
+                 *       printk("%s: Event Acknowledge timeout.\n", dev->name);
+                 */
+        }
+
+        /* else evt->function == I2O_CMD_UTIL_EVT_ACK) */
+        /* Do we need to do something here too? */
+}   
+
+
 void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        u8 trl_count  = (u8)(msg[3] & 0x000000FF);      
        u32 *pskb = &msg[6];
-       
-       while (trl_count) 
-       {       
-               dprintk("%s: Releasing unused sk_buff %p\n",dev->name, 
+
+       while (trl_count) {     
+               dprintk("%s: Releasing unused sk_buff %p.\n",dev->name,
                        (struct sk_buff*)(*pskb));
-               dev_kfree_skb((struct sk_buff*)(*pskb)); 
+               dev_kfree_skb((struct sk_buff*)(*pskb));
                pskb++;
                priv->bucket_count--;
                trl_count--;
        }
 }
 
-static struct i2o_handler i2o_lan_handler =
-{
-       i2o_lan_reply,
-       "I2O Lan OSM",
-       0,              // context
-       I2O_CLASS_LAN
-};
-static int lan_context;
-
-
 static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -210,25 +295,21 @@ static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
        u8 trl_count  = msg[3] & 0x000000FF;    
        struct sk_buff *skb, *newskb;
 
-static int n_calls = 0;
-n_calls++;
-
 #if 0
        dprintk(KERN_INFO "TrlFlags = 0x%02X, TrlElementSize = %d, TrlCount = %d\n"
-               "msgsize = %d, buckets_remaining = %d\n", 
+               "msgsize = %d, buckets_remaining = %d\n",
                msg[3]>>24, msg[3]&0x0000FF00, trl_count, msg[0]>>16, msg[5]);  
 #endif
-
-       while (trl_count--)
-       {
+       while (trl_count--) {
                skb = (struct sk_buff *)(bucket->context);              
                packet = (struct i2o_packet_info *)bucket->packet_info; 
                priv->bucket_count--;
 
+#if 0
                dprintk(KERN_INFO "Buckets_remaining = %d, bucket_count = %d, trl_count = %d\n",
                        msg[5], priv->bucket_count, trl_count);
-#if 0
-               dprintk(KERN)INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
+
+               dprintk(KERN_INFO "flags = 0x%02X, offset = 0x%06X, status = 0x%02X, length = %d\n",
                        packet->flags, packet->offset, packet->status, packet->len);
 #endif
                if (packet->len < rx_copybreak) {
@@ -241,15 +322,15 @@ n_calls++;
                                newskb->protocol = priv->type_trans(newskb, dev);
 
                                netif_rx(newskb);
-                               dev_kfree_skb(skb); // FIXME: reuse this skb? 
+                               dev_kfree_skb(skb); // FIXME: reuse this skb?
                        }
                        else {
-                               printk("I2OLAN-%s: Can't allocate skb.\n", dev->name);
+                               printk("%s: Can't allocate skb.\n", dev->name);
                                return -ENOMEM;
                        }
                } else {
                        skb_put(skb,packet->len);               
-                       skb->dev  = dev;                
+                       skb->dev = dev;         
                        skb->protocol = priv->type_trans(skb, dev);
 
                        netif_rx(skb);
@@ -260,20 +341,17 @@ n_calls++;
                bucket++; // to next Packet Descriptor Block
        }
 
-       if (priv->bucket_count < bucketpost - bucketthresh)
-               i2o_lan_receive_post(dev, bucketpost - priv->bucket_count);
-
        if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN)
-       {
-               printk(KERN_INFO "%s: DDM out of buckets (count = %d)! "
-                        "Number of posts = %d\n", dev->name, msg[5], n_calls);
-               n_calls = 0;
-       }
+               printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n",
+                        dev->name, msg[5]);
+       
+       if (priv->bucket_count <= bucketpost - bucketthresh)
+               i2o_lan_receive_post(dev, bucketpost - priv->bucket_count);
 
        return 0;
 }
 
-/* 
+/*
  * i2o_lan_receive_post(): Post buckets to receive packets.
  */
 static int i2o_lan_receive_post(struct net_device *dev, u32 count)
@@ -289,14 +367,12 @@ static int i2o_lan_receive_post(struct net_device *dev, u32 count)
        int n_elems = (iop->inbound_size - 16 ) / 12; /* msg header + SGLs */
        u32 total = 0;
        int i;
-
-       while (total < count)
-       {
+       
+       while (total < count) {
                m = I2O_POST_READ32(iop);
                if (m == 0xFFFFFFFF)
                        return -ETIMEDOUT;              
-               msg = bus_to_virt(iop->mem_offset + m);
-
+               msg = (u32 *)(iop->mem_offset + m);
                bucket_count = (total + n_elems < count)
                             ? n_elems
                             : count - total;
@@ -306,8 +382,7 @@ static int i2o_lan_receive_post(struct net_device *dev, u32 count)
                msg[2] = priv->unit << 16 | lan_context; // InitiatorContext    
                msg[3] = bucket_count;                   // BucketCount
 
-               for (i = 0; i < bucket_count; i++)
-               {
+               for (i = 0; i < bucket_count; i++) {
                        skb = dev_alloc_skb(bucket_len + 2);
                        if (skb == NULL)
                                return -ENOMEM;
@@ -331,11 +406,11 @@ static int i2o_lan_receive_post(struct net_device *dev, u32 count)
        return 0;       
 }      
 
-/* 
- * i2o_lan_reset(): Reset the LAN adapter into the operational state and 
+/*
+ * i2o_lan_reset(): Reset the LAN adapter into the operational state and
  *     restore it to full operation.
  */
-static int i2o_lan_reset(struct net_device *dev) 
+static int i2o_lan_reset(struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;
@@ -351,12 +426,12 @@ static int i2o_lan_reset(struct net_device *dev)
        if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
                return -ETIMEDOUT;              
 
-       return 0; 
+       return 0;
 }
 
-/* 
+/*
  * i2o_lan_suspend(): Put LAN adapter into a safe, non-active state.
- *     Reply to any LAN class message with status error_no_data_transfer 
+ *     Reply to any LAN class message with status error_no_data_transfer
  *     / suspended.
  */
 static int i2o_lan_suspend(struct net_device *dev)
@@ -366,14 +441,14 @@ static int i2o_lan_suspend(struct net_device *dev)
        struct i2o_controller *iop = i2o_dev->controller;       
        u32 msg[5];
 
-       dprintk( "%s: LAN SUSPEND MESSAGE\n", dev->name );
+       dprintk( "%s: LAN SUSPEND MESSAGE.\n", dev->name );
        msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
        msg[1] = LAN_SUSPEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
        msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
        msg[3] = 0;                              // TransactionContext
        msg[4] = 1 << 16;                        // return posted buckets
 
-       if (i2o_post_this(iop, msg, sizeof(msg))< 0)
+       if (i2o_post_this(iop, msg, sizeof(msg)) < 0)
                return -ETIMEDOUT;
 
        return 0;
@@ -385,9 +460,9 @@ static int i2o_lan_suspend(struct net_device *dev)
 static void i2o_set_batch_mode(struct net_device *dev)
 {
 
-/* 
+/*
  * NOTE: we have not been able to test batch mode
- *      since HDMs we have, don't implement it 
+ *      since HDMs we have, don't implement it
  */
 
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
@@ -400,11 +475,13 @@ static void i2o_set_batch_mode(struct net_device *dev)
        // enable batch mode, toggle automatically
        val = 0x00000000;
 //     val = 0x00000001; // turn off batch mode
-       if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, 4) < 0)
-               printk(KERN_WARNING "Unable to enter I2O LAN batch mode.\n");
-       else
+       if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0003, 0, &val, sizeof(val)) <0)
+               printk(KERN_WARNING "%s: Unable to enter I2O LAN batch mode.\n",
+                       dev->name);
+       else 
                dprintk(KERN_INFO "%s: I2O LAN batch mode enabled.\n",dev->name);
 //             dprintk(KERN_INFO "%s: I2O LAN batch mode disabled.\n",dev->name);
+
        /*
         * When PacketOrphanlimit is same as the maximum packet length,
         * the packets will never be split into two separate buckets
@@ -413,31 +490,39 @@ static void i2o_set_batch_mode(struct net_device *dev)
        /* set LAN_OPERATION attributes */
 
        val = dev->mtu + dev->hard_header_len; // PacketOrphanLimit
-       if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0004, 2, &val, 4))
-               printk(KERN_WARNING "i2o_lan: Unable to set PacketOrphanLimit.\n");
+       if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0004, 2, &val, sizeof(val)) < 0)
+               printk(KERN_WARNING "%s: Unable to set PacketOrphanLimit.\n",
+                       dev->name);
        else
-               dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d\n",
+               dprintk(KERN_INFO "%s: PacketOrphanLimit set to %d.\n",
                        dev->name,val);
-
+       
        return; 
 }
 
-/* 
- * i2o_lan_open(): Open the device to send/receive packets via 
+/*
+ * i2o_lan_open(): Open the device to send/receive packets via
  * the network device. 
  */
 static int i2o_lan_open(struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
-       struct i2o_device *i2o_dev = priv->i2o_dev;     
+       struct i2o_device *i2o_dev = priv->i2o_dev;
+       struct i2o_controller *iop = i2o_dev->controller; 
+       u32 evt_mask =  0xFFC00007; // All generic events, all lan evenst
 
-       if(i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
-       {
+       if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
                printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
                return -EAGAIN;
        }
-       dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", dev->name, i2o_dev->lct_data->tid);
-
+       dprintk(KERN_INFO "%s: I2O LAN device claimed (tid=%d).\n", 
+               dev->name, i2o_dev->lct_data->tid);
+#if 0
+       if (i2o_event_register(iop, i2o_dev->lct_data->tid,
+                               priv->unit << 16 | lan_context, evt_mask) < 0)
+               printk(KERN_WARNING "%s: Unable to set the event mask.\n", 
+                       dev->name);
+#endif
        i2o_lan_reset(dev);
        
        dev->tbusy = 0;
@@ -453,19 +538,26 @@ static int i2o_lan_open(struct net_device *dev)
 
 /*
  * i2o_lan_close(): End the transfering.
- */ 
+ */
 static int i2o_lan_close(struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
        struct i2o_device *i2o_dev = priv->i2o_dev;     
-
+//#if 0
+       struct i2o_controller *iop = i2o_dev->controller; 
+
+       if (i2o_event_register(iop, i2o_dev->lct_data->tid,
+                               priv->unit << 16 | lan_context, 0) < 0)
+               printk(KERN_WARNING "%s: Unable to clear the event mask.\n", 
+                               dev->name);
+//#endif
        dev->tbusy = 1;
        dev->start = 0;
        i2o_lan_suspend(dev);
 
-       if(i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
+       if (i2o_release_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY))
                printk(KERN_WARNING "%s: Unable to unclaim I2O LAN device "
-                      "(tid=%d)\n", dev->name, i2o_dev->lct_data->tid);
+                      "(tid=%d).\n", dev->name, i2o_dev->lct_data->tid);
 
        MOD_DEC_USE_COUNT;
 
@@ -473,9 +565,9 @@ static int i2o_lan_close(struct net_device *dev)
 }
 
 #if 0
-/* 
+/*
  * i2o_lan_sdu_send(): Send a packet, MAC header added by the HDM.
- * Must be supported by Fibre Channel, optional for Ethernet/802.3, 
+ * Must be supported by Fibre Channel, optional for Ethernet/802.3,
  * Token Ring, FDDI
  */
 static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
@@ -484,12 +576,12 @@ static int i2o_lan_sdu_send(struct sk_buff *skb, struct net_device *dev)
 }
 #endif
 
-/* 
+/*
  * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
- * 
- * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for 
+ *
+ * Must be supported by Ethernet/802.3, Token Ring, FDDI, optional for
  * Fibre Channel
- */ 
+ */
 static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
 {
        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
@@ -498,14 +590,13 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
        u32 m, *msg;
        u32 flags = 0;
 
-       /* 
+       /*
         * Keep interrupt from changing dev->tbusy from underneath us
         * (Do we really need to do this?)
         */
        spin_lock_irqsave(&priv->lock, flags);
 
-       if(test_and_set_bit(0,(void*)&dev->tbusy) != 0)
-       {
+       if(test_and_set_bit(0,(void*)&dev->tbusy) != 0) {
                spin_unlock_irqrestore(&priv->lock, flags);
                return 1;
        }
@@ -515,9 +606,19 @@ static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
                spin_unlock_irqrestore(&priv->lock, flags);
                dev_kfree_skb(skb);
                return -ETIMEDOUT;
-       }    
-       msg = bus_to_virt(iop->mem_offset + m);
-       
+       }
+       msg = (u32 *)(iop->mem_offset + m);
+
+#if 0
+       __raw_writel(SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4,&msg[0]);
+       __raw_writel(LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid, &msg[1]);
+       __raw_writel(priv->unit << 16 | lan_context, &msg[2]); // InitiatorContext
+       __raw_writel(1 << 4, &msg[3]);                  // TransmitControlWord
+       __raw_writel(0xD5000000 | skb->len, &msg[4]);   // MAC hdr included
+       __raw_writel((u32)skb, &msg[5]);                // TransactionContext
+       __raw_writel(virt_to_bus(skb->data),&msg[6]);
+#endif
+
        msg[0] = SEVEN_WORD_MSG_SIZE | 1<<12 | SGL_OFFSET_4;
        msg[1] = LAN_PACKET_SEND<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;   
        msg[2] = priv->unit << 16 | lan_context; // IntiatorContext
@@ -552,8 +653,8 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
        u64 val64[16];
        u64 supported_group[4] = { 0, 0, 0, 0 };
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, 
-                        val64, sizeof(val64)) < 0)
+        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0100, -1, val64, 
+                            sizeof(val64)) < 0)
                printk("%s: Unable to query LAN_HISTORICAL_STATS.\n",dev->name);
        else {
                dprintk("%s: LAN_HISTORICAL_STATS queried.\n",dev->name);
@@ -566,13 +667,13 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                priv->stats.rx_dropped = val64[6];
        }
 
-        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0180, -1, 
+        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0180, -1,
                        &supported_group, sizeof(supported_group)) < 0)
                printk("%s: Unable to query LAN_SUPPORTED_OPTIONAL_HISTORICAL_STATS.\n",dev->name);
 
        if (supported_group[2]) {
-               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0183, -1, 
-                       val64, sizeof(val64) ) < 0)
+               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0183, -1,
+                       val64, sizeof(val64)) < 0)
                        printk("%s: Unable to query LAN_OPTIONAL_RX_HISTORICAL_STATS.\n",dev->name);
                else {
                        dprintk("%s: LAN_OPTIONAL_RX_HISTORICAL_STATS queried.\n",dev->name);
@@ -582,11 +683,10 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                }
        }
 
-       if (i2o_dev->lct_data->sub_class == I2O_LAN_ETHERNET)
-       {
+       if (i2o_dev->lct_data->sub_class == I2O_LAN_ETHERNET) {
                u64 supported_stats = 0;                
 
-               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0200, -1, 
+               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0200, -1,
                                 val64, sizeof(val64)) < 0)
                        printk("%s: Unable to query LAN_802_3_HISTORICAL_STATS.\n",dev->name);
                else {
@@ -596,14 +696,15 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
                        priv->stats.tx_carrier_errors  = val64[6];
                }
 
-               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0280, -1, 
-                                &supported_stats, 8) < 0)
-                       printk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS\n", dev->name);
+               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0280, -1,
+                                &supported_stats, sizeof(supported_stats)) < 0)
+                       printk("%s: Unable to query LAN_SUPPORTED_802_3_HISTORICAL_STATS.\n", dev->name);
 
                if (supported_stats != 0) {
-                       if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0281, -1, 
+                       if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0281, -1,
                                         val64, sizeof(val64)) < 0)
-                               printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
+;
+//                             printk("%s: Unable to query LAN_OPTIONAL_802_3_HISTORICAL_STATS.\n",dev->name);
                        else {
                                dprintk("%s: LAN_OPTIONAL_802_3_HISTORICAL_STATS queried.\n",dev->name);
                                if (supported_stats & 0x1)
@@ -616,13 +717,12 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
        }
 
 #ifdef CONFIG_TR
-       if (i2o_dev->lct_data->sub_class == I2O_LAN_TR)
-       {
-               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0300, -1, 
+       if (i2o_dev->lct_data->sub_class == I2O_LAN_TR) {
+               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0300, -1,
                                 val64, sizeof(val64)) < 0)
                        printk("%s: Unable to query LAN_802_5_HISTORICAL_STATS.\n",dev->name);
                else {
-                       struct tr_statistics *stats = 
+                       struct tr_statistics *stats =
                                        (struct tr_statistics *)&priv->stats;
 //                     dprintk("%s: LAN_802_5_HISTORICAL_STATS queried.\n",dev->name);
 
@@ -642,9 +742,8 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
 #endif
 
 #ifdef CONFIG_FDDI
-       if (i2o_dev->lct_data->sub_class == I2O_LAN_FDDI)
-       {
-               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0400, -1, 
+       if (i2o_dev->lct_data->sub_class == I2O_LAN_FDDI) {
+               if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0400, -1,
                                 val64, sizeof(val64)) < 0)
                        printk("%s: Unable to query LAN_FDDI_HISTORICAL_STATS.\n",dev->name);
                else {
@@ -666,90 +765,97 @@ static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
 
        return (struct net_device_stats *)&priv->stats;
 }
+
 /*
- * i2o_lan_set_multicast_list(): Enable a network device to receive packets
- *     not send to the protocol address.
+ * i2o_lan_set_mc_list(): Enable a network device to receive packets
+ *      not send to the protocol address.
  */
-static void i2o_lan_set_multicast_list(struct net_device *dev)
+
+static void i2o_lan_set_mc_list(struct net_device *dev)
 {
-       struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
-       struct i2o_device *i2o_dev = priv->i2o_dev;
-       struct i2o_controller *iop = i2o_dev->controller;
-       u32 filter_mask;
-       u32 work32[64];
+        struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+        struct i2o_device *i2o_dev = priv->i2o_dev;
+        struct i2o_controller *iop = i2o_dev->controller;
+        u32 filter_mask;
+        u32 max_size_mc_table;
+        u32 mc_addr_group[64];
+
+        if (i2o_query_scalar(iop, i2o_dev->lct_data->tid,  0x0001, -1,
+                             &mc_addr_group, sizeof(mc_addr_group)) < 0 ) {
+                printk(KERN_WARNING "%s: Unable to query LAN_MAC_ADDRESS group.\n", dev->name);
+                return;
+        }
 
-       dprintk(KERN_INFO "%s: Entered i2o_lan_set_multicast_list().\n", dev->name);
+        max_size_mc_table = mc_addr_group[8];
 
-return;
+        if (dev->flags & IFF_PROMISC) {
+                filter_mask = 0x00000002;
+                dprintk(KERN_INFO "%s: Enabling promiscuous mode...\n", dev->name);
+        }
 
-/* FIXME: Why does the next call kill the interrupt handler?
- * The same piece of code works fine in function lan_open(), and in i2o_proc.c
- *
- * *because its trying to sleep in an irq - this must be async - Alan
- */
+        else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > max_size_mc_table) {
+                filter_mask = 0x00000004;
+                dprintk(KERN_INFO "%s: Enabling all multicast mode...\n", dev->name);
+        }
 
-       if (i2o_query_scalar(iop, i2o_dev->lct_data->tid, 0x0001, -1,
-                            &work32, sizeof(work32)) < 0) 
-       {
-               printk(KERN_WARNING "i2o_lan: Unable to query "
-                       " LAN_MAC_ADDRESS table.\n");   
-               return;
-       }
-       printk(KERN_INFO "capab mask = 0x%08X, filter mask = 0x%08X\n",
-               work32[7], work32[6]);
+        else if (dev->mc_count) {
+                struct dev_mc_list *mc;
+               u8 mc_table[2 + 8 * dev->mc_count]; // RowCount, Addresses
+               u64 *work64 = (u64 *)(mc_table + 2);
 
-       filter_mask = work32[6];
+                filter_mask = 0x00000000;
+                dprintk(KERN_INFO "%s: Enabling multicast mode...\n", dev->name);
 
-       if (dev->flags & IFF_PROMISC)
-       {
-               filter_mask |= 0x00000002; 
-               dprintk(KERN_INFO "i2o_lan: Enabling promiscuous mode...\n");
+                /* Fill multicast addr table */
+
+               memset(mc_table, 0, sizeof(mc_table));
+                memcpy(mc_table, &dev->mc_count, 2);
+                for (mc = dev->mc_list; mc ; mc = mc->next, work64++ )
+                        memcpy(work64, mc->dmi_addr, mc->dmi_addrlen);
+               
+               /* Clear old mc table, copy new table to <iop,tid> */
+
+                if (i2o_clear_table(iop, i2o_dev->lct_data->tid,  0x0002) < 0)
+                        printk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+
+                if ((i2o_row_add_table(iop, i2o_dev->lct_data->tid,  0x0002, -1,
+                        mc_table, sizeof(mc_table))) < 0)
+                        printk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
         }
-        
-       else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > work32[5])
-       {
-               filter_mask |= 0x00000000; 
-               dprintk(KERN_INFO "i2o_lan: Enabling all multicast mode...\n");
-       }
 
-        else if (dev->mc_count)
-       {       
-               struct dev_mc_list *mclist;
-               int i;
-               u8 *work8 = (u8 *)work32;
+        else { 
+                filter_mask = 0x00000300; // Broadcast, Multicast disabled
+                printk(KERN_INFO "%s: Enabling unicast mode...\n",dev->name);
+        }
 
-               dprintk(KERN_INFO "i2o_lan: Enabling multicast mode...\n");
-                filter_mask = 0x00000004; 
+       /* Finally copy new FilterMask to <iop,tid> */
 
-               /* Fill the multicast addresses */
-               mclist = dev->mc_list;
+        if (i2o_set_scalar(iop, i2o_dev->lct_data->tid,  0x0001, 3,
+                        &filter_mask, sizeof(filter_mask)) <0)
+                printk(KERN_WARNING "%s: Unable to set MAC FilterMask.\n",dev->name);
 
-               for (i = 0; i < dev->mc_count; i++)
-               {       
-                       memcpy(work8, mclist->dmi_addr, mclist->dmi_addrlen);
-                       work8 += 8;
-                       mclist = mclist->next;
-               } 
+        return;
+}
 
-               if (i2o_clear_table(iop, i2o_dev->lct_data->tid, 0x0002) < 0)
-                       dprintk("%s: Unable to clear LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
+/*
+ * i2o_lan_set_multicast_list():
+ *       Queue routine i2o_lan_set_mc_list() to be called later.
+ *       Needs to be async.
+ */
 
-               if (i2o_row_add_table(iop, i2o_dev->lct_data->tid, 0x0002, -1,
-                       work32, dev->mc_count*8) < 0)   
-                       dprintk("%s: Unable to set LAN_MULTICAST_MAC_ADDRESS table.\n",dev->name);
-       } 
-       
-       else {
-               filter_mask |= 0x00000300; // Broadcast, Multicast disabled
-               dprintk(KERN_INFO "i2o_lan: Enabling unicast mode...\n");
-        }
+static void i2o_lan_set_multicast_list(struct net_device *dev)
+{
+        struct tq_struct *task;
 
-       if (i2o_set_scalar(iop, i2o_dev->lct_data->tid, 0x0001, 3,
-                       &filter_mask, 4) < 0)
-               printk(KERN_WARNING "i2o_lan: Unable to set MAC FilterMask.\n");
+        task = (struct tq_struct *)kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
+        if (task == NULL)
+                return;
 
-       return;
+        task->next = NULL;
+        task->sync = 0;
+        task->routine = (void *)i2o_lan_set_mc_list;
+        task->data = (void *)dev;
+        queue_task(task, &tq_scheduler);
 }
 
 struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
@@ -761,24 +867,21 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
        void (*unregister_dev)(struct net_device *dev);
 
-       switch (i2o_dev->lct_data->sub_class)
-       {
+       switch (i2o_dev->lct_data->sub_class) {
        case I2O_LAN_ETHERNET:
-               dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
+               dev = init_etherdev(NULL, sizeof(struct i2o_lan_local));
                if (dev == NULL)
                        return NULL;
                type_trans = eth_type_trans;
                unregister_dev = unregister_netdev;
                break;
 
-
 #ifdef CONFIG_ANYLAN
        case I2O_LAN_100VG:
-               printk(KERN_ERR "i2o_lan: 100base VG not yet supported\n");
+               printk(KERN_ERR "i2o_lan: 100base VG not yet supported.\n");
                break;
 #endif
 
-
 #ifdef CONFIG_TR
        case I2O_LAN_TR:
                dev = init_trdev(NULL, sizeof(struct i2o_lan_local));
@@ -800,8 +903,7 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
                dev->priv = (void *)(dev + 1);
                 dev->name = (char *)(dev + 1) + sizeof(struct i2o_lan_local);
 
-               if (dev_alloc_name(dev,"fddi%d") < 0)
-               {
+               if (dev_alloc_name(dev,"fddi%d") < 0) {
                        printk(KERN_WARNING "i2o_lan: Too many FDDI devices.\n");
                        kfree(dev);
                        return NULL;
@@ -817,13 +919,13 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
 
 #ifdef CONFIG_FIBRE_CHANNEL
        case I2O_LAN_FIBRE_CHANNEL:
-               printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported\n");
+               printk(KERN_INFO "i2o_lan: Fibre Channel not yet supported.\n");
        break;
 #endif
 
        case I2O_LAN_UNKNOWN:
        default:
-               printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported\n",
+               printk(KERN_ERR "i2o_lan: LAN type 0x%08X not supported.\n",
                       i2o_dev->lct_data->sub_class);
                return NULL;
        }
@@ -838,13 +940,12 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        priv->unit = unit;
 
        if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
-                       0x0001, 0, &hw_addr, 8) < 0)
-       {
-       printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
+                            0x0001, 0, &hw_addr, sizeof(hw_addr)) < 0) {
+               printk(KERN_ERR "%s: Unable to query hardware address.\n", dev->name);
                unit--;
                unregister_dev(dev);
                kfree(dev);
-               return NULL;  
+               return NULL;
        }
 
        dprintk("%s: hwaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -854,18 +955,18 @@ struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
        dev->addr_len = 6;
        memcpy(dev->dev_addr, hw_addr, 6);
 
-   if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
-         0x0007, 2, &max_tx, 4) < 0)
-   {
-      printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
-      unit--;
-      unregister_dev(dev);
-      kfree(dev);
-         return NULL;
-   }
-   printk(KERN_INFO "%s: Max TX Outstanding = %d\n", dev->name, max_tx);
-   priv->max_tx = max_tx;
-   priv->tx_count = 0;
+       if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
+               0x0007, 2, &max_tx, sizeof(max_tx)) < 0) 
+       {
+               printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
+               unit--;
+               unregister_dev(dev);
+               kfree(dev);
+               return NULL;
+       }
+       dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, max_tx);
+       priv->max_tx = max_tx;
+       priv->tx_count = 0;
 
        priv->lock = SPIN_LOCK_UNLOCKED;
 
@@ -887,43 +988,41 @@ int __init i2o_lan_init(void)
        struct net_device *dev;
        int i;
 
-       if (i2o_install_handler(&i2o_lan_handler) < 0)
-       {
-               printk(KERN_ERR "Unable to register I2O LAN OSM.\n");
+       printk(KERN_INFO "Linux I2O LAN OSM (c) 1999 University of Helsinki.\n");
+       if (i2o_install_handler(&i2o_lan_handler) < 0) {
+               printk(KERN_ERR "i2o_lan: Unable to register I2O LAN OSM.\n");
                return -EINVAL;
-       }   
+       }
        lan_context = i2o_lan_handler.context;
        
        for(i=0; i <= MAX_LAN_CARDS; i++)
                i2o_landevs[i] = NULL;
 
-       for (i=0; i < MAX_I2O_CONTROLLERS; i++)
-       {
+       for (i=0; i < MAX_I2O_CONTROLLERS; i++) {
                struct i2o_controller *iop = i2o_find_controller(i);
                struct i2o_device *i2o_dev;
 
-               if (iop==NULL)
-                       continue;
+               if (iop==NULL) continue;
+
+               for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next) {
 
-               for (i2o_dev=iop->devices;i2o_dev != NULL;i2o_dev=i2o_dev->next)
-               {
-                       if (i2o_dev->lct_data->class_id != I2O_CLASS_LAN) 
+                       if (i2o_dev->lct_data->class_id != I2O_CLASS_LAN)
                                continue;
 
-                       if(i2o_dev->lct_data->user_tid != 0xFFF)
+                       /* Make sure device not already claimed by an ISM */
+                       if (i2o_dev->lct_data->user_tid != 0xFFF)
                                continue;
 
-                       if (unit == MAX_LAN_CARDS)
-                       {
+                       if (unit == MAX_LAN_CARDS) {
                                i2o_unlock_controller(iop);
-                               printk(KERN_WARNING "Too many I2O LAN devices.\n");
+                               printk(KERN_WARNING "i2o_lan: Too many I2O LAN devices.\n");
                                return -EINVAL;
                        }
 
                        dev = i2o_lan_register_device(i2o_dev);
-                       if (dev == NULL)
-                       {
-                               printk(KERN_ERR "Unable to register I2O LAN device\n");
+                       if (dev == NULL) {
+                               printk(KERN_ERR "i2o_lan: Unable to register I2O LAN device.\n");
                                continue; // try next one
                        }
 
@@ -947,14 +1046,12 @@ void cleanup_module(void)
 {
        int i;
 
-       for (i = 0; i <= unit; i++)
-       {
+       for (i = 0; i <= unit; i++) {
                struct net_device *dev = i2o_landevs[i];
                struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; 
                struct i2o_device *i2o_dev = priv->i2o_dev;     
 
-               switch (i2o_dev->lct_data->sub_class)
-               {
+               switch (i2o_dev->lct_data->sub_class) {
                case I2O_LAN_ETHERNET:
                        unregister_netdev(dev);
                        kfree(dev);
@@ -976,11 +1073,11 @@ void cleanup_module(void)
                               i2o_dev->lct_data->sub_class);
                }
 
-               dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n", 
+               dprintk(KERN_INFO "%s: I2O LAN device unregistered.\n",
                        dev->name);
        }
 
-        i2o_remove_handler(&i2o_lan_handler);
+       i2o_remove_handler(&i2o_lan_handler);
 }
 
 EXPORT_NO_SYMBOLS;
@@ -992,4 +1089,4 @@ MODULE_PARM(bucketpost, "i");   // Number of buckets to post
 MODULE_PARM(bucketthresh, "i"); // Bucket post threshold
 MODULE_PARM(rx_copybreak, "i");
 
-#endif    
+#endif
index 26efb34cfda6002dfa042732477e6ff4dd1f688a..7cd22e9acd2b490bf4f1a5bc96c38c9a158451db 100644 (file)
@@ -18,7 +18,7 @@
 /* Tunable parameters first */
 
 #define I2O_BUCKET_COUNT       256
-#define I2O_BUCKET_THRESH      16
+#define I2O_BUCKET_THRESH      8
 
 /* LAN types */
 #define I2O_LAN_ETHERNET       0x0030
@@ -108,5 +108,11 @@ struct i2o_bucket_descriptor {
        u32 context;                    /* FIXME: 64bit support */
        struct i2o_packet_info packet_info[1];
 };
+
+/* Event Indicator Mask Flags for LAN OSM */
+
+#define I2O_LAN_EVT_LINK_DOWN          0x01
+#define I2O_LAN_EVT_LINK_UP            0x02
+#define I2O_LAN_EVT_MEDIA_CHANGE       0x04
  
 #endif /* _I2O_LAN_H */
index 80a85ac1a0985a25ee10ff2cfd22ff96937cdf83..da3748797e97cabafacade71e35dbe779295b105 100644 (file)
@@ -5,11 +5,11 @@
  *     (C) Copyright 1999   Red Hat Software
  *     
  *     Written by Alan Cox, Building Number Three Ltd
- *     Modified by Deepak Saxena <deepak@plexity.net>
+ *     Modified by Deepak Saxena <deepak@plexity.net>
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
+ *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
  *     TODO:
@@ -120,7 +120,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
 
        if(c==NULL)
        {
-               printk(KERN_ERR "i2o_pci: insufficient memory to add controller.\n");
+               printk(KERN_ERR "i2o: Insufficient memory to add controller.\n");
                return -ENOMEM;
        }
        memset(c, 0, sizeof(*c));
@@ -137,7 +137,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
        
        if(i==6)
        {
-               printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n");
+               printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
                kfree(c);
                return -EINVAL;
        }
@@ -145,11 +145,11 @@ int __init i2o_pci_install(struct pci_dev *dev)
        size = dev->resource[i].end-dev->resource[i].start+1;   
        /* Map the I2O controller */
        
-       printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+       printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
        mem = ioremap(memptr, size);
        if(mem==NULL)
        {
-               printk(KERN_ERR "i2o_pci: Unable to map controller.\n");
+               printk(KERN_ERR "i2o: Unable to map controller.\n");
                kfree(c);
                return -EINVAL;
        }
@@ -189,7 +189,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
        
        if(i<0)
        {
-               printk(KERN_ERR "i2o: unable to install controller.\n");
+               printk(KERN_ERR "i2o: Unable to install controller.\n");
                kfree(c);
                iounmap(mem);
                return i;
@@ -216,7 +216,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
                }
        }
 
-       printk(KERN_INFO "Installed iop%d at IRQ%d\n", c->unit, dev->irq);
+       printk(KERN_INFO "%s: Installed at IRQ%d\n", c->name, dev->irq);
        I2O_IRQ_WRITE32(c,0x0);
        c->enabled = 1;
        return 0;       
@@ -227,7 +227,7 @@ int __init i2o_pci_scan(void)
        struct pci_dev *dev;
        int count=0;
        
-       printk(KERN_INFO "Checking for PCI I2O controllers...\n");
+       printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
        
        for(dev=pci_devices; dev!=NULL; dev=dev->next)
        {
@@ -235,17 +235,17 @@ int __init i2o_pci_scan(void)
                        continue;
                if((dev->class&0xFF)>1)
                {
-                       printk(KERN_INFO "I2O controller found but does not support I2O 1.5 (skipping).\n");
+                       printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
                        continue;
                }
-               printk(KERN_INFO "I2O controller on bus %d at %d.\n",
+               printk(KERN_INFO "i2o: I2O controller on bus %d at %d.\n",
                        dev->bus->number, dev->devfn);
                pci_set_master(dev);
                if(i2o_pci_install(dev)==0)
                        count++;
        }
        if(count)
-               printk(KERN_INFO "%d I2O controller%s found and installed.\n", count,
+               printk(KERN_INFO "i2o: %d I2O controller%s found and installed.\n", count,
                        count==1?"":"s");
        return count?count:-ENODEV;
 }
@@ -270,7 +270,7 @@ static void i2o_pci_activate(i2o_controller * c)
                if(i2o_activate_controller(c))
 #endif /* MODULE */
                {
-                       printk("I2O: Failed to initialize iop%d\n", c->unit);
+                       printk("%s: Failed to initialize.\n", c->name);
 #ifdef MODULE
                        core->unlock(c);
                        core->delete(c);
index 4059a518951792094857cb7157b8bbc3d59f94d1..2636b089d08a387565aff50a5cb95521014277a4 100644 (file)
@@ -51,9 +51,6 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
-
-#include "i2o_proc.h"
-
 #include "i2o_lan.h"
 
 /*
@@ -69,24 +66,34 @@ typedef struct _i2o_proc_entry_t
 
 static int proc_context = 0;
 
-
 static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_stat(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
+
 static int i2o_proc_read_hw(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_dst(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_ddm_table(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_ds(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_driver_store(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_drivers_stored(char *, char **, off_t, int, int *, void *);
+
 static int i2o_proc_read_groups(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_phys_device(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_claimed(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_users(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_priv_msgs(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_dev(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_authorized_users(char *, char **, off_t, int, int *, void *);
+
 static int i2o_proc_read_dev_name(char *, char **, off_t, int, int *, void *);
-static int i2o_proc_read_ddm(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_dev_identity(char *, char **, off_t, int, int *, void *);
+static int i2o_proc_read_ddm_identity(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_uinfo(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_sgl_limits(char *, char **, off_t, int, int *, void *);
+
+static int i2o_proc_read_sensors(char *, char **, off_t, int, int *, void *);
+
 static int print_serial_number(char *, int, u8 *, int);
-static int i2o_proc_create_entries(void *, 
-                                  i2o_proc_entry *, struct proc_dir_entry *);
+
+static int i2o_proc_create_entries(void *, i2o_proc_entry *,
+                                  struct proc_dir_entry *);
 static void i2o_proc_remove_entries(i2o_proc_entry *, struct proc_dir_entry *);
 static int i2o_proc_add_controller(struct i2o_controller *, 
                                   struct proc_dir_entry * );
@@ -117,18 +124,8 @@ static int i2o_proc_read_lan_rx_info(char *, char **, off_t, int, int *,
                                     void *);
 static int i2o_proc_read_lan_hist_stats(char *, char **, off_t, int, int *,
                                        void *);
-static int i2o_proc_read_lan_supp_opt_stats(char *, char **, off_t, int, int *,
-                                           void *);
-static int i2o_proc_read_lan_opt_tx_hist_stats(char *, char **, off_t, int,
-                                              int *, void *);
-static int i2o_proc_read_lan_opt_rx_hist_stats(char *, char **, off_t, int,
-                                              int *, void *);
 static int i2o_proc_read_lan_eth_stats(char *, char **, off_t, int,
                                       int *, void *);
-static int i2o_proc_read_lan_supp_eth_stats(char *, char **, off_t, int, int *,
-                                           void *);
-static int i2o_proc_read_lan_opt_eth_stats(char *, char **, off_t, int, int *,
-                                          void *);
 static int i2o_proc_read_lan_tr_stats(char *, char **, off_t, int, int *,
                                      void *);
 static int i2o_proc_read_lan_fddi_stats(char *, char **, off_t, int, int *,
@@ -155,11 +152,11 @@ static i2o_proc_entry generic_iop_entries[] =
 {
        {"hrt", S_IFREG|S_IRUGO, i2o_proc_read_hrt, NULL},
        {"lct", S_IFREG|S_IRUGO, i2o_proc_read_lct, NULL},
-       {"stat", S_IFREG|S_IRUGO, i2o_proc_read_stat, NULL},
+       {"status", S_IFREG|S_IRUGO, i2o_proc_read_status, NULL},
        {"hw", S_IFREG|S_IRUGO, i2o_proc_read_hw, NULL},
-       {"dst", S_IFREG|S_IRUGO, i2o_proc_read_dst, NULL},
        {"ddm_table", S_IFREG|S_IRUGO, i2o_proc_read_ddm_table, NULL},
-       {"ds", S_IFREG|S_IRUGO, i2o_proc_read_ds, NULL},
+       {"driver_store", S_IFREG|S_IRUGO, i2o_proc_read_driver_store, NULL},
+       {"drivers_stored", S_IFREG|S_IRUGO, i2o_proc_read_drivers_stored, NULL},
        {NULL, 0, NULL, NULL}
 };
 
@@ -169,11 +166,16 @@ static i2o_proc_entry generic_iop_entries[] =
 static i2o_proc_entry generic_dev_entries[] = 
 {
        {"groups", S_IFREG|S_IRUGO, i2o_proc_read_groups, NULL},
+       {"phys_dev", S_IFREG|S_IRUGO, i2o_proc_read_phys_device, NULL},
+       {"claimed", S_IFREG|S_IRUGO, i2o_proc_read_claimed, NULL},
+       {"users", S_IFREG|S_IRUGO, i2o_proc_read_users, NULL},
        {"priv_msgs", S_IFREG|S_IRUGO, i2o_proc_read_priv_msgs, NULL},
-       {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev, NULL},
-       {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm, NULL},
-       {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
+       {"authorized_users", S_IFREG|S_IRUGO, i2o_proc_read_authorized_users, NULL},
+       {"dev_identity", S_IFREG|S_IRUGO, i2o_proc_read_dev_identity, NULL},
+       {"ddm_identity", S_IFREG|S_IRUGO, i2o_proc_read_ddm_identity, NULL},
        {"user_info", S_IFREG|S_IRUGO, i2o_proc_read_uinfo, NULL},
+       {"sgl_limits", S_IFREG|S_IRUGO, i2o_proc_read_sgl_limits, NULL},
+       {"sensors", S_IFREG|S_IRUGO, i2o_proc_read_sensors, NULL},
        {NULL, 0, NULL, NULL}
 };
 
@@ -187,22 +189,22 @@ static i2o_proc_entry rbs_dev_entries[] =
 };
 
 #define SCSI_TABLE_SIZE        13
-       static char *scsi_devices[] = 
-               {
-                       "Direct-Access Read/Write",
-                       "Sequential-Access Storage",
-                       "Printer",
-                       "Processor",
-                       "WORM Device",
-                       "CD-ROM Device",
-                       "Scanner Device",
-                       "Optical Memory Device",
-                       "Medium Changer Device",
-                       "Communications Device",
-                       "Graphics Art Pre-Press Device",
-                       "Graphics Art Pre-Press Device",
-                       "Array Controller Device"
-               };
+static char *scsi_devices[] = 
+{
+       "Direct-Access Read/Write",
+       "Sequential-Access Storage",
+       "Printer",
+       "Processor",
+       "WORM Device",
+       "CD-ROM Device",
+       "Scanner Device",
+       "Optical Memory Device",
+       "Medium Changer Device",
+       "Communications Device",
+       "Graphics Art Pre-Press Device",
+       "Graphics Art Pre-Press Device",
+       "Array Controller Device"
+};
 
 /* private */
 
@@ -214,7 +216,6 @@ static i2o_proc_entry rbs_dev_entries[] =
  */
 static i2o_proc_entry lan_entries[] = 
 {
-       /* LAN param groups 0000h-0008h */
        {"lan_dev_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_dev_info, NULL},
        {"lan_mac_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_mac_addr, NULL},
        {"lan_mcast_addr", S_IFREG|S_IRUGO|S_IWUSR,
@@ -227,56 +228,30 @@ static i2o_proc_entry lan_entries[] =
        {"lan_alt_addr", S_IFREG|S_IRUGO, i2o_proc_read_lan_alt_addr, NULL},
        {"lan_tx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_tx_info, NULL},
        {"lan_rx_info", S_IFREG|S_IRUGO, i2o_proc_read_lan_rx_info, NULL},
-       /* LAN param groups 0100h, 0180h, 0182h, 0183h */
-       {"lan_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
-       {"lan_supp_opt_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_supp_opt_stats, NULL},
-       {"lan_opt_tx_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_opt_tx_hist_stats, NULL},
-       {"lan_opt_rx_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_opt_rx_hist_stats, NULL},
-       /* TODO: LAN param group 0184h */
+
+       {"lan_hist_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_hist_stats, NULL},
        {NULL, 0, NULL, NULL}
 };
 
 /*
- * Ethernet specific LAN entries
+ * Port specific LAN entries
  * 
  */
 static i2o_proc_entry lan_eth_entries[] = 
 {
-       /* LAN param groups 0200h, 0280h, 0281h */
-       {"lan_eth_stat", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
-        {"lan_supp_eth_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_supp_eth_stats, NULL},
-        {"lan_opt_eth_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_opt_eth_stats, NULL},
+       {"lan_eth_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_eth_stats, NULL},
        {NULL, 0, NULL, NULL}
 };
 
-/*
- * Token Ring specific LAN entries
- * 
- */
 static i2o_proc_entry lan_tr_entries[] = 
 {
-       /* LAN param group 0300h */
-       {"lan_tr_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_tr_stats, NULL},
-       /* TODO: LAN param group 0380h, 0381h */
+       {"lan_tr_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_tr_stats, NULL},
        {NULL, 0, NULL, NULL}
 };
 
-/*
- * FDDI specific LAN entries
- * 
- */
 static i2o_proc_entry lan_fddi_entries[] = 
 {
-       /* LAN param group 0400h */
-       {"lan_fddi_stats", S_IFREG|S_IRUGO,
-        i2o_proc_read_lan_fddi_stats, NULL},
-       /* TODO: LAN param group 0480h, 0481h */
+       {"lan_fddi_stats", S_IFREG|S_IRUGO, i2o_proc_read_lan_fddi_stats, NULL},
        {NULL, 0, NULL, NULL}
 };
 
@@ -290,6 +265,22 @@ static char *chtostr(u8 *chars, int n)
         return strncat(tmp, (char *)chars, n);
 }
 
+static int i2o_report_query_status(char *buf, int block_status, char *group)
+{
+       switch (block_status)
+       {
+       case -ETIMEDOUT:
+               return sprintf(buf, "Timeout reading group %s.\n",group);
+       case -ENOMEM:
+               return sprintf(buf, "No free memory to read the table.\n");
+       case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
+               return sprintf(buf, "Group %s not supported.\n", group);
+       default:
+               return sprintf(buf, "Error reading group %s. BlockStatus 0x%02X\n",
+                              group, -block_status);
+       }
+}
+
 static char* bus_strings[] = 
 { 
        "Local Bus", 
@@ -314,7 +305,7 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
                      int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller *)data;
-       pi2o_hrt hrt = (pi2o_hrt)c->hrt;
+       i2o_hrt *hrt = (i2o_hrt *)c->hrt;
        u32 bus;
        int count;
        int i;
@@ -342,17 +333,15 @@ int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len,
        }
        
        len += sprintf(buf+len, "HRT has %d entries of %d bytes each.\n",
-                      count, hrt->entry_len);
+                      count, hrt->entry_len << 2);
 
        for(i = 0; i < count; i++)
        {
                len += sprintf(buf+len, "Entry %d:\n", i);
                len += sprintf(buf+len, "   Adapter ID: %0#10x\n", 
                                        hrt->hrt_entry[i].adapter_id);
-               len += sprintf(buf+len, "   Controlled by: %0#6x\n",
+               len += sprintf(buf+len, "   Controlling tid: %0#6x\n",
                                        hrt->hrt_entry[i].parent_tid);
-               len += sprintf(buf+len, "   Bus#%d\n", 
-                                       hrt->hrt_entry[i].bus_num);
 
                if(hrt->hrt_entry[i].bus_type != 0x80)
                {
@@ -425,20 +414,19 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
        int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller*)data;
-       pi2o_lct lct = (pi2o_lct)c->lct;
+       i2o_lct *lct = (i2o_lct *)c->lct;
        int entries;
        int i;
 
 #define BUS_TABLE_SIZE 3
        static char *bus_ports[] =
-               {
-                       "Generic Bus",
-                       "SCSI Bus",
-                       "Fibre Channel Bus"
-               };
+       {
+               "Generic Bus",
+               "SCSI Bus",
+               "Fibre Channel Bus"
+       };
 
        spin_lock(&i2o_proc_lock);
-
        len = 0;
 
        entries = (lct->table_size - 3)/9;
@@ -451,8 +439,7 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
        for(i = 0; i < entries; i++)
        {
                len += sprintf(buf+len, "Entry %d\n", i);
-
-               len += sprintf(buf+len, "  %s", i2o_get_class_name(lct->lct_entry[i].class_id));
+               len += sprintf(buf+len, "  Class, SubClass  : %s", i2o_get_class_name(lct->lct_entry[i].class_id));
        
                /*
                 *      Classes which we'll print subclass info for
@@ -463,23 +450,23 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
                                switch(lct->lct_entry[i].sub_class)
                                {
                                        case 0x00:
-                                               len += sprintf(buf+len, ": Direct-Access Read/Write");
+                                               len += sprintf(buf+len, ", Direct-Access Read/Write");
                                                break;
 
                                        case 0x04:
-                                               len += sprintf(buf+len, ": WORM Drive");
+                                               len += sprintf(buf+len, ", WORM Drive");
                                                break;
        
                                        case 0x05:
-                                               len += sprintf(buf+len, ": CD-ROM Drive");
+                                               len += sprintf(buf+len, ", CD-ROM Drive");
                                                break;
 
                                        case 0x07:
-                                               len += sprintf(buf+len, ": Optical Memory Device");
+                                               len += sprintf(buf+len, ", Optical Memory Device");
                                                break;
 
                                        default:
-                                               len += sprintf(buf+len, ": Unknown (0x%02x)",
+                                               len += sprintf(buf+len, ", Unknown (0x%02x)",
                                                               lct->lct_entry[i].sub_class);
                                                break;
                                }
@@ -489,27 +476,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
                                switch(lct->lct_entry[i].sub_class & 0xFF)
                                {
                                        case 0x30:
-                                               len += sprintf(buf+len, ": Ethernet");
+                                               len += sprintf(buf+len, ", Ethernet");
                                                break;
 
                                        case 0x40:
-                                               len += sprintf(buf+len, ": 100base VG");
+                                               len += sprintf(buf+len, ", 100base VG");
                                                break;
 
                                        case 0x50:
-                                               len += sprintf(buf+len, ": IEEE 802.5/Token-Ring");
+                                               len += sprintf(buf+len, ", IEEE 802.5/Token-Ring");
                                                break;
 
                                        case 0x60:
-                                               len += sprintf(buf+len, ": ANSI X3T9.5 FDDI");
+                                               len += sprintf(buf+len, ", ANSI X3T9.5 FDDI");
                                                break;
                
                                        case 0x70:
-                                               len += sprintf(buf+len, ": Fibre Channel");
+                                               len += sprintf(buf+len, ", Fibre Channel");
                                                break;
 
                                        default:
-                                               len += sprintf(buf+len, ": Unknown Sub-Class (0x%02x)",
+                                               len += sprintf(buf+len, ", Unknown Sub-Class (0x%02x)",
                                                               lct->lct_entry[i].sub_class & 0xFF);
                                                break;
                                }
@@ -517,27 +504,27 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
 
                        case I2O_CLASS_SCSI_PERIPHERAL:
                                if(lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
-                                       len += sprintf(buf+len, ": %s", 
+                                       len += sprintf(buf+len, ", %s", 
                                                                scsi_devices[lct->lct_entry[i].sub_class]);
                                else
-                                       len += sprintf(buf+len, ": Unknown Device Type");
+                                       len += sprintf(buf+len, ", Unknown Device Type");
                                break;
 
                        case I2O_CLASS_BUS_ADAPTER_PORT:
                                if(lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
-                                       len += sprintf(buf+len, ": %s", 
+                                       len += sprintf(buf+len, ", %s", 
                                                                bus_ports[lct->lct_entry[i].sub_class]);
                                else
-                                       len += sprintf(buf+len, ": Unknown Bus Type");
+                                       len += sprintf(buf+len, ", Unknown Bus Type");
                                break;
                }
                len += sprintf(buf+len, "\n");
                
-               len += sprintf(buf+len, "  Local TID: 0x%03x\n", lct->lct_entry[i].tid);
-               len += sprintf(buf+len, "  User TID: 0x%03x\n", lct->lct_entry[i].user_tid);
-               len += sprintf(buf+len, "  Parent TID: 0x%03x\n", 
+               len += sprintf(buf+len, "  Local TID        : 0x%03x\n", lct->lct_entry[i].tid);
+               len += sprintf(buf+len, "  User TID         : 0x%03x\n", lct->lct_entry[i].user_tid);
+               len += sprintf(buf+len, "  Parent TID       : 0x%03x\n", 
                                        lct->lct_entry[i].parent_tid);
-               len += sprintf(buf+len, "  Identity Tag: 0x%x%x%x%x%x%x%x%x\n",
+               len += sprintf(buf+len, "  Identity Tag     : 0x%x%x%x%x%x%x%x%x\n",
                                        lct->lct_entry[i].identity_tag[0],
                                        lct->lct_entry[i].identity_tag[1],
                                        lct->lct_entry[i].identity_tag[2],
@@ -546,219 +533,211 @@ int i2o_proc_read_lct(char *buf, char **start, off_t offset, int len,
                                        lct->lct_entry[i].identity_tag[5],
                                        lct->lct_entry[i].identity_tag[6],
                                        lct->lct_entry[i].identity_tag[7]);
-               len += sprintf(buf+len, "  Change Indicator: %0#10x\n", 
+               len += sprintf(buf+len, "  Change Indicator : %0#10x\n", 
                                lct->lct_entry[i].change_ind);
-               len += sprintf(buf+len, "  Device Flags: %0#10x\n", 
+               len += sprintf(buf+len, "  Event Capab Mask : %0#10x\n", 
                                lct->lct_entry[i].device_flags);
        }
 
        spin_unlock(&i2o_proc_lock);
-       
        return len;
 }
 
-int i2o_proc_read_stat(char *buf, char **start, off_t offset, int len, 
-       int *eof, void *data)
+int i2o_proc_read_status(char *buf, char **start, off_t offset, int len, 
+                        int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller*)data;
-       u32 *msg;
-       u32 m;
-       u8 *workspace;
-       u16 *work16;
-       u32 *work32;
-       long time;
        char prodstr[25];
        int version;
        
        spin_lock(&i2o_proc_lock);
-
        len = 0;
 
-       workspace = (u8*)kmalloc(88, GFP_KERNEL);
-       if(!workspace)
-       {
-               len += sprintf(buf, "No memory for status transfer\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
-       }
-
-       m = I2O_POST_READ32(c);
-       if(m == 0xFFFFFFFF)
-       {
-               len += sprintf(buf, "Could not get inbound message frame from IOP!\n"); 
-               kfree(workspace);
-               spin_unlock(&i2o_proc_lock);
-               return len;
-       }
-       
-       msg = (u32 *)(m+c->mem_offset);
-
-       memset(workspace, 0, 88);
-       work32 = (u32*)workspace;
-       work16 = (u16*)workspace;
-
-       msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
-       msg[1] = I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
-       msg[2] = msg[3] = msg[4] = msg[5] = 0;
-       msg[6] = virt_to_phys(workspace);
-       msg[7] = 0; /* FIXME: 64-bit */
-       msg[8] = 88;
-
-       /* 
-        * hmm...i2o_post_message should just take ptr to message, and 
-        * determine offset on it's own...less work for OSM developers
-        */
-       i2o_post_message(c, m);
-
-       time = jiffies;
-
-       while(workspace[87] != 0xFF)
-       {
-               if(jiffies-time >= 2*HZ)
-               {
-                       len += sprintf(buf, "Timeout waiting for status reply\n");
-                       kfree(workspace);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
-               schedule();
-               barrier();
-       }
+       i2o_status_get(c); // reread the status block
 
-       len += sprintf(buf+len, "Organization ID: %0#6x\n", work16[0]);
+       len += sprintf(buf+len,"Organization ID        : %0#6x\n", 
+                               c->status_block->org_id);
 
-       version = workspace[9]&0xF0>>4;
-       if(version == 0x02) {
-               len += sprintf(buf+len, "Lowest I2O version supported: ");
+       version = c->status_block->i2o_version;
+       
+/* FIXME for Spec 2.0
+       if (version == 0x02) {
+               len += sprintf(buf+len,"Lowest I2O version supported: ");
                switch(workspace[2]) {
-               case 0x00:
-                       len += sprintf(buf+len, "1.0\n");
-                       break;
-               case 0x01:
-                       len += sprintf(buf+len, "1.5\n");
-                       break;
-               case 0x02:
-                       len += sprintf(buf+len, "2.0\n");
-                       break;
+                       case 0x00:
+                               len += sprintf(buf+len,"1.0\n");
+                               break;
+                       case 0x01:
+                               len += sprintf(buf+len,"1.5\n");
+                               break;
+                       case 0x02:
+                               len += sprintf(buf+len,"2.0\n");
+                               break;
                }
 
                len += sprintf(buf+len, "Highest I2O version supported: ");
                switch(workspace[3]) {
+                       case 0x00:
+                               len += sprintf(buf+len,"1.0\n");
+                               break;
+                       case 0x01:
+                               len += sprintf(buf+len,"1.5\n");
+                               break;
+                       case 0x02:
+                               len += sprintf(buf+len,"2.0\n");
+                               break;
+               }
+       }
+*/
+       len += sprintf(buf+len,"IOP ID                 : %0#5x\n", 
+                               c->status_block->iop_id);
+       len += sprintf(buf+len,"Host Unit ID           : %0#6x\n",
+                               c->status_block->host_unit_id);
+       len += sprintf(buf+len,"Segment Number         : %0#5x\n",
+                               c->status_block->segment_number);
+
+       len += sprintf(buf+len, "I2O version            : ");
+       switch (version) {
                case 0x00:
-                       len += sprintf(buf+len, "1.0\n");
+                       len += sprintf(buf+len,"1.0\n");
                        break;
                case 0x01:
-                       len += sprintf(buf+len, "1.5\n");
+                       len += sprintf(buf+len,"1.5\n");
                        break;
                case 0x02:
-                       len += sprintf(buf+len, "2.0\n");
+                       len += sprintf(buf+len,"2.0\n");
                        break;
-               }
-       }
-
-       len += sprintf(buf+len, "IOP ID: %0#5x\n", work16[2]&0xFFF);
-       len += sprintf(buf+len, "Host Unit ID: %0#6x\n", work16[3]);
-       len += sprintf(buf+len, "Segment Number: %0#5x\n", work16[4]&0XFFF);
-
-       len += sprintf(buf+len, "I2O version: ");
-       switch(version)
-       {
-       case 0x00:
-               len += sprintf(buf+len, "1.0\n");
-               break;
-       case 0x01:
-               len += sprintf(buf+len, "1.5\n");
-               break;
-       case 0x02:
-               len += sprintf(buf+len, "2.0\n");
-               break;
-       default:
-               len += sprintf(buf+len, "Unknown version\n");
+               default:
+                       len += sprintf(buf+len,"Unknown version\n");
        }
 
-       len += sprintf(buf+len, "IOP State: ");
-       switch(workspace[10])
-       {
+       len += sprintf(buf+len, "IOP State              : ");
+       switch (c->status_block->iop_state) {
                case 0x01:
-                       len += sprintf(buf+len, "Init\n");
+                       len += sprintf(buf+len,"INIT\n");
                        break;
 
                case 0x02:
-                       len += sprintf(buf+len, "Reset\n");
+                       len += sprintf(buf+len,"RESET\n");
                        break;
 
                case 0x04:
-                       len += sprintf(buf+len, "Hold\n");
+                       len += sprintf(buf+len,"HOLD\n");
                        break;
 
                case 0x05:
-                       len += sprintf(buf+len, "Hold\n");
+                       len += sprintf(buf+len,"READY\n");
                        break;
 
                case 0x08:
-                       len += sprintf(buf+len, "Operational\n");
+                       len += sprintf(buf+len,"OPERATIONAL\n");
                        break;
 
                case 0x10:
-                       len += sprintf(buf+len, "FAILED\n");
+                       len += sprintf(buf+len,"FAILED\n");
                        break;
 
                case 0x11:
-                       len += sprintf(buf+len, "FAULTED\n");
+                       len += sprintf(buf+len,"FAULTED\n");
                        break;
 
                default:
-                       len += sprintf(buf+len, "Unknown\n");
+                       len += sprintf(buf+len,"Unknown\n");
                        break;
        }
 
-       /* 0x00 is the only type supported w/spec 1.5 */
-       /* Added 2.0 types */
-       len += sprintf(buf+len, "Messenger Type: ");
-       switch (workspace[11])
-       {
-       case 0x00:
-               len += sprintf(buf+len, "Memory mapped\n");
-               break;
-       case 0x01:
-               len += sprintf(buf+len, "Memory mapped only\n");
-               break;
-       case 0x02:
-               len += sprintf(buf+len, "Remote only\n");
-               break;
-       case 0x03:
-               len += sprintf(buf+len, "Memory mapped and remote\n");
-               break;
-       default:
-               len += sprintf(buf+len, "Unknown\n");
-               break;
+       len += sprintf(buf+len,"Messenger Type         : ");
+       switch (c->status_block->msg_type) { 
+               case 0x00:
+                       len += sprintf(buf+len,"Memory mapped\n");
+                       break;
+               case 0x01:
+                       len += sprintf(buf+len,"Memory mapped only\n");
+                       break;
+               case 0x02:
+                       len += sprintf(buf+len,"Remote only\n");
+                       break;
+               case 0x03:
+                       len += sprintf(buf+len,"Memory mapped and remote\n");
+                       break;
+               default:
+                       len += sprintf(buf+len,"Unknown\n");
        }
-       len += sprintf(buf+len, "Inbound Frame Size: %d bytes\n", work16[6]*4);
-       len += sprintf(buf+len, "Max Inbound Frames: %d\n", work32[4]);
-       len += sprintf(buf+len, "Current Inbound Frames: %d\n", work32[5]);
-       len += sprintf(buf+len, "Max Outbound Frames: %d\n", work32[6]);
+
+       len += sprintf(buf+len,"Inbound Frame Size     : %d bytes\n", 
+                               c->status_block->inbound_frame_size<<2);
+       len += sprintf(buf+len,"Max Inbound Frames     : %d\n", 
+                               c->status_block->max_inbound_frames);
+       len += sprintf(buf+len,"Current Inbound Frames : %d\n", 
+                               c->status_block->cur_inbound_frames);
+       len += sprintf(buf+len,"Max Outbound Frames    : %d\n", 
+                               c->status_block->max_outbound_frames);
 
        /* Spec doesn't say if NULL terminated or not... */
-       memcpy(prodstr, work32+7, 24);
+       memcpy(prodstr, c->status_block->product_id, 24);
        prodstr[24] = '\0';
-       len += sprintf(buf+len, "Product ID: %s\n", prodstr);
-
-       len += sprintf(buf+len, "LCT Size: %d\n", work32[13]);
-
-       len += sprintf(buf+len, "Desired private memory space: %d kB\n", 
-                                               work32[15]>>10);
-       len += sprintf(buf+len, "Allocated private memory space: %d kB\n", 
-                                               work32[16]>>10);
-       len += sprintf(buf+len, "Private memory base address: %0#10x\n", 
-                                               work32[17]);
-       len += sprintf(buf+len, "Desired private I/O space: %d kB\n", 
-                                               work32[18]>>10);
-       len += sprintf(buf+len, "Allocated private I/O space: %d kB\n", 
-                                               work32[19]>>10);
-       len += sprintf(buf+len, "Private I/O base address: %0#10x\n", 
-                                               work32[20]);
-
-       kfree(workspace);
+       len += sprintf(buf+len,"Product ID             : %s\n", prodstr);
+       len += sprintf(buf+len,"Expected LCT Size      : %d bytes\n", 
+                               c->status_block->expected_lct_size);
+
+       len += sprintf(buf+len,"IOP Capabilities\n");
+       len += sprintf(buf+len,"   Context Field Size Support : ");
+       switch (c->status_block->iop_capabilities & 0x0000003) {
+               case 0:
+                       len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+                       break;
+               case 1:
+                       len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+                       break;
+               case 2:
+                       len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields, "
+                                               "but not concurrently\n");
+                       break;
+               case 3:
+                       len += sprintf(buf+len,"Supports 32-bit and 64-bit context fields "
+                                               "concurrently\n");
+                       break;
+               default:
+                       len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
+       }
+       len += sprintf(buf+len,"   Current Context Field Size : ");
+       switch (c->status_block->iop_capabilities & 0x0000000C) {
+               case 0:
+                       len += sprintf(buf+len,"not configured\n");
+                       break;
+               case 4:
+                       len += sprintf(buf+len,"Supports only 32-bit context fields\n");
+                       break;
+               case 8:
+                       len += sprintf(buf+len,"Supports only 64-bit context fields\n");
+                       break;
+               case 12:
+                       len += sprintf(buf+len,"Supports both 32-bit or 64-bit context fields "
+                                               "concurrently\n");
+                       break;
+               default:
+                       len += sprintf(buf+len,"\n");
+       }
+       len += sprintf(buf+len,"   Inbound Peer Support       : %s\n",
+                       (c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
+       len += sprintf(buf+len,"   Outbound Peer Support      : %s\n",
+                       (c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
+       len += sprintf(buf+len,"   Peer to Peer Support       : %s\n",
+                       (c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
+
+       len += sprintf(buf+len, "Desired private memory size   : %d kB\n", 
+                               c->status_block->desired_mem_size>>10);
+       len += sprintf(buf+len, "Allocated private memory size : %d kB\n", 
+                               c->status_block->current_mem_size>>10);
+       len += sprintf(buf+len, "Private memory base address   : %0#10x\n", 
+                               c->status_block->current_mem_base);
+       len += sprintf(buf+len, "Desired private I/O size      : %d kB\n", 
+                               c->status_block->desired_io_size>>10);
+       len += sprintf(buf+len, "Allocated private I/O size    : %d kB\n", 
+                               c->status_block->current_io_size>>10);
+       len += sprintf(buf+len, "Private I/O base address      : %0#10x\n", 
+                               c->status_block->current_io_base);
+
        spin_unlock(&i2o_proc_lock);
 
        return len;
@@ -790,25 +769,25 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
 
        len = 0;
 
-       token = i2o_query_scalar(c, ADAPTER_TID,
-                                       0,              // ParamGroup 0x0000h
-                                       -1,             // all fields
-                                       &work32,
-                                       sizeof(work32));
+       token = i2o_query_scalar(c, ADAPTER_TID, 0x0000, -1, &work32, sizeof(work32));
 
-       if(token < 0)
-       {
-               len += sprintf(buf, "Error waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0000 IOP Hardware");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf, "IOP Hardware Information Table (group = 0x0000)\n");
-
-       len += sprintf(buf+len, "I2O Vendor ID        : %0#6x\n", work16[0]);
-       len += sprintf(buf+len, "Product ID           : %0#6x\n", work16[1]);
-       len += sprintf(buf+len, "RAM                  : %dkB\n", work32[1]>>10);
-       len += sprintf(buf+len, "Non-Volatile Storage : %dkB\n", work32[2]>>10);
+       len += sprintf(buf+len, "I2O Vendor ID    : %0#6x\n", work16[0]);
+       len += sprintf(buf+len, "Product ID       : %0#6x\n", work16[1]);
+       len += sprintf(buf+len, "CPU              : ");
+       if(work8[16] > 8)
+               len += sprintf(buf+len, "Unknown\n");
+       else
+               len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]);
+       /* Anyone using ProcessorVersion? */
+       
+       len += sprintf(buf+len, "RAM              : %dkB\n", work32[1]>>10);
+       len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10);
 
        hwcap = work32[3];
        len += sprintf(buf+len, "Capabilities :\n");
@@ -823,13 +802,6 @@ int i2o_proc_read_hw(char *buf, char **start, off_t offset, int len,
        if(hwcap&0x00000010)
                len += sprintf(buf+len, "   Battery-backed RAM\n");
 
-       len += sprintf(buf+len, "CPU                 : ");
-       if(work8[16] > 8)
-               len += sprintf(buf+len, "Unknown\n");
-       else
-               len += sprintf(buf+len, "%s\n", cpu_table[work8[16]]);
-       /* Anyone using ProcessorVersion? */
-       
        spin_unlock(&i2o_proc_lock);
 
        return len;
@@ -850,11 +822,10 @@ int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len,
                u8  reserved;
                u16 i2o_vendor_id;
                u16 module_id;
-               u8  module_name[24];
-               u8  module_version[4];
+               u8  module_name_version[28];
                u32 data_size;
                u32 code_size;
-       } i2o_exec_execute_ddm_table, *pi2o_exec_execute_ddm_table;
+       } i2o_exec_execute_ddm_table;
 
        struct
        {
@@ -879,27 +850,13 @@ int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len,
                                NULL, 0,
                                &result, sizeof(result));
 
-       if (token<0)
-               switch (token)
-               {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading group. BlockStatus %d\n",
-                                      token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0003 Executing DDM List");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       len += sprintf(buf+len, "Tid   Type            Vendor Id     Name                     Vrs  Data_size Code_size\n");
+       len += sprintf(buf+len, "Tid   Module_type     Vendor Mod_id  Module_name             Vrs  Data_size Code_size\n");
        ddm_table=result.ddm_table[0];
 
        for(i=0; i < result.row_count; ddm_table=result.ddm_table[++i])
@@ -918,11 +875,10 @@ int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len,
                        len += sprintf(buf+len, "                ");
                }
 
-               len += sprintf(buf+len, "%0#7x", ddm_table.i2o_vendor_id);
-               len += sprintf(buf+len, "%0#7x", ddm_table.module_id);
-               len += sprintf(buf+len, "%-25s", chtostr(ddm_table.module_name, 24));
-               len += sprintf(buf+len, "%-6s", chtostr(ddm_table.module_version,4));
-               len += sprintf(buf+len, "%8d  ", ddm_table.data_size);
+               len += sprintf(buf+len, "%-#7x", ddm_table.i2o_vendor_id);
+               len += sprintf(buf+len, "%-#8x", ddm_table.module_id);
+               len += sprintf(buf+len, "%-29s", chtostr(ddm_table.module_name_version, 28));
+               len += sprintf(buf+len, "%9d  ", ddm_table.data_size);
                len += sprintf(buf+len, "%8d", ddm_table.code_size);
 
                len += sprintf(buf+len, "\n");
@@ -935,20 +891,20 @@ int i2o_proc_read_ddm_table(char *buf, char **start, off_t offset, int len,
 
 
 /* Executive group 0004h - Driver Store (scalar) */
-int i2o_proc_read_ds(char *buf, char **start, off_t offset, int len, 
+int i2o_proc_read_driver_store(char *buf, char **start, off_t offset, int len, 
                     int *eof, void *data)
 {
        struct i2o_controller *c = (struct i2o_controller*)data;
        u32 work32[8];
+       int token;
 
        spin_lock(&i2o_proc_lock);
 
        len = 0;
 
-       if(i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32,
-               sizeof(work32)) < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       token = i2o_query_scalar(c, ADAPTER_TID, 0x0004, -1, &work32, sizeof(work32));
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0004 Driver Store");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -966,8 +922,8 @@ int i2o_proc_read_ds(char *buf, char **start, off_t offset, int len,
 
 
 /* Executive group 0005h - Driver Store Table (table) */
-int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len, 
-                     int *eof, void *data)
+int i2o_proc_read_drivers_stored(char *buf, char **start, off_t offset,
+                                int len, int *eof, void *data)
 {
        typedef struct _i2o_driver_store {
                u16 stored_ddm_index;
@@ -1005,33 +961,17 @@ int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len,
        len = 0;
 
        token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-                               c, ADAPTER_TID,
-                               0x0005, -1,
-                               NULL, 0,
+                               c, ADAPTER_TID, 0x0005, -1, NULL, 0, 
                                &result, sizeof(result));
 
-       if (token<0)
-               switch (token)
-               {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading group. "
-                                       "BlockStatus %d\n",token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
-
-       len += sprintf(buf+len, "#  Type            Vendor Id      Name                    Vrs  Date     Mod_size Par_size Flags\n");   
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0005 DRIVER STORE TABLE");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
+       len += sprintf(buf+len, "#  Module_type     Vendor Mod_id  Module_name             Vrs"  
+                               "Date     Mod_size Par_size Flags\n");
        for(i=0, dst=result.dst[0]; i < result.row_count; dst=result.dst[++i])
        {
                len += sprintf(buf+len, "%-3d", dst.stored_ddm_index);
@@ -1052,8 +992,8 @@ int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len,
                        len += sprintf(buf+len, "%-d", dst.module_state);
 #endif
 
-               len += sprintf(buf+len, "%#7x", dst.i2o_vendor_id);
-               len += sprintf(buf+len, "%#8x", dst.module_id);
+               len += sprintf(buf+len, "%-#7x", dst.i2o_vendor_id);
+               len += sprintf(buf+len, "%-#8x", dst.module_id);
                len += sprintf(buf+len, "%-29s", chtostr(dst.module_name_version,28));
                len += sprintf(buf+len, "%-9s", chtostr(dst.date,8));
                len += sprintf(buf+len, "%8d ", dst.module_size);
@@ -1077,81 +1017,69 @@ int i2o_proc_read_dst(char *buf, char **start, off_t offset, int len,
 int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len, 
                         int *eof, void *data)
 {
-       struct i2o_controller *c = (struct i2o_controller*)data;
+       struct i2o_device *d = (struct i2o_device*)data;
        int token;
        int i;
-       int rows;
-       u16 work16[2048];
-       u16 *group=work16;
-       int more;
-       
+       u8 properties;
+
+       typedef struct _i2o_group_info
+       {
+               u16 group_number;
+               u16 field_count;
+               u16 row_count;
+               u8  properties;
+               u8  reserved;
+       } i2o_group_info;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               i2o_group_info group[256];
+       } result;
+
        spin_lock(&i2o_proc_lock);
 
        len = 0;
 
        token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-                               c, ADAPTER_TID,
-                               0xF000, -1,
-                               NULL, 0,
-                               &work16, sizeof(work16));
-
-       if (token<0)
-               switch (token)
-               {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading table. BlockStatus %d\n",
-                                      token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
+                               d->controller, d->lct_data->tid, 0xF000, -1, NULL, 0,
+                               &result, sizeof(result));
 
-       rows=work16[4];
-       more=work16[5];
+       if (token < 0) {
+               len = i2o_report_query_status(buf+len, token, "0xF000 Params Descriptor");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       len += sprintf(buf+len, "\nPARAMS DESCRIPTOR TABLE:\n\n");
        len += sprintf(buf+len, "#  Group   FieldCount RowCount Type   Add Del Clear\n");
 
-       group+=64;
-
-       for(i=0; i < rows; i++, group+=16)
+       for (i=0; i < result.row_count; i++)
        {
                len += sprintf(buf+len, "%-3d", i);
-
-               len += sprintf(buf+len, "%#6x ", group[0]);
-               len += sprintf(buf+len, "%10d ", group[1]);
-               len += sprintf(buf+len, "%8d ", group[2]);
-
-               if(group[3]&0x1)
-                       len += sprintf(buf+len, "Table  ");
-               else
-                       len += sprintf(buf+len, "Scalar ");
-               if(group[3]&0x2)
-                       len += sprintf(buf+len, "x   ");
-               else
-                       len += sprintf(buf+len, "    ");
-               if(group[3]&0x4)
-                       len += sprintf(buf+len, "x   ");
-               else
-                       len += sprintf(buf+len, "    ");
-               if(group[3]&0x8)
-                       len += sprintf(buf+len, "x   ");
-               else
-                       len += sprintf(buf+len, "    ");
+               len += sprintf(buf+len, "0x%04X ", result.group[i].group_number);
+               len += sprintf(buf+len, "%10d ", result.group[i].field_count);
+               len += sprintf(buf+len, "%8d ",  result.group[i].row_count);
+
+               properties = result.group[i].properties;
+               if (properties & 0x1)   len += sprintf(buf+len, "Table  ");
+                               else    len += sprintf(buf+len, "Scalar ");
+               if (properties & 0x2)   len += sprintf(buf+len, " + ");
+                               else    len += sprintf(buf+len, " - ");
+               if (properties & 0x4)   len += sprintf(buf+len, "  + ");
+                               else    len += sprintf(buf+len, "  - ");
+               if (properties & 0x8)   len += sprintf(buf+len, "  + ");
+                               else    len += sprintf(buf+len, "  - ");
 
                len += sprintf(buf+len, "\n");
        }
 
-       if(more)
+       if (result.more_flag)
                len += sprintf(buf+len, "There is more...\n");
 
        spin_unlock(&i2o_proc_lock);
@@ -1160,74 +1088,283 @@ int i2o_proc_read_groups(char *buf, char **start, off_t offset, int len,
 }
 
 
-/* Generic group F005h - Private message extensions (table) */
-int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
-                           int *eof, void *data)
+/* Generic group F001h - Physical Device Table (table) */
+int i2o_proc_read_phys_device(char *buf, char **start, off_t offset, int len,
+                             int *eof, void *data)
 {
-       struct i2o_controller *c = (struct i2o_controller*)data;
+       struct i2o_device *d = (struct i2o_device*)data;
        int token;
        int i;
-       int rows;
-       int more;
-       u16 work16[1024];
-       u16 *field=work16;
 
-       spin_lock(&i2o_proc_lock);
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               u32 adapter_id[64];
+       } result;
 
+       spin_lock(&i2o_proc_lock);
        len = 0;
 
        token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-                               c, ADAPTER_TID,
-                               0xF000, -1,
-                               NULL, 0,
-                               &work16, sizeof(work16));
+                               d->controller, d->lct_data->tid,
+                               0xF001, -1, NULL, 0,
+                               &result, sizeof(result));
 
-       if (token<0)
-               switch (token)
-               {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
-                                      token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF001 Physical Device Table");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       rows=work16[4];
-       more=work16[5];
-       
-       len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
+       if (result.row_count)
+               len += sprintf(buf+len, "#  AdapterId\n");
 
-       field+=64;
-       for(i=0; i < rows; i++, field+=16)
+       for (i=0; i < result.row_count; i++)
        {
-               len += sprintf(buf+len, "%0#9x ", field[0]);
-               len += sprintf(buf+len, "%0#6x ", work16[1]);
-               len += sprintf(buf+len, "%0#6x", work16[2]);
-
-               len += sprintf(buf+len, "\n");
+               len += sprintf(buf+len, "%-2d", i);
+               len += sprintf(buf+len, "%#7x\n", result.adapter_id[i]);
        }
 
-       if(more)
+       if (result.more_flag)
                len += sprintf(buf+len, "There is more...\n");
 
        spin_unlock(&i2o_proc_lock);
-
        return len;
 }
 
-
-int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len, 
-                     int *eof, void *data)
+/* Generic group F002h - Claimed Table (table) */
+int i2o_proc_read_claimed(char *buf, char **start, off_t offset, int len,
+                         int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       int token;
+       int i;
+
+       struct {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               u16 claimed_tid[64];
+       } result;
+
+       spin_lock(&i2o_proc_lock);
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               d->controller, d->lct_data->tid,
+                               0xF002, -1, NULL, 0,
+                               &result, sizeof(result));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF002 Claimed Table");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       if (result.row_count)
+               len += sprintf(buf+len, "#  ClaimedTid\n");
+
+       for (i=0; i < result.row_count; i++)
+       {
+               len += sprintf(buf+len, "%-2d", i);
+               len += sprintf(buf+len, "%#7x\n", result.claimed_tid[i]);
+       }
+
+       if (result.more_flag)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+/* Generic group F003h - User Table (table) */
+int i2o_proc_read_users(char *buf, char **start, off_t offset, int len,
+                       int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       int token;
+       int i;
+
+       typedef struct _i2o_user_table
+       {
+               u16 instance;
+               u16 user_tid;
+               u8 claim_type;
+               u8  reserved1;
+               u16  reserved2;
+       } i2o_user_table;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               i2o_user_table user[64];
+       } result;
+
+       spin_lock(&i2o_proc_lock);
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               d->controller, d->lct_data->tid,
+                               0xF003, -1, NULL, 0,
+                               &result, sizeof(result));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF003 User Table");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       len += sprintf(buf+len, "#  Instance UserTid ClaimType\n");
+
+       for(i=0; i < result.row_count; i++)
+       {
+               len += sprintf(buf+len, "%-3d", i);
+               len += sprintf(buf+len, "%#8x ", result.user[i].instance);
+               len += sprintf(buf+len, "%#7x ", result.user[i].user_tid);
+               len += sprintf(buf+len, "%#9x\n", result.user[i].claim_type);
+       }
+
+       if (result.more_flag)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+/* Generic group F005h - Private message extensions (table) (optional) */
+int i2o_proc_read_priv_msgs(char *buf, char **start, off_t offset, int len, 
+                           int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       int token;
+       int i;
+
+       typedef struct _i2o_private
+       {
+               u16 ext_instance;
+               u16 organization_id;
+               u16 x_function_code;
+       } i2o_private;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               i2o_private extension[64];
+       } result;
+
+       spin_lock(&i2o_proc_lock);
+
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               d->controller, d->lct_data->tid,
+                               0xF000, -1,
+                               NULL, 0,
+                               &result, sizeof(result));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF005 Private Message Extensions (optional)");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+       
+       len += sprintf(buf+len, "Instance#  OrgId  FunctionCode\n");
+
+       for(i=0; i < result.row_count; i++)
+       {
+               len += sprintf(buf+len, "%0#9x ", result.extension[i].ext_instance);
+               len += sprintf(buf+len, "%0#6x ", result.extension[i].organization_id);
+               len += sprintf(buf+len, "%0#6x",  result.extension[i].x_function_code);
+
+               len += sprintf(buf+len, "\n");
+       }
+
+       if(result.more_flag)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+
+       return len;
+}
+
+
+/* Generic group F006h - Authorized User Table (table) */
+int i2o_proc_read_authorized_users(char *buf, char **start, off_t offset, int len,
+                                  int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       int token;
+       int i;
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               u32 alternate_tid[64];
+       } result;
+
+       spin_lock(&i2o_proc_lock);
+       len = 0;
+
+       token = i2o_query_table(I2O_PARAMS_TABLE_GET,
+                               d->controller, d->lct_data->tid,
+                               0xF006, -1,
+                               NULL, 0,
+                               &result, sizeof(result));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF006 Autohorized User Table");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+
+       if (result.row_count)
+               len += sprintf(buf+len, "#  AlternateTid\n");
+
+       for(i=0; i < result.row_count; i++)
+       {
+               len += sprintf(buf+len, "%-2d", i);
+               len += sprintf(buf+len, "%#7x ", result.alternate_tid[i]);
+       }
+
+       if (result.more_flag)
+               len += sprintf(buf+len, "There is more...\n");
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
+
+/* Generic group F100h - Device Identity (scalar) */
+int i2o_proc_read_dev_identity(char *buf, char **start, off_t offset, int len, 
+                              int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
        static u32 work32[128];         // allow for "stuff" + up to 256 byte (max) serial number
@@ -1240,14 +1377,11 @@ int i2o_proc_read_dev(char *buf, char **start, off_t offset, int len,
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                       0xF100,         // ParamGroup F100h (Device Identity)
-                                       -1,             // all fields
-                                       &work32,
-                                       sizeof(work32));
+                               0xF100, -1,
+                               &work32, sizeof(work32));
 
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token ,"0xF100 Device Identity");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -1290,44 +1424,45 @@ int i2o_proc_read_dev_name(char *buf, char **start, off_t offset, int len,
 }
 
 
-
-int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len, 
-                     int *eof, void *data)
+/* Generic group F101h - DDM Identity (scalar) */
+int i2o_proc_read_ddm_identity(char *buf, char **start, off_t offset, int len, 
+                             int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[128];
-       static u16 *work16 = (u16*)work32;
        int token;
 
+       struct
+       {
+               u16 ddm_tid;
+               u8 module_name[24];
+               u8 module_rev[8];
+               u8 sn_format;
+               u8 serial_number[12];
+               u8 pad[256]; // allow up to 256 byte (max) serial number
+       } result;       
+
        spin_lock(&i2o_proc_lock);
        
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                       0xF101,         // ParamGroup F101h (DDM Identity)
-                                       -1,             // all fields
-                                       &work32,
-                                       sizeof(work32));
+                               0xF101, -1,
+                               &result, sizeof(result));
 
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF101 DDM Identity");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", work16[0]&0xFFF);
-       len += sprintf(buf+len, "Module name         : %s\n", chtostr((u8 *)(work16+1), 24));
-       len += sprintf(buf+len, "Module revision     : %s\n", chtostr((u8 *)(work16+13), 8));
+       len += sprintf(buf,     "Registering DDM TID : 0x%03x\n", result.ddm_tid);
+       len += sprintf(buf+len, "Module name         : %s\n", chtostr(result.module_name, 24));
+       len += sprintf(buf+len, "Module revision     : %s\n", chtostr(result.module_rev, 8));
 
        len += sprintf(buf+len, "Serial number       : ");
-       len = print_serial_number(buf, len,
-                       (u8*)(work16+17),
-                                       /* allow for SNLen plus
-                                        * possible trailing '\0'
-                                        */
-                       sizeof(work32)-(17*sizeof(u16))-2
-                               );
+       len = print_serial_number(buf, len, result.serial_number, sizeof(result)-36);
+                               /* allow for SNLen plus possible trailing '\0' */
+
        len += sprintf(buf+len, "\n");
 
        spin_unlock(&i2o_proc_lock);
@@ -1335,41 +1470,44 @@ int i2o_proc_read_ddm(char *buf, char **start, off_t offset, int len,
        return len;
 }
 
+/* Generic group F102h - User Information (scalar) */
 int i2o_proc_read_uinfo(char *buf, char **start, off_t offset, int len, 
                        int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[256];
        int token;
+
+       struct
+       {
+               u8 device_name[64];
+               u8 service_name[64];
+               u8 physical_location[64];
+               u8 instance_number[4];
+       } result;
+
        spin_lock(&i2o_proc_lock);
-       
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                       0xF102,         // ParamGroup F102h (User Information)
-                                       -1,             // all fields
-                                       &work32,
-                                       sizeof(work32));
+                               0xF102, -1,
+                               &result, sizeof(result));
 
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF102 User Information");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf,     "Device name     : %s\n", chtostr((u8 *)work32, 64));
-       len += sprintf(buf+len, "Service name    : %s\n", chtostr((u8 *)(work32+16), 64));
-       len += sprintf(buf+len, "Physical name   : %s\n", chtostr((u8 *)(work32+32), 64));
-       len += sprintf(buf+len, "Instance number : %s\n", chtostr((u8 *)(work32+48), 4));
-        
-       spin_unlock(&i2o_proc_lock);
+       len += sprintf(buf,     "Device name     : %s\n", chtostr(result.device_name, 64));
+       len += sprintf(buf+len, "Service name    : %s\n", chtostr(result.service_name, 64));
+       len += sprintf(buf+len, "Physical name   : %s\n", chtostr(result.physical_location, 64));
+       len += sprintf(buf+len, "Instance number : %s\n", chtostr(result.instance_number, 4));
 
+       spin_unlock(&i2o_proc_lock);
        return len;
 }
 
-
+/* Generic group F103h - SGL Operating Limits (scalar) */
 int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len, 
                             int *eof, void *data)
 {
@@ -1384,14 +1522,11 @@ int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len,
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                0xF103,        // ParamGroup F103h (SGL Operating Limits)
-                                -1,            // all fields
-                                &work32,
-                                sizeof(work32));
+                                0xF103, -1,
+                                &work32, sizeof(work32));
 
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF103 SGL Operating Limits");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -1424,6 +1559,164 @@ int i2o_proc_read_sgl_limits(char *buf, char **start, off_t offset, int len,
        return len;
 }
 
+/* Generic group F200h - Sensors (scalar) */
+int i2o_proc_read_sensors(char *buf, char **start, off_t offset, int len,
+                         int *eof, void *data)
+{
+       struct i2o_device *d = (struct i2o_device*)data;
+       int token;
+
+       struct
+       {
+               u16 sensor_instance;
+               u8  component;
+               u16 component_instance;
+               u8  sensor_class;
+               u8  sensor_type;
+               u8  scaling_exponent;
+               u32 actual_reading;
+               u32 minimum_reading;
+               u32 low2lowcat_treshold;
+               u32 lowcat2low_treshold;
+               u32 lowwarn2low_treshold;
+               u32 low2lowwarn_treshold;
+               u32 norm2lowwarn_treshold;
+               u32 lowwarn2norm_treshold;
+               u32 nominal_reading;
+               u32 hiwarn2norm_treshold;
+               u32 norm2hiwarn_treshold;
+               u32 high2hiwarn_treshold;
+               u32 hiwarn2high_treshold;
+               u32 hicat2high_treshold;
+               u32 hi2hicat_treshold;
+               u32 maximum_reading;
+               u8  sensor_state;
+               u16 event_enable;
+       } result;
+       
+       spin_lock(&i2o_proc_lock);      
+       len = 0;
+
+       token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                0xF200, -1,
+                                &result, sizeof(result));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0xF200 Sensors (optional)");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
+       
+       len += sprintf(buf+len, "Sensor instance       : %d\n", result.sensor_instance);
+
+       len += sprintf(buf+len, "Component             : %d = ", result.component);
+       switch (result.component)
+       {
+       case 0: len += sprintf(buf+len, "Other");               
+               break;
+       case 1: len += sprintf(buf+len, "Planar logic Board");
+               break;
+       case 2: len += sprintf(buf+len, "CPU");
+               break;
+       case 3: len += sprintf(buf+len, "Chassis");
+               break;
+       case 4: len += sprintf(buf+len, "Power Supply");
+               break;
+       case 5: len += sprintf(buf+len, "Storage");
+               break;
+       case 6: len += sprintf(buf+len, "External");
+               break;
+       }               
+       len += sprintf(buf+len,"\n");
+
+       len += sprintf(buf+len, "Component instance    : %d\n", result.component_instance);
+       len += sprintf(buf+len, "Sensor class          : %s\n",
+                               result.sensor_class ? "Analog" : "Digital");
+       
+       len += sprintf(buf+len, "Sensor type           : %d = ",result.sensor_type);
+       switch (result.sensor_type)
+       {
+       case 0: len += sprintf(buf+len, "Other\n");
+               break;
+       case 1: len += sprintf(buf+len, "Thermal\n");
+               break;
+       case 2: len += sprintf(buf+len, "DC voltage (DC volts)\n");
+               break;
+       case 3: len += sprintf(buf+len, "AC voltage (AC volts)\n");
+               break;
+       case 4: len += sprintf(buf+len, "DC current (DC amps)\n");
+               break;
+       case 5: len += sprintf(buf+len, "AC current (AC volts)\n");
+               break;
+       case 6: len += sprintf(buf+len, "Door open\n");
+               break;
+       case 7: len += sprintf(buf+len, "Fan operational\n");
+               break;
+       }                       
+
+       len += sprintf(buf+len, "Scaling exponent      : %d\n", result.scaling_exponent);
+       len += sprintf(buf+len, "Actual reading        : %d\n", result.actual_reading);
+       len += sprintf(buf+len, "Minimum reading       : %d\n", result.minimum_reading);
+       len += sprintf(buf+len, "Low2LowCat treshold   : %d\n", result.low2lowcat_treshold);
+       len += sprintf(buf+len, "LowCat2Low treshold   : %d\n", result.lowcat2low_treshold);
+       len += sprintf(buf+len, "LowWarn2Low treshold  : %d\n", result.lowwarn2low_treshold);
+       len += sprintf(buf+len, "Low2LowWarn treshold  : %d\n", result.low2lowwarn_treshold);
+       len += sprintf(buf+len, "Norm2LowWarn treshold : %d\n", result.norm2lowwarn_treshold);
+       len += sprintf(buf+len, "LowWarn2Norm treshold : %d\n", result.lowwarn2norm_treshold);
+       len += sprintf(buf+len, "Nominal reading       : %d\n", result.nominal_reading);
+       len += sprintf(buf+len, "HiWarn2Norm treshold  : %d\n", result.hiwarn2norm_treshold);
+       len += sprintf(buf+len, "Norm2HiWarn treshold  : %d\n", result.norm2hiwarn_treshold);
+       len += sprintf(buf+len, "High2HiWarn treshold  : %d\n", result.high2hiwarn_treshold);
+       len += sprintf(buf+len, "HiWarn2High treshold  : %d\n", result.hiwarn2high_treshold);
+       len += sprintf(buf+len, "HiCat2High treshold   : %d\n", result.hicat2high_treshold);
+       len += sprintf(buf+len, "High2HiCat treshold   : %d\n", result.hi2hicat_treshold);
+       len += sprintf(buf+len, "Maximum reading       : %d\n", result.maximum_reading);
+
+       len += sprintf(buf+len, "Sensor state          : %d = ", result.sensor_state);
+       switch (result.sensor_state)
+       {
+       case 0:  len += sprintf(buf+len, "Normal\n");
+                break;
+       case 1:  len += sprintf(buf+len, "Abnormal\n");
+                break;
+       case 2:  len += sprintf(buf+len, "Unknown\n");
+                break;
+       case 3:  len += sprintf(buf+len, "Low Catastrophic (LoCat)\n");
+                break;
+       case 4:  len += sprintf(buf+len, "Low (Low)\n");
+                break;
+       case 5:  len += sprintf(buf+len, "Low Warning (LoWarn)\n");
+                break;
+       case 6:  len += sprintf(buf+len, "High Warning (HiWarn)\n");
+                break;
+       case 7:  len += sprintf(buf+len, "High (High)\n");
+                break;
+       case 8:  len += sprintf(buf+len, "High Catastrophic (HiCat)\n");
+                break;
+       }                       
+
+       len += sprintf(buf+len, "Event_enable          : 0x%02X\n", result.event_enable);
+       if (result.event_enable & 0x01)
+               len += sprintf(buf+len, "\tOperational state change. \n");
+       if (result.event_enable & 0x02)
+               len += sprintf(buf+len, "\tLow catastrophic. \n");
+       if (result.event_enable & 0x04)
+               len += sprintf(buf+len, "\tLow reading. \n");
+       if (result.event_enable & 0x08)
+               len += sprintf(buf+len, "\tLow warning. \n");
+       if (result.event_enable & 0x10)
+               len += sprintf(buf+len, "\tChange back to normal from out of range state. \n");
+       if (result.event_enable & 0x20)
+               len += sprintf(buf+len, "\tHigh warning. \n");
+       if (result.event_enable & 0x40)
+               len += sprintf(buf+len, "\tHigh reading. \n");
+       if (result.event_enable & 0x80)
+               len += sprintf(buf+len, "\tHigh catastrophic. \n");
+
+       spin_unlock(&i2o_proc_lock);
+       return len;
+}
+
 
 static int print_serial_number(char *buff, int pos, u8 *serialno, int max_len)
 {
@@ -1749,14 +2042,12 @@ int i2o_proc_read_lan_dev_info(char *buf, char **start, off_t offset, int len,
        int token;
 
        spin_lock(&i2o_proc_lock);
-
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0000, -1, &work32, 56*4);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token, "0x0000 LAN Device Info");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -1877,9 +2168,8 @@ int i2o_proc_read_lan_mac_addr(char *buf, char **start, off_t offset, int len,
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0001, -1, &work32, 48*4);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0001 LAN MAC Address");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -1955,51 +2245,44 @@ int i2o_proc_read_lan_mcast_addr(char *buf, char **start, off_t offset,
                                 int len, int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 field32[64];
-       static u8 *field8 = (u8 *)field32;
-       static u16 *field16 = (u16 *)field32;
        int token;
        int i;
+       u8 mc_addr[8];
+
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               u8  mc_addr[256][8];
+       } result;       
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-                       d->controller, d->lct_data->tid, 0x0002, -1, 
-                       NULL, 0, &field32, sizeof(field32));
-
-       if (token<0)
-               switch (token) {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
-                                      token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
-
-       len += sprintf(buf, "RowCount=%d, MoreFlag=%d\n", 
-                      field16[0], field16[1]);
+                               d->controller, d->lct_data->tid, 0x0002, -1, 
+                               NULL, 0, &result, sizeof(result));
 
-       field8=(u8 *)&field16[2];
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x002 LAN Multicast MAC Address");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       for(i=0; i<field16[0]; i++, field8+=8)
+       for (i = 0; i < result.row_count; i++)
        {
+               memcpy(mc_addr, result.mc_addr[i], 8);
+
                len += sprintf(buf+len, "MC MAC address[%d]: "
                               "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                              i,
-                              field8[0], field8[1], field8[2],
-                              field8[3], field8[4], field8[5],
-                              field8[6], field8[7]);
+                              i, mc_addr[0], mc_addr[1], mc_addr[2],
+                              mc_addr[3], mc_addr[4], mc_addr[5],
+                              mc_addr[6], mc_addr[7]);
        }
 
        spin_unlock(&i2o_proc_lock);
@@ -2019,9 +2302,8 @@ int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0003, -1, &work32, 9*4);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0003 LAN Batch Control");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -2050,8 +2332,8 @@ int i2o_proc_read_lan_batch_control(char *buf, char **start, off_t offset,
                               work32[4]/10);
        }
 
-       len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
-       len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
+       len += sprintf(buf+len, "Max Rx batch count     : %d\n", work32[5]);
+       len += sprintf(buf+len, "Max Rx batch delay     : %d\n", work32[6]);
 
        if(d->i2oversion == 0x00) {
                len += sprintf(buf+len,
@@ -2079,9 +2361,8 @@ int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0004, -1, &work32, 20);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0004 LAN Operation");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -2090,7 +2371,7 @@ int i2o_proc_read_lan_operation(char *buf, char **start, off_t offset, int len,
        len += sprintf(buf+len, "Transmission error reporting  : %s\n",
                       (work32[1]&1)?"on":"off");
        len += sprintf(buf+len, "Bad packet handling           : %s\n",
-                      (work32[1]&0x2)?"by host":"by DDM");                   
+                               (work32[1]&0x2)?"by host":"by DDM");
        len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
 
        len += sprintf(buf+len, "Tx modes :\n");
@@ -2134,52 +2415,72 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
                                      int len, int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 work32[9];
-       static u8 *work8 = (u8*)work32;
-        static u64 *work64 = (u64*)work32;
        int token;
 
+       struct
+       {
+               u32 connector_type;
+               u32 connection_type;
+               u64 current_tx_wire_speed;
+               u64 current_rx_wire_speed;
+               u8  duplex_mode;
+               u8  link_status;
+               u8  reserved;
+               u8  duplex_mode_target;
+               u32 connector_type_target;
+               u32 connection_type_target;
+       } result;       
+
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0005, -1, &work32, 36);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+                                0x0005, -1, &result, sizeof(result));
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token, "0x0005 LAN Media Operation");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
        len += sprintf(buf, "Connector type         : %s\n",
-                      i2o_get_connector_type(work32[0]));
+                      i2o_get_connector_type(result.connector_type));
        len += sprintf(buf+len, "Connection type        : %s\n",
-                      i2o_get_connection_type(work32[1]));
-
-       len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", (int)work64[1]);
-       len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", (int)work64[2]);
+                      i2o_get_connection_type(result.connection_type));
 
-       len += sprintf(buf+len, "Duplex mode            : %s duplex\n", 
-                       (work8[24]&1)?"Full":"Half");
+       len += sprintf(buf+len, "Current Tx wire speed  : %d bps\n", (int)result.current_tx_wire_speed);
+       len += sprintf(buf+len, "Current Rx wire speed  : %d bps\n", (int)result.current_rx_wire_speed);
+       len += sprintf(buf+len, "Duplex mode            : %s duplex\n",
+                       (result.duplex_mode)?"Full":"Half");
+                       
        len += sprintf(buf+len, "Link status            : ");
-       if(work8[25] == 0x00)
+       switch (result.link_status)
+       {
+       case 0x00:
                len += sprintf(buf+len, "Unknown\n");
-       else if(work8[25] == 0x01)
+               break;
+       case 0x01:
                len += sprintf(buf+len, "Normal\n");
-       else if(work8[25] == 0x02)
+               break;
+       case 0x02:
                len += sprintf(buf+len, "Failure\n");
-       else if(work8[25] == 0x03)
+               break;
+       case 0x03:
                len += sprintf(buf+len, "Reset\n");
-       else
+               break;
+       default:
                len += sprintf(buf+len, "Unspecified\n");
-
-       if (d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
+       }
+       
+       if (d->i2oversion == 0x00) /* Reserved in 1.53 and 2.0 */
+       {
                len += sprintf(buf+len, "Bad packets handled by : %s\n",
-                              (work8[26] == 0xFF)?"host":"DDM");
+                              (result.reserved == 0xFF)?"host":"DDM");
        }
-       if (d->i2oversion != 0x00) {
+       else
+       {
                len += sprintf(buf+len, "Duplex mode target     : ");
-               switch (work8[27]) {
+               switch (result.duplex_mode_target)
+               {
                case 0:
                        len += sprintf(buf+len, "Half duplex\n");
                        break;
@@ -2188,69 +2489,59 @@ int i2o_proc_read_lan_media_operation(char *buf, char **start, off_t offset,
                        break;
                default:
                        len += sprintf(buf+len, "\n");
-                       break;
                }
 
                len += sprintf(buf+len, "Connector type target  : %s\n",
-                              i2o_get_connector_type(work32[7]));
+                              i2o_get_connector_type(result.connector_type_target));
                len += sprintf(buf+len, "Connection type target : %s\n",
-                              i2o_get_connection_type(work32[8]));
+                              i2o_get_connection_type(result.connection_type_target));
        }
 
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
-/* LAN group 0006h - Alternate address (table) */
+/* LAN group 0006h - Alternate address (table) (optional) */
 int i2o_proc_read_lan_alt_addr(char *buf, char **start, off_t offset, int len,
                               int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u32 field32[64];
-       static u8 *field8 = (u8 *)field32;
-       static u16 *field16 = (u16 *)field32;
        int token;
        int i;
+       u8 alt_addr[8];
+       struct
+       {
+               u16 result_count;
+               u16 pad;
+               u16 block_size;
+               u8  block_status;
+               u8  error_info_size;
+               u16 row_count;
+               u16 more_flag;
+               u8  alt_addr[256][8];
+       } result;       
 
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_table(I2O_PARAMS_TABLE_GET,
-                       d->controller, d->lct_data->tid, 0x0006, -1, 
-                       NULL, 0, &field32, sizeof(field32));
+                               d->controller, d->lct_data->tid,
+                               0x0006, -1, NULL, 0, &result, sizeof(result));
 
-       if (token<0)
-               switch (token) {
-               case -ETIMEDOUT:
-                       len += sprintf(buf, "Timeout reading table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               case -ENOMEM:
-                       len += sprintf(buf, "No free memory to read the table.\n");
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-                       break;
-               default:
-                       len += sprintf(buf, "Error reading field. BlockStatus %d\n",
-                                      token);
-                       spin_unlock(&i2o_proc_lock);
-                       return len;
-               }
-
-       len += sprintf(buf,"RowCount=%d, MoreFlag=%d\n", field16[0],
-                      field16[1]);
-
-       field8=(u8 *)&field16[2];
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token, "0x0006 LAN Alternate Address (optional)");
+               spin_unlock(&i2o_proc_lock);
+               return len;
+       }
 
-       for(i=0; i<field16[0]; i++, field8+=8)
+       for (i=0; i < result.row_count; i++)
        {
+               memcpy(alt_addr,result.alt_addr[i],8);
                len += sprintf(buf+len, "Alternate address[%d]: "
                               "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-                              i,
-                              field8[0], field8[1], field8[2],
-                              field8[3], field8[4], field8[5],
-                              field8[6], field8[7]);
+                              i, alt_addr[0], alt_addr[1], alt_addr[2],
+                              alt_addr[3], alt_addr[4], alt_addr[5],
+                              alt_addr[6], alt_addr[7]);
        }
 
        spin_unlock(&i2o_proc_lock);
@@ -2271,9 +2562,8 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0007, -1, &work32, 8*4);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0007 LAN Transmit Info");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -2304,12 +2594,15 @@ int i2o_proc_read_lan_tx_info(char *buf, char **start, off_t offset, int len,
                len += sprintf(buf+len, "    RSVP checksum\n");
        if(work32[4]&0x00001000)
                len += sprintf(buf+len, "    ICMP checksum\n");
-       if (d->i2oversion == 0x00) {
+       if (d->i2oversion == 0x00)
+       {
                if(work32[4]&0x00008000)
                        len += sprintf(buf+len, "    Loopback enabled\n");
                if(work32[4]&0x00010000)
                        len += sprintf(buf+len, "    Loopback suppression enabled\n");
-       } else {
+       }
+       else
+       {
                if(work32[4]&0x00010000)
                        len += sprintf(buf+len, "    Loopback enabled\n");
                if(work32[4]&0x00020000)
@@ -2333,9 +2626,8 @@ int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len,
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
                                 0x0008, -1, &work32, 8*4);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0008 LAN Receive Info");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -2354,288 +2646,345 @@ int i2o_proc_read_lan_rx_info(char *buf, char **start, off_t offset, int len,
        return len;
 }
 
+static int i2o_report_opt_field(char *buf, char *field_name,
+                               int field_nbr, int supp_fields, u64 *value)
+{
+       if (supp_fields & (1 << field_nbr))
+               return sprintf(buf, "%-24s : " FMT_U64_HEX "\n", field_name, U64_VAL(value));
+       else    
+               return sprintf(buf, "%-24s : Not supported\n", field_name);     
+}
 
 /* LAN group 0100h - LAN Historical statistics (scalar) */
+/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
+/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics (scalar) */
+/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics (scalar) */
+
 int i2o_proc_read_lan_hist_stats(char *buf, char **start, off_t offset, int len,
                                 int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[9];
        int token;
 
+       struct
+       {
+               u64 tx_packets;
+               u64 tx_bytes;
+               u64 rx_packets;
+               u64 rx_bytes;
+               u64 tx_errors;
+               u64 rx_errors;
+               u64 rx_dropped;
+               u64 adapter_resets;
+               u64 adapter_suspends;
+       } stats;                        // 0x0100
+
+       static u64 supp_groups[4];      // 0x0180
+
+       struct
+       {
+               u64 tx_retries;
+               u64 tx_directed_bytes;
+               u64 tx_directed_packets;
+               u64 tx_multicast_bytes;
+               u64 tx_multicast_packets;
+               u64 tx_broadcast_bytes;
+               u64 tx_broadcast_packets;
+               u64 tx_group_addr_packets;
+               u64 tx_short_packets;
+       } tx_stats;                     // 0x0182
+
+       struct
+       {
+               u64 rx_crc_errors;
+               u64 rx_directed_bytes;
+               u64 rx_directed_packets;
+               u64 rx_multicast_bytes;
+               u64 rx_multicast_packets;
+               u64 rx_broadcast_bytes;
+               u64 rx_broadcast_packets;
+               u64 rx_group_addr_packets;
+               u64 rx_short_packets;
+               u64 rx_long_packets;
+               u64 rx_runt_packets;
+       } rx_stats;                     // 0x0183
+
+       struct
+       {
+               u64 ipv4_generate;
+               u64 ipv4_validate_success;
+               u64 ipv4_validate_errors;
+               u64 tcp_generate;
+               u64 tcp_validate_success;
+               u64 tcp_validate_errors;
+               u64 udp_generate;
+               u64 udp_validate_success;
+               u64 udp_validate_errors;
+               u64 rsvp_generate;
+               u64 rsvp_validate_success;
+               u64 rsvp_validate_errors;               
+               u64 icmp_generate;
+               u64 icmp_validate_success;
+               u64 icmp_validate_errors;
+       } chksum_stats;                 // 0x0184
+
        spin_lock(&i2o_proc_lock);      
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0100, -1, &work64, 9*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+                                0x0100, -1, &stats, sizeof(stats));
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x100 LAN Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf,     "Tx packets       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "Tx packets       : " FMT_U64_HEX "\n",
+                      U64_VAL(&stats.tx_packets));
        len += sprintf(buf+len, "Tx bytes         : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[1]));
+                      U64_VAL(&stats.tx_bytes));
        len += sprintf(buf+len, "Rx packets       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[2]));
+                      U64_VAL(&stats.rx_packets));
        len += sprintf(buf+len, "Rx bytes         : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[3]));
+                      U64_VAL(&stats.rx_bytes));
        len += sprintf(buf+len, "Tx errors        : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[4]));
+                      U64_VAL(&stats.tx_errors));
        len += sprintf(buf+len, "Rx errors        : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[5]));
+                      U64_VAL(&stats.rx_errors));
        len += sprintf(buf+len, "Rx dropped       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[6]));
+                      U64_VAL(&stats.rx_dropped));
        len += sprintf(buf+len, "Adapter resets   : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[7]));
+                      U64_VAL(&stats.adapter_resets));
        len += sprintf(buf+len, "Adapter suspends : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[8]));
-
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
-
-/* LAN group 0180h - Supported Optional Historical Statistics (scalar) */
-int i2o_proc_read_lan_supp_opt_stats(char *buf, char **start, off_t offset,
-                                    int len, int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[4];
-       int token;
+                      U64_VAL(&stats.adapter_suspends));
 
-       spin_lock(&i2o_proc_lock);      
-
-       len = 0;
+       /* Optional statistics follows */
+       /* Get 0x0180 to see which optional groups/fields are supported */
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0180, -1, &work64, 4*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+                                0x0180, -1, &supp_groups, sizeof(supp_groups));
+       
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token, "0x180 LAN Supported Optional Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       if (d->i2oversion == 0x00)
-               len += sprintf(buf, "Supported stats : " FMT_U64_HEX " \n",
-                              U64_VAL(&work64[0]));
-       else
+       if (supp_groups[1]) /* 0x0182 */
        {
-               len += sprintf(buf, "Supported stats (0182h) : " FMT_U64_HEX " \n",
-                              U64_VAL(&work64[1]));
-               len += sprintf(buf, "Supported stats (0183h) : " FMT_U64_HEX " \n",
-                              U64_VAL(&work64[2]));
-               len += sprintf(buf, "Supported stats (0184h) : " FMT_U64_HEX " \n",
-                              U64_VAL(&work64[3]));
-       }
-
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
-
-/* LAN group 0182h - Optional Non Media Specific Transmit Historical Statistics
- * (scalar) */
-int i2o_proc_read_lan_opt_tx_hist_stats(char *buf, char **start, off_t offset,
-                                       int len, int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[9];
-       int token;
-
-       spin_lock(&i2o_proc_lock);      
+               token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                       0x0182, -1, &tx_stats, sizeof(tx_stats));
 
-       len = 0;
+               if (token < 0) {
+                       len += i2o_report_query_status(buf+len, token,"0x182 LAN Optional Tx Historical Statistics");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                0x0182, -1, &work64, 9*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
+               len += sprintf(buf+len, "==== Optional TX statistics (group 0182h)\n");
+
+               len += i2o_report_opt_field(buf+len, "Tx RetryCount",
+                                       0, supp_groups[1], &tx_stats.tx_retries);
+               len += i2o_report_opt_field(buf+len, "Tx DirectedBytes",
+                                       1, supp_groups[1], &tx_stats.tx_directed_bytes);
+               len += i2o_report_opt_field(buf+len, "Tx DirectedPackets",
+                                       2, supp_groups[1], &tx_stats.tx_directed_packets);
+               len += i2o_report_opt_field(buf+len, "Tx MulticastBytes",
+                                       3, supp_groups[1], &tx_stats.tx_multicast_bytes);
+               len += i2o_report_opt_field(buf+len, "Tx MulticastPackets",
+                                       4, supp_groups[1], &tx_stats.tx_multicast_packets);
+               len += i2o_report_opt_field(buf+len, "Tx BroadcastBytes",
+                                       5, supp_groups[1], &tx_stats.tx_broadcast_bytes);
+               len += i2o_report_opt_field(buf+len, "Tx BroadcastPackets",
+                                       6, supp_groups[1], &tx_stats.tx_broadcast_packets);
+               len += i2o_report_opt_field(buf+len, "Tx TotalGroupAddrPackets",
+                                       7, supp_groups[1], &tx_stats.tx_group_addr_packets);
+               len += i2o_report_opt_field(buf+len, "Tx TotalPacketsTooShort",
+                                       8, supp_groups[1], &tx_stats.tx_short_packets);
        }
 
-       len += sprintf(buf,     "TxRetryCount           : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
-       len += sprintf(buf+len, "DirectedBytesTx        : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "DirectedPacketsTx      : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "MulticastBytesTx       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "MulticastPacketsTx     : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "BroadcastBytesTx       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[5]));
-       len += sprintf(buf+len, "BroadcastPacketsTx     : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "TotalGroupAddrTxCount  : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "TotalTxPacketsTooShort : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[8]));
-
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
-/* LAN group 0183h - Optional Non Media Specific Receive Historical Statistics
- * (scalar) */
-int i2o_proc_read_lan_opt_rx_hist_stats(char *buf, char **start, off_t offset,
-                                       int len, int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[11];
-       int token;
+       if (supp_groups[2]) /* 0x0183 */
+       {
+               token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                        0x0183, -1, &rx_stats, sizeof(rx_stats));
+               if (token < 0) {
+                       len += i2o_report_query_status(buf+len, token,"0x183 LAN Optional Rx Historical Stats");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
 
-       spin_lock(&i2o_proc_lock);      
+               len += sprintf(buf+len, "==== Optional RX statistics (group 0183h)\n");
+
+               len += i2o_report_opt_field(buf+len, "Rx CRCErrorCount",
+                                       0, supp_groups[2], &rx_stats.rx_crc_errors);
+               len += i2o_report_opt_field(buf+len, "Rx DirectedBytes",
+                                       1, supp_groups[2], &rx_stats.rx_directed_bytes);
+               len += i2o_report_opt_field(buf+len, "Rx DirectedPackets",
+                                       2, supp_groups[2], &rx_stats.rx_directed_packets);
+               len += i2o_report_opt_field(buf+len, "Rx MulticastBytes",
+                                       3, supp_groups[2], &rx_stats.rx_multicast_bytes);
+               len += i2o_report_opt_field(buf+len, "Rx MulticastPackets",
+                                       4, supp_groups[2], &rx_stats.rx_multicast_packets);
+               len += i2o_report_opt_field(buf+len, "Rx BroadcastBytes",
+                                       5, supp_groups[2], &rx_stats.rx_broadcast_bytes);
+               len += i2o_report_opt_field(buf+len, "Rx BroadcastPackets",
+                                       6, supp_groups[2], &rx_stats.rx_broadcast_packets);
+               len += i2o_report_opt_field(buf+len, "Rx TotalGroupAddrPackets",
+                                       7, supp_groups[2], &rx_stats.rx_group_addr_packets);
+               len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooShort",
+                                       8, supp_groups[2], &rx_stats.rx_short_packets);
+               len += i2o_report_opt_field(buf+len, "Rx TotalPacketsTooLong",
+                                       9, supp_groups[2], &rx_stats.rx_long_packets);
+               len += i2o_report_opt_field(buf+len, "Rx TotalPacketsRunt",
+                                       10, supp_groups[2], &rx_stats.rx_runt_packets);
+       }
+       
+       if (supp_groups[3]) /* 0x0184 */
+       {
+               token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                       0x0184, -1, &chksum_stats, sizeof(chksum_stats));
 
-       len = 0;
+               if (token < 0) {
+                       len += i2o_report_query_status(buf+len, token,"0x184 LAN Optional Chksum Historical Stats");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0183, -1, &work64, 11*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
+               len += sprintf(buf+len, "==== Optional CHKSUM statistics (group 0x0184)\n");
+
+               len += i2o_report_opt_field(buf+len, "IPv4 Generate",
+                                       0, supp_groups[3], &chksum_stats.ipv4_generate);
+               len += i2o_report_opt_field(buf+len, "IPv4 ValidateSuccess",
+                                       1, supp_groups[3], &chksum_stats.ipv4_validate_success);
+               len += i2o_report_opt_field(buf+len, "IPv4 ValidateError",
+                                       2, supp_groups[3], &chksum_stats.ipv4_validate_errors);
+               len += i2o_report_opt_field(buf+len, "TCP  Generate",
+                                       3, supp_groups[3], &chksum_stats.tcp_generate);
+               len += i2o_report_opt_field(buf+len, "TCP  ValidateSuccess",
+                                       4, supp_groups[3], &chksum_stats.tcp_validate_success);
+               len += i2o_report_opt_field(buf+len, "TCP  ValidateError",
+                                       5, supp_groups[3], &chksum_stats.tcp_validate_errors);
+               len += i2o_report_opt_field(buf+len, "UDP  Generate",
+                                       6, supp_groups[3], &chksum_stats.udp_generate);
+               len += i2o_report_opt_field(buf+len, "UDP  ValidateSuccess",
+                                       7, supp_groups[3], &chksum_stats.udp_validate_success);
+               len += i2o_report_opt_field(buf+len, "UDP  ValidateError",
+                                       8, supp_groups[3], &chksum_stats.udp_validate_errors);
+               len += i2o_report_opt_field(buf+len, "RSVP Generate",
+                                       9, supp_groups[3], &chksum_stats.rsvp_generate);
+               len += i2o_report_opt_field(buf+len, "RSVP ValidateSuccess",
+                                       10, supp_groups[3], &chksum_stats.rsvp_validate_success);
+               len += i2o_report_opt_field(buf+len, "RSVP ValidateError",
+                                       11, supp_groups[3], &chksum_stats.rsvp_validate_errors);
+               len += i2o_report_opt_field(buf+len, "ICMP Generate",
+                                       12, supp_groups[3], &chksum_stats.icmp_generate);
+               len += i2o_report_opt_field(buf+len, "ICMP ValidateSuccess",
+                                       13, supp_groups[3], &chksum_stats.icmp_validate_success);
+               len += i2o_report_opt_field(buf+len, "ICMP ValidateError",
+                                       14, supp_groups[3], &chksum_stats.icmp_validate_errors);
        }
 
-       len += sprintf(buf,     "ReceiveCRCErrorCount     : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
-       len += sprintf(buf+len, "DirectedBytesRx          : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[1]));
-       len += sprintf(buf+len, "DirectedPacketsRx        : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[2]));
-       len += sprintf(buf+len, "MulticastBytesRx         : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[3]));
-       len += sprintf(buf+len, "MulticastPacketsRx       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[4]));
-       len += sprintf(buf+len, "BroadcastBytesRx         : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[5]));
-       len += sprintf(buf+len, "BroadcastPacketsRx       : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[6]));
-       len += sprintf(buf+len, "TotalGroupAddrRxCount    : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[7]));
-       len += sprintf(buf+len, "TotalRxPacketsTooShort   : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[8]));
-       len += sprintf(buf+len, "TotalRxPacketsTooLong    : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[9]));
-       len += sprintf(buf+len, "TotalRuntPacketsReceived : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[10]));
-
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
 /* LAN group 0200h - Required Ethernet Statistics (scalar) */
+/* LAN group 0280h - Optional Ethernet Statistics Supported (scalar) */
+/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
 int i2o_proc_read_lan_eth_stats(char *buf, char **start, off_t offset,
                                int len, int *eof, void *data)
 {
        struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[8];
        int token;
 
+       struct
+       {
+               u64 rx_align_errors;
+               u64 tx_one_collisions;
+               u64 tx_multiple_collisions;
+               u64 tx_deferred;
+               u64 tx_late_collisions;
+               u64 tx_max_collisions;
+               u64 tx_carrier_lost;
+               u64 tx_excessive_deferrals;
+       } stats;        
+
+       static u64 supp_fields;
+       struct
+       {
+               u64 rx_overrun;
+               u64 tx_underrun;
+               u64 tx_heartbeat_failure;       
+       } hist_stats;
 
-       spin_lock(&i2o_proc_lock);
-       
+       spin_lock(&i2o_proc_lock);      
        len = 0;
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                0x0200, -1, &work64, 8*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                0x0200, -1, &stats, sizeof(stats));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0200 LAN Ethernet Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf,     "Rx alignment errors    : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
+       len += sprintf(buf+len, "Rx alignment errors    : " FMT_U64_HEX "\n",
+                      U64_VAL(&stats.rx_align_errors));
        len += sprintf(buf+len, "Tx one collisions      : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[1]));
+                      U64_VAL(&stats.tx_one_collisions));
        len += sprintf(buf+len, "Tx multicollisions     : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[2]));
+                      U64_VAL(&stats.tx_multiple_collisions));
        len += sprintf(buf+len, "Tx deferred            : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[3]));
+                      U64_VAL(&stats.tx_deferred));
        len += sprintf(buf+len, "Tx late collisions     : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[4]));
+                      U64_VAL(&stats.tx_late_collisions));
        len += sprintf(buf+len, "Tx max collisions      : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[5]));
+                      U64_VAL(&stats.tx_max_collisions));
        len += sprintf(buf+len, "Tx carrier lost        : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[6]));
+                      U64_VAL(&stats.tx_carrier_lost));
        len += sprintf(buf+len, "Tx excessive deferrals : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[7]));
+                      U64_VAL(&stats.tx_excessive_deferrals));
 
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
-/* LAN group 0280h - Supported Ethernet Historical Statistics (scalar) */
-int i2o_proc_read_lan_supp_eth_stats(char *buf, char **start, off_t offset,
-                                    int len, int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[1];
-       int token;
-
-       spin_lock(&i2o_proc_lock);      
+       /* Optional Ethernet statistics follows  */
+       /* Get 0x0280 to see which optional fields are supported */
 
-       len = 0;
+       token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                0x0280, -1, &supp_fields, sizeof(supp_fields));
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                0x0280, -1, &work64, 8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0280 LAN Supported Optional Ethernet Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf, "Supported stats : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
-
-       spin_unlock(&i2o_proc_lock);
-       return len;
-}
-
-/* LAN group 0281h - Optional Ethernet Historical Statistics (scalar) */
-int i2o_proc_read_lan_opt_eth_stats(char *buf, char **start, off_t offset,
-                                   int len, int *eof, void *data)
-{
-       struct i2o_device *d = (struct i2o_device*)data;
-       static u64 work64[3];
-       int token;
+       if (supp_fields) /* 0x0281 */
+       {
+               token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                        0x0281, -1, &stats, sizeof(stats));
 
-       spin_lock(&i2o_proc_lock);      
+               if (token < 0) {
+                       len += i2o_report_query_status(buf+len, token,"0x0281 LAN Optional Ethernet Statistics");
+                       spin_unlock(&i2o_proc_lock);
+                       return len;
+               }
 
-       len = 0;
+               len += sprintf(buf+len, "==== Optional ETHERNET statistics (group 0x0281)\n");
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0281, -1, &work64, 3*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
-               spin_unlock(&i2o_proc_lock);
-               return len;
+               len += i2o_report_opt_field(buf+len, "Rx Overrun",
+                                       0, supp_fields, &hist_stats.rx_overrun);
+               len += i2o_report_opt_field(buf+len, "Tx Underrun",
+                                       1, supp_fields, &hist_stats.tx_underrun);
+               len += i2o_report_opt_field(buf+len, "Tx HeartbeatFailure",
+                                       2, supp_fields, &hist_stats.tx_heartbeat_failure);
        }
 
-       len += sprintf(buf, "Rx overrun           : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[0]));
-       len += sprintf(buf, "Tx underrun          : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[1]));
-       len += sprintf(buf, "Tx heartbeat failure : " FMT_U64_HEX "\n",
-                      U64_VAL(&work64[2]));
-
        spin_unlock(&i2o_proc_lock);
        return len;
 }
 
 /* LAN group 0300h - Required Token Ring Statistics (scalar) */
+/* LAN group 0380h, 0381h - Optional Statistics not yet defined (TODO) */
 int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
                               int len, int *eof, void *data)
 {
@@ -2663,15 +3012,14 @@ int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
                "Signal Loss"
        };
 
-       spin_lock(&i2o_proc_lock);
-       
+       spin_lock(&i2o_proc_lock);      
        len = 0;
 
-       token = i2o_query_scalar(d->controller, d->lct_data->tid, 
-                                0x0300, -1, &work64, 13*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+       token = i2o_query_scalar(d->controller, d->lct_data->tid,
+                                0x0300, -1, &work64, sizeof(work64));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0300 Token Ring Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
@@ -2707,6 +3055,7 @@ int i2o_proc_read_lan_tr_stats(char *buf, char **start, off_t offset,
 }
 
 /* LAN group 0400h - Required FDDI Statistics (scalar) */
+/* LAN group 0480h, 0481h - Optional Statistics, not yet defined (TODO) */
 int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
                                 int len, int *eof, void *data)
 {
@@ -2758,19 +3107,18 @@ int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
        };
 
        spin_lock(&i2o_proc_lock);
-       
        len = 0;
 
        token = i2o_query_scalar(d->controller, d->lct_data->tid,
-                                0x0400, -1, &work64, 11*8);
-       if(token < 0)
-       {
-               len += sprintf(buf, "Timeout waiting for reply from IOP\n");
+                                0x0400, -1, &work64, sizeof(work64));
+
+       if (token < 0) {
+               len += i2o_report_query_status(buf+len, token,"0x0400 FDDI Required Statistics");
                spin_unlock(&i2o_proc_lock);
                return len;
        }
 
-       len += sprintf(buf,     "ConfigurationState : %s\n", conf_state[work64[0]]);
+       len += sprintf(buf+len, "ConfigurationState : %s\n", conf_state[work64[0]]);
        len += sprintf(buf+len, "UpstreamNode       : " FMT_U64_HEX "\n",
                       U64_VAL(&work64[1]));
        len += sprintf(buf+len, "DownStreamNode     : " FMT_U64_HEX "\n",
@@ -2780,7 +3128,7 @@ int i2o_proc_read_lan_fddi_stats(char *buf, char **start, off_t offset,
        len += sprintf(buf+len, "FramesLost         : " FMT_U64_HEX "\n",
                       U64_VAL(&work64[4]));
        len += sprintf(buf+len, "RingMgmtState      : %s\n", ring_state[work64[5]]);
-       len += sprintf(buf+len, "LCTFailures: " FMT_U64_HEX "\n",
+       len += sprintf(buf+len, "LCTFailures        : " FMT_U64_HEX "\n",
                       U64_VAL(&work64[6]));
        len += sprintf(buf+len, "LEMRejects         : " FMT_U64_HEX "\n",
                       U64_VAL(&work64[7]));
diff --git a/drivers/i2o/i2o_proc.h b/drivers/i2o/i2o_proc.h
deleted file mode 100644 (file)
index f2fe718..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef i2oproc_h
-#define i2oproc_h
-
-/*
- * Fixme: make this dependent on architecture
- * The official header files to this already...but we can't use them
- */
-#define     I2O_64BIT_CONTEXT          0
-
-typedef struct _i2o_msg {
-       u8 ver_offset;
-       u8 msg_flags;
-       u16 msg_size;
-       u32 target_addr:12;
-       u32 initiator_addr:12;
-       u32 function:8;
-       u32 init_context;       /* FIXME: 64-bit support! */
-} i2o_msg, *pi2o_msg;
-
-typedef struct _i2o_reply_message {
-       i2o_msg msg_frame;
-       u32 tctx;               /* FIXME: 64-bit */
-       u16 detailed_status_code;
-       u8 reserved;
-       u8 req_status;
-} i2o_reply_msg, *pi2o_reply_msg;
-
-typedef struct _i2o_mult_reply_message {
-       i2o_msg msg_frame;
-       u32 tctx;               /* FIXME: 64-bit */
-       u16 detailed_status_code;
-       u8 reserved;
-       u8 req_status;
-} i2o_mult_reply_msg, *pi2o_mult_reply_msg;
-   
-#endif                         /* i2oproc_h */
index 3d4e7aaff34acbfee6e9efc36b7b536a0f9de13c..e383dbb4d3b5b14052a97cbd0669036307b3d757 100644 (file)
@@ -587,7 +587,7 @@ int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                m = I2O_POST_READ32(c);
        }
        while(m==0xFFFFFFFF);
-       msg = c->mem_offset + m;
+       msg = (u32 *)(c->mem_offset + m);
        
        /*
         *      Put together a scsi execscb message
index a9125785d57ad817a4a0a14387c7e8d1f6484a56..15959e6975557259d9a48645637d2ab6e063fdf5 100644 (file)
@@ -781,7 +781,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length
        isa_memcpy_toio(write_ptr+2, buf, length);
 
        /* Set the old command link pointing to this send packet. */
-       isa_isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);
+       isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);
        lp->tx_cmd_link = tx_block + 20;
 
        /* Set the next free tx region. */
index 490c0f3818868f5e868dd60165cdc0f026f9c74b..a68c55dfb7c07275ea966ec3c5d9c2b58f52ea2b 100644 (file)
@@ -3,8 +3,20 @@
 # Makefile for the Linux network (ethercard) device drivers.
 #
 
+O_OBJS          :=
+M_OBJS          :=
+MX_OBJS         :=
+
+# Object file lists.
+
+obj-y           :=
+obj-m           :=
+obj-n           :=
+obj-            :=
+
 SUB_DIRS     := 
-MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_SUB_DIRS :=
+MOD_IN_SUB_DIRS :=
 ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan
 
 L_TARGET := net.a
@@ -12,18 +24,11 @@ L_OBJS   := auto_irq.o
 M_OBJS   :=
 MOD_LIST_NAME := NET_MODULES
 
-# Need these to keep track of whether the 7990 (LANCE), 8390, PPP and SLHC 
-# modules should really go in the kernel or a module.
-CONFIG_8390_BUILTIN :=
-CONFIG_8390_MODULE  :=
-CONFIG_SLHC_BUILTIN :=
-CONFIG_SLHC_MODULE  :=
-CONFIG_PPPDEF_BUILTIN :=
-CONFIG_PPPDEF_MODULE  :=
-CONFIG_7990_BUILTIN :=
-CONFIG_7990_MODULE :=
-CONFIG_82596_BUILTIN :=
-CONFIG_82596_MODULE :=
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs     :=     8390.o arcnet.o arlan.o ppp_async.o \
+                       ppp_generic.o slhc.o
 
 ifeq ($(CONFIG_PCMCIA),y)
   SUB_DIRS += pcmcia
@@ -34,1077 +39,238 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_ISDN),y)
-  ifeq ($(CONFIG_ISDN_PPP),y)
-    CONFIG_SLHC_BUILTIN = y
-    CONFIG_PPPDEF_BUILTIN = y
-  endif
-else
-  ifeq ($(CONFIG_ISDN),m)
-    ifeq ($(CONFIG_ISDN_PPP),y)
-      CONFIG_SLHC_MODULE = y
-      CONFIG_PPPDEF_MODULE = y
-    endif
-  endif
-endif
-
-ifeq ($(CONFIG_NET),y)
-L_OBJS += Space.o setup.o net_init.o loopback.o
-endif
-
-ifeq ($(CONFIG_SEEQ8005),y)
-L_OBJS += seeq8005.o
-endif
-
-ifeq ($(CONFIG_ETHERTAP),y)
-L_OBJS += ethertap.o
-else
-  ifeq ($(CONFIG_ETHERTAP),m)
-  M_OBJS += ethertap.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SB1000),y)
-L_OBJS += sb1000.o
-else
-  ifeq ($(CONFIG_NET_SB1000),m)
-  M_OBJS += sb1000.o
-  endif
-endif
-
-ifeq ($(CONFIG_DAYNAPORT), y)
-L_OBJS += daynaport.o
-CONFIG_8390_BUILTIN = y
-endif
-
-ifeq ($(CONFIG_APNE),y)
-L_OBJS += apne.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_APNE),m)
-  M_OBJS += apne.o
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_PCMCIA_PCNET),y)
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_PCMCIA_PCNET),m)
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_SHAPER),y)
-L_OBJS += shaper.o
-else
-  ifeq ($(CONFIG_SHAPER),m)
-  M_OBJS += shaper.o
-  endif
-endif
-
-ifeq ($(CONFIG_SK_G16),y)
-L_OBJS += sk_g16.o
-endif
-
-ifeq ($(CONFIG_HP100),y)
-L_OBJS += hp100.o
-else
-  ifeq ($(CONFIG_HP100),m)
-  M_OBJS += hp100.o
-  endif
-endif
-
-ifeq ($(CONFIG_SMC9194),y)
-L_OBJS += smc9194.o
-else
-  ifeq ($(CONFIG_SMC9194),m)
-  M_OBJS += smc9194.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARM_AM79C961A),y)
-L_OBJS += am79c961a.o
-else
-  ifeq ($(CONFIG_ARM_AM79C961A),m)
-  M_OBJS += am79c961a.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARM_ETHERH),y)
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_ARM_ETHERH),m)
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_WD80x3),y)
-L_OBJS += wd.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_WD80x3),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += wd.o
-  endif
-endif
-
-ifeq ($(CONFIG_EL2),y)
-L_OBJS += 3c503.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_EL2),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += 3c503.o
-  endif
-endif
-
-ifeq ($(CONFIG_NE2K_PCI),y)
-L_OBJS += ne2k-pci.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_NE2K_PCI),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ne2k-pci.o
-  endif
-endif
-
-ifeq ($(CONFIG_NE2000),y)
-L_OBJS += ne.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_NE2000),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ne.o
-  endif
-endif
-
-ifeq ($(CONFIG_NE2_MCA),y)
-L_OBJS += ne2.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_NE2_MCA),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ne2.o
-  endif
-endif
-
-ifeq ($(CONFIG_HPLAN),y)
-L_OBJS += hp.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_HPLAN),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += hp.o
-  endif
-endif
-
-ifeq ($(CONFIG_HPLAN_PLUS),y)
-L_OBJS += hp-plus.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_HPLAN_PLUS),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += hp-plus.o
-  endif
-endif
-
-ifeq ($(CONFIG_ULTRA),y)
-L_OBJS += smc-ultra.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_ULTRA),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += smc-ultra.o
-  endif
-endif
-
-ifeq ($(CONFIG_ULTRAMCA),y)
-L_OBJS += smc-mca.o
-CONFIG_8390_BUILTIN = y
+ifeq ($(CONFIG_IRDA),y)
+SUB_DIRS += irda
+MOD_IN_SUB_DIRS += irda
 else
-  ifeq ($(CONFIG_ULTRAMCA),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += smc-mca.o
+  ifeq ($(CONFIG_IRDA),m)
+  MOD_IN_SUB_DIRS += irda
   endif
 endif
 
-ifeq ($(CONFIG_ULTRA32),y)
-L_OBJS += smc-ultra32.o
-CONFIG_8390_BUILTIN = y
+ifeq ($(CONFIG_TR),y)
+SUB_DIRS += tokenring
+MOD_IN_SUB_DIRS += tokenring
 else
-  ifeq ($(CONFIG_ULTRA32),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += smc-ultra32.o
+  ifeq ($(CONFIG_TR),m)
+  MOD_IN_SUB_DIRS += tokenring
   endif
 endif
 
-ifeq ($(CONFIG_E2100),y)
-L_OBJS += e2100.o
-CONFIG_8390_BUILTIN = y
+ifeq ($(CONFIG_WAN),y)
+SUB_DIRS += wan
+MOD_IN_SUB_DIRS += wan
 else
-  ifeq ($(CONFIG_E2100),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += e2100.o
+  ifeq ($(CONFIG_WAN),m)
+  MOD_IN_SUB_DIRS += wan
   endif
 endif
 
-ifeq ($(CONFIG_ES3210),y)
-L_OBJS += es3210.o
-CONFIG_8390_BUILTIN = y
+ifeq ($(CONFIG_NET_FC),y)
+SUB_DIRS += fc
+MOD_IN_SUB_DIRS += fc
 else
-  ifeq ($(CONFIG_ES3210),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += es3210.o
+  ifeq ($(CONFIG_NET_FC),m)
+  MOD_IN_SUB_DIRS += fc
   endif
 endif
 
-ifeq ($(CONFIG_LNE390),y)
-L_OBJS += lne390.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_LNE390),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += lne390.o
+ifeq ($(CONFIG_ISDN),y)
+  ifeq ($(CONFIG_ISDN_PPP),y)
+    obj-y += slhc.o ppp_deflate.o
   endif
-endif
-
-ifeq ($(CONFIG_NE3210),y)
-L_OBJS += ne3210.o
-CONFIG_8390_BUILTIN = y
 else
-  ifeq ($(CONFIG_NE3210),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ne3210.o
+  ifeq ($(CONFIG_ISDN),m)
+    ifeq ($(CONFIG_ISDN_PPP),y)
+      obj-m += slhc.o ppp_deflate.o
+    endif
   endif
 endif
 
-ifeq ($(CONFIG_PLIP),y)
-L_OBJS += plip.o
-else
-  ifeq ($(CONFIG_PLIP),m)
-  M_OBJS += plip.o
-  endif
-endif
+obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
+obj-$(CONFIG_SEEQ8005) += seeq8005.o
+obj-$(CONFIG_ETHERTAP) += ethertap.o
+obj-$(CONFIG_NET_SB1000) += sb1000.o
+obj-$(CONFIG_DAYNAPORT) += daynaport.o 8390.o
+obj-$(CONFIG_APNE) += apne.o 8390.o
+obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
+obj-$(CONFIG_SHAPER) += shaper.o
+obj-$(CONFIG_SK_G16) += sk_g16.o
+obj-$(CONFIG_HP100) += hp100.o
+obj-$(CONFIG_SMC9194) += smc9194.o
+obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
+obj-$(CONFIG_ARM_ETHERH) += 8390.o
+obj-$(CONFIG_WD80x3) += wd.o 8390.o
+obj-$(CONFIG_EL2) += 3c503.o 8390.o
+obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
+obj-$(CONFIG_NE2000) += ne.o 8390.o
+obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
+obj-$(CONFIG_HPLAN) += hp.o 8390.o
+obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
+obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
+obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
+obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
+obj-$(CONFIG_E2100) += e2100.o 8390.o
+obj-$(CONFIG_ES3210) += es3210.o 8390.o
+obj-$(CONFIG_LNE390) += lne390.o 8390.o
+obj-$(CONFIG_NE3210) += ne3210.o 8390.o
+obj-$(CONFIG_PLIP) += plip.o
 
 # bsd_comp.o is *always* a module, for some documented reason
 # (licensing).
 ifeq ($(CONFIG_PPP),y)
-LX_OBJS += ppp_generic.o
-CONFIG_SLHC_BUILTIN = y
-  ifeq ($(CONFIG_PPP_ASYNC),y)
-  LX_OBJS += ppp_async.o
-  else
-    ifeq ($(CONFIG_PPP_ASYNC),m)
-    MX_OBJS += ppp_async.o
-    endif
-  endif
-  ifeq ($(CONFIG_PPP_SYNC_TTY),y)
-  LX_OBJS += ppp_synctty.o
-  else
-    ifeq ($(CONFIG_PPP_SYNC_TTY),m)
-    MX_OBJS += ppp_synctty.o
-    endif
-  endif
-  ifeq ($(CONFIG_PPP_DEFLATE),y)
-  CONFIG_PPPDEF_BUILTIN = y
-  else
-    ifeq ($(CONFIG_PPP_DEFLATE),m)
-    CONFIG_PPPDEF_MODULE = y
-    endif
-  endif
+  obj-y += ppp_generic.o slhc.o
+  obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
+  obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+  obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
   ifeq ($(CONFIG_PPP_BSDCOMP),m)
-  M_OBJS += bsd_comp.o
+    obj-m += bsd_comp.o
   endif
 else
   ifeq ($(CONFIG_PPP),m)
-  MX_OBJS += ppp_generic.o
-  CONFIG_SLHC_MODULE = y
-    ifeq ($(CONFIG_PPP_ASYNC),m)
-    MX_OBJS += ppp_async.o
-    endif
-    ifeq ($(CONFIG_PPP_SYNC_TTY),m)
-    MX_OBJS += ppp_synctty.o
-    endif
-    ifeq ($(CONFIG_PPP_DEFLATE),m)
-    CONFIG_PPPDEF_MODULE = y
-    endif
+    obj-m += ppp_generic.o slhc.o
+    obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
+    obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+    obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
     ifeq ($(CONFIG_PPP_BSDCOMP),m)
-    M_OBJS += bsd_comp.o
+      obj-m += bsd_comp.o
     endif
   endif
 endif
 
+obj-$(CONFIG_SLIP) += slip.o
 ifeq ($(CONFIG_SLIP),y)
-L_OBJS += slip.o
-  ifeq ($(CONFIG_SLIP_COMPRESSED),y)
-  CONFIG_SLHC_BUILTIN = y
-  endif
+  obj-$(CONFIG_SLIP_COMPRESSED) += slhc.o
 else
   ifeq ($(CONFIG_SLIP),m)
-    ifeq ($(CONFIG_SLIP_COMPRESSED),y)
-    CONFIG_SLHC_MODULE = y
-  endif
-  M_OBJS += slip.o
-  endif
-endif
-
-ifeq ($(CONFIG_STRIP),y)
-L_OBJS += strip.o
-else
-  ifeq ($(CONFIG_STRIP),m)
-  M_OBJS += strip.o
-  endif
-endif
-
-ifeq ($(CONFIG_DE650),y)
-ETDRV_OBJS := $(L_OBJS) de650.o
-CONFIG_8390_BUILTIN = y
-endif
-
-ifeq ($(CONFIG_3C589),y)
-L_OBJS += 3c589.o
-endif
-
-ifeq ($(CONFIG_DUMMY),y)
-L_OBJS += dummy.o
-else
-  ifeq ($(CONFIG_DUMMY),m)
-  M_OBJS += dummy.o
-  endif
-endif
-
-ifeq ($(CONFIG_DE600),y)
-L_OBJS += de600.o
-else
-  ifeq ($(CONFIG_DE600),m)
-  M_OBJS += de600.o
-  endif
-endif
-
-ifeq ($(CONFIG_DE620),y)
-L_OBJS += de620.o
-else
-  ifeq ($(CONFIG_DE620),m)
-  M_OBJS += de620.o
-  endif
-endif
-
-ifeq ($(CONFIG_AT1500),y)
-L_OBJS += lance.o
-endif
-
-ifeq ($(CONFIG_LANCE),y)
-L_OBJS += lance.o
-else
-  ifeq ($(CONFIG_LANCE),m)
-  M_OBJS += lance.o
-  endif
-endif
-
-ifeq ($(CONFIG_SUN3LANCE),y)
-L_OBJS += sun3lance.o
-endif
-
-ifeq ($(CONFIG_PCNET32),y)
-L_OBJS += pcnet32.o
-else
-  ifeq ($(CONFIG_PCNET32),m)
-  M_OBJS += pcnet32.o
-  endif
-endif
-
-ifeq ($(CONFIG_DEFXX),y)
-L_OBJS += defxx.o
-endif
-
-ifeq ($(CONFIG_SUNLANCE),y)
-L_OBJS += sunlance.o
-else
-  ifeq ($(CONFIG_SUNLANCE),m)
-  M_OBJS += sunlance.o
-  endif
-endif
-
-ifeq ($(CONFIG_SGISEEQ), y)
-L_OBJS += sgiseeq.o
-endif
-
-ifeq ($(CONFIG_HAPPYMEAL),y)
-L_OBJS += sunhme.o
-else
-  ifeq ($(CONFIG_HAPPYMEAL),m)
-  M_OBJS += sunhme.o
-  endif
-endif
-
-ifeq ($(CONFIG_SUNQE),y)
-L_OBJS += sunqe.o
-else
-  ifeq ($(CONFIG_SUNQE),m)
-  M_OBJS += sunqe.o
-  endif
-endif
-
-ifeq ($(CONFIG_SUNBMAC),y)
-L_OBJS += sunbmac.o
-else
-  ifeq ($(CONFIG_SUNBMAC),m)
-  M_OBJS += sunbmac.o
-  endif
-endif
-
-ifeq ($(CONFIG_SUNBMAC),y)
-L_OBJS += sunbmac.o
-else
-  ifeq ($(CONFIG_SUNBMAC),m)
-  M_OBJS += sunbmac.o
-  endif
-endif
-
-ifeq ($(CONFIG_MYRI_SBUS),y)
-L_OBJS += myri_sbus.o
-else
-  ifeq ($(CONFIG_MYRI_SBUS),m)
-  M_OBJS += myri_sbus.o
-  endif
-endif
-
-ifeq ($(CONFIG_AT1700),y)
-L_OBJS += at1700.o
-else
-  ifeq ($(CONFIG_AT1700),m)
-  M_OBJS += at1700.o
-  endif
-endif
-
-ifeq ($(CONFIG_FMV18X),y)
-L_OBJS += fmv18x.o
-else
-  ifeq ($(CONFIG_FMV18X),m)
-  M_OBJS += fmv18x.o
-  endif
-endif
-
-ifeq ($(CONFIG_EL1),y)
-L_OBJS += 3c501.o
-else
-  ifeq ($(CONFIG_EL1),m)
-  M_OBJS += 3c501.o
-  endif
-endif
+    obj-$(CONFIG_SLIP_COMPRESSED) += slhc.o
+  endif
+endif
+
+obj-$(CONFIG_STRIP) += strip.o
+obj-$(CONFIG_DE650) += de650.o 8390.o
+obj-$(CONFIG_3C589) += 3c589.o
+obj-$(CONFIG_DUMMY) += dummy.o
+obj-$(CONFIG_DE600) += de600.o
+obj-$(CONFIG_DE620) += de620.o
+obj-$(CONFIG_AT1500) += lance.o
+obj-$(CONFIG_LANCE) += lance.o
+obj-$(CONFIG_SUN3LANCE) += sun3lance.o
+obj-$(CONFIG_PCNET32) += pcnet32.o
+obj-$(CONFIG_DEFXX) += defxx.o
+obj-$(CONFIG_SUNLANCE) += sunlance.o
+obj-$(CONFIG_SGISEEQ) += sgiseeq.o
+obj-$(CONFIG_HAPPYMEAL) += sunhme.o
+obj-$(CONFIG_SUNQE) += sunqe.o
+obj-$(CONFIG_SUNBMAC) += sunbmac.o
+obj-$(CONFIG_SUNBMAC) += sunbmac.o
+obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
+obj-$(CONFIG_AT1700) += at1700.o
+obj-$(CONFIG_FMV18X) += fmv18x.o
+obj-$(CONFIG_EL1) += 3c501.o
+obj-$(CONFIG_EL16) += 3c507.o
+obj-$(CONFIG_ELMC) += 3c523.o
+obj-$(CONFIG_SKMC) += sk_mca.o
+obj-$(CONFIG_ELMC_II) += 3c527.o
+obj-$(CONFIG_EL3) += 3c509.o
+obj-$(CONFIG_3C515) += 3c515.o
+obj-$(CONFIG_VORTEX) += 3c59x.o
+obj-$(CONFIG_EEXPRESS) += eexpress.o
+obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o
+obj-$(CONFIG_RTL8139) += rtl8139.o
+obj-$(CONFIG_SIS900) += sis900.o
+obj-$(CONFIG_DM9102) += dmfe.o
+obj-$(CONFIG_YELLOWFIN) += yellowfin.o
+obj-$(CONFIG_ACENIC) += acenic.o
+obj-$(CONFIG_WAVELAN) += wavelan.o
+obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
+obj-$(CONFIG_TLAN) += tlan.o
+obj-$(CONFIG_VIA_RHINE) += via-rhine.o
+obj-$(CONFIG_ZNET) += znet.o
+obj-$(CONFIG_DEPCA) += depca.o
+obj-$(CONFIG_EWRK3) += ewrk3.o
+obj-$(CONFIG_ATP) += atp.o
+obj-$(CONFIG_DE4X5) += de4x5.o
+obj-$(CONFIG_NI5010) += ni5010.o
+obj-$(CONFIG_NI52) += ni52.o
+obj-$(CONFIG_NI65) += ni65.o
+obj-$(CONFIG_ELPLUS) += 3c505.o
+obj-$(CONFIG_AC3200) += ac3200.o 8390.o
+obj-$(CONFIG_APRICOT) += 82596.o
+obj-$(CONFIG_MVME16x_NET) += 82596.o
+obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_DEC_ELCP) += tulip.o
+obj-$(CONFIG_ARCNET) += arcnet.o
+obj-$(CONFIG_ARCNET_COM90xx) += com90xx.o
+obj-$(CONFIG_ARCNET_COM90xxIO) += com90io.o
+obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o
+obj-$(CONFIG_ARCNET_COM20020) += com20020.o
+obj-$(CONFIG_ETH16I) += eth16i.o
+obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o
+obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
+obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
+obj-$(CONFIG_EQUALIZER) += eql.o
+obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
+obj-$(CONFIG_BAGETLANCE) += bagetlance.o
+obj-$(CONFIG_DECLANCE) += declance.o
+obj-$(CONFIG_ATARILANCE) += atarilance.o
+obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
+obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
+obj-$(CONFIG_A2065) += a2065.o
+obj-$(CONFIG_HYDRA) += hydra.o
+obj-$(CONFIG_ARIADNE) += ariadne.o
+obj-$(CONFIG_DGRS) += dgrs.o
+obj-$(CONFIG_CS89x0) += cs89x0.o
+obj-$(CONFIG_LTPC) += ltpc.o
+obj-$(CONFIG_COPS) += cops.o
+obj-$(CONFIG_IPDDP) += ipddp.o
+obj-$(CONFIG_RCPCI) += rcpci.o
+obj-$(CONFIG_MACE) += mace.o
+obj-$(CONFIG_MACSONIC) += macsonic.o
+obj-$(CONFIG_BMAC) += bmac.o
+obj-$(CONFIG_NCR885E) += ncr885e.o
+obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 
-ifeq ($(CONFIG_EL16),y)
-L_OBJS += 3c507.o
-else
-  ifeq ($(CONFIG_EL16),m)
-  M_OBJS += 3c507.o
-  endif
-endif
+#
+# HIPPI adapters
+#
 
-ifeq ($(CONFIG_ELMC),y)
-L_OBJS += 3c523.o
-else
-  ifeq ($(CONFIG_ELMC),m)
-  M_OBJS += 3c523.o
-  endif
-endif
+obj-$(CONFIG_ROADRUNNER) += rrunner.o
 
-ifeq ($(CONFIG_SKMC),y)
-L_OBJS += sk_mca.o
-else
-  ifeq ($(CONFIG_SKMC),m)
-  M_OBJS += sk_mca.o
-  endif
-endif
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
 
-ifeq ($(CONFIG_ELMC_II),y)
-L_OBJS += 3c527.o
-else
-  ifeq ($(CONFIG_ELMC_II),m)
-  M_OBJS += 3c527.o
-  endif
-endif
+multi-y         := $(filter $(list-multi), $(obj-y))
+multi-m         := $(filter $(list-multi), $(obj-m))
+int-y           := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m           := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
 
-ifeq ($(CONFIG_EL3),y)
-L_OBJS += 3c509.o
-else
-  ifeq ($(CONFIG_EL3),m)
-  M_OBJS += 3c509.o
-  endif
-endif
+# Files that are both resident and modular: remove from modular.
 
-ifeq ($(CONFIG_3C515),y)
-L_OBJS += 3c515.o
-else
-  ifeq ($(CONFIG_3C515),m)
-  M_OBJS += 3c515.o
-  endif
-endif
+obj-m           := $(filter-out $(obj-y), $(obj-m))
+int-m           := $(filter-out $(int-y), $(int-m))
 
-ifeq ($(CONFIG_VORTEX),y)
-L_OBJS += 3c59x.o
-else
-  ifeq ($(CONFIG_VORTEX),m)
-  M_OBJS += 3c59x.o
-  endif
-endif
+# Take multi-part drivers out of obj-y and put components in.
 
-ifeq ($(CONFIG_EEXPRESS),y)
-L_OBJS += eexpress.o
-else
-  ifeq ($(CONFIG_EEXPRESS),m)
-  M_OBJS += eexpress.o
-  endif
-endif
+obj-y           := $(filter-out $(list-multi), $(obj-y)) $(int-y)
 
-ifeq ($(CONFIG_EEXPRESS_PRO),y)
-L_OBJS += eepro.o
-else
-  ifeq ($(CONFIG_EEXPRESS_PRO),m)
-  M_OBJS += eepro.o
-  endif
-endif
+# Translate to Rules.make lists.
 
-ifeq ($(CONFIG_EEXPRESS_PRO100),y)
-L_OBJS += eepro100.o
-else
-  ifeq ($(CONFIG_EEXPRESS_PRO100),m)
-  M_OBJS += eepro100.o
-  endif
-endif
+O_OBJS          := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS         := $(filter     $(export-objs), $(obj-y))
+M_OBJS          := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS         := $(sort $(filter     $(export-objs), $(obj-m)))
 
-ifeq ($(CONFIG_RTL8139),y)
-L_OBJS += rtl8139.o
-else
-  ifeq ($(CONFIG_RTL8139),m)
-  M_OBJS += rtl8139.o
-  endif
-endif
+L_OBJS += $(O_OBJS)
+L_OBJS += $(OX_OBJS)
 
-ifeq ($(CONFIG_SIS900),y)
-L_OBJS += sis900.o
-else
-  ifeq ($(CONFIG_SIS900),m)
-  M_OBJS += sis900.o
-  endif
-endif
+include $(TOPDIR)/Rules.make
 
-ifeq ($(CONFIG_DM9102),y) 
-L_OBJS += dmfe.o
-else
-  ifeq ($(CONFIG_DM9102),m)
-  M_OBJS += dmfe.o
-  endif
-endif
+clean:
+       rm -f core *.o *.a *.s
 
+rcpci.o: rcpci45.o rclanmtl.o
+       $(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
 
-ifeq ($(CONFIG_YELLOWFIN),y)
-L_OBJS += yellowfin.o
-else
-  ifeq ($(CONFIG_YELLOWFIN),m)
-  M_OBJS += yellowfin.o
-  endif
-endif
-
-ifeq ($(CONFIG_ACENIC),y)
-L_OBJS += acenic.o
-else
-  ifeq ($(CONFIG_ACENIC),m)
-  M_OBJS += acenic.o
-  endif
-endif
-
-ifeq ($(CONFIG_WAVELAN),y)
-L_OBJS += wavelan.o
-else
-  ifeq ($(CONFIG_WAVELAN),m)
-  M_OBJS += wavelan.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARLAN),y)
-LX_OBJS += arlan.o arlan-proc.o
-else
-  ifeq ($(CONFIG_ARLAN),m)
-  MX_OBJS += arlan.o arlan-proc.o
-  endif
-endif
-
-ifeq ($(CONFIG_TLAN),y)
-L_OBJS += tlan.o
-else
-  ifeq ($(CONFIG_TLAN),m)
-  M_OBJS += tlan.o
-  endif
-endif
-
-ifeq ($(CONFIG_VIA_RHINE),y)
-L_OBJS += via-rhine.o
-else
-  ifeq ($(CONFIG_VIA_RHINE),m)
-  M_OBJS += via-rhine.o
-  endif
-endif
-
-ifeq ($(CONFIG_ZNET),y)
-L_OBJS += znet.o
-endif
-
-ifeq ($(CONFIG_DEPCA),y)
-L_OBJS += depca.o
-else
-  ifeq ($(CONFIG_DEPCA),m)
-  M_OBJS += depca.o
-  endif
-endif
-
-ifeq ($(CONFIG_EWRK3),y)
-L_OBJS += ewrk3.o
-else
-  ifeq ($(CONFIG_EWRK3),m)
-  M_OBJS += ewrk3.o
-  endif
-endif
-
-ifeq ($(CONFIG_ATP),y)
-L_OBJS += atp.o
-endif
-
-ifeq ($(CONFIG_DE4X5),y)
-L_OBJS += de4x5.o
-else
-  ifeq ($(CONFIG_DE4X5),m)
-  M_OBJS += de4x5.o
-  endif
-endif
-
-ifeq ($(CONFIG_NI5010),y)
-L_OBJS += ni5010.o
-else
-  ifeq ($(CONFIG_NI5010),m)
-  M_OBJS += ni5010.o
-  endif
-endif
-
-ifeq ($(CONFIG_NI52),y)
-L_OBJS += ni52.o
-else
-  ifeq ($(CONFIG_NI52),m)
-  M_OBJS += ni52.o
-  endif
-endif
-
-ifeq ($(CONFIG_NI65),y)
-L_OBJS += ni65.o
-else
-  ifeq ($(CONFIG_NI65),m)
-  M_OBJS += ni65.o
-  endif
-endif
-
-ifeq ($(CONFIG_ELPLUS),y)
-L_OBJS += 3c505.o
-else
-  ifeq ($(CONFIG_ELPLUS),m)
-  M_OBJS += 3c505.o
-  endif
-endif
-
-ifeq ($(CONFIG_AC3200),y)
-L_OBJS += ac3200.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_AC3200),m)
-  CONFIG_8390_MODULE = y
-  M_OBJS += ac3200.o
-  endif
-endif
-
-ifeq ($(CONFIG_APRICOT),y)
-CONFIG_82596_BUILTIN = y
-else
-  ifeq ($(CONFIG_APRICOT),m)
-  CONFIG_82596_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_MVME16x_NET),y)
-CONFIG_82596_BUILTIN = y
-else
-  ifeq ($(CONFIG_MVME16x_NET),m)
-  CONFIG_82596_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_BVME6000_NET),y)
-CONFIG_82596_BUILTIN = y
-else
-  ifeq ($(CONFIG_BVME6000_NET),m)
-  CONFIG_82596_MODULE = y
-  endif
-endif
-
-ifeq ($(CONFIG_DEC_ELCP),y)
-L_OBJS += tulip.o
-else
-  ifeq ($(CONFIG_DEC_ELCP),m)
-  M_OBJS += tulip.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARCNET),y)
-LX_OBJS += arcnet.o
-else
-  ifeq ($(CONFIG_ARCNET),m)
-  MX_OBJS += arcnet.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARCNET_COM90xx),y)
-L_OBJS += com90xx.o
-else
-  ifeq ($(CONFIG_ARCNET_COM90xx),m)
-  M_OBJS += com90xx.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARCNET_COM90xxIO),y)
-L_OBJS += com90io.o
-else
-  ifeq ($(CONFIG_ARCNET_COM90xxIO),m)
-  M_OBJS += com90io.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARCNET_RIM_I),y)
-L_OBJS += arc-rimi.o
-else
-  ifeq ($(CONFIG_ARCNET_RIM_I),m)
-  M_OBJS += arc-rimi.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARCNET_COM20020),y)
-L_OBJS += com20020.o
-else
-  ifeq ($(CONFIG_ARCNET_COM20020),m)
-  M_OBJS += com20020.o
-  endif
-endif
-
-ifeq ($(CONFIG_ETH16I),y)
-L_OBJS += eth16i.o
-else
-  ifeq ($(CONFIG_ETH16I),m)
-  M_OBJS += eth16i.o
-  endif
-endif
-
-ifeq ($(CONFIG_EPIC100),y)
-L_OBJS += epic100.o
-else
-  ifeq ($(CONFIG_EPIC100),m)
-  M_OBJS += epic100.o
-  endif
-endif
-
-# If anything built-in uses slhc, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-ifdef CONFIG_SLHC_BUILTIN
-LX_OBJS += slhc.o
-else
-  ifdef CONFIG_SLHC_MODULE
-  MX_OBJS += slhc.o
-  endif
-endif
-
-# if anything built-in uses ppp_deflate, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-ifdef CONFIG_PPPDEF_BUILTIN
-L_OBJS += ppp_deflate.o
-else
-  ifdef CONFIG_PPPDEF_MODULE
-  M_OBJS += ppp_deflate.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARIADNE2),y)
-L_OBJS += ariadne2.o
-CONFIG_8390_BUILTIN = y
-else
-  ifeq ($(CONFIG_ARIADNE2),m)
-  M_OBJS += ariadne2.o
-  CONFIG_8390_MODULE = y
-  endif
-endif
-
-# If anything built-in uses the 8390, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-ifdef CONFIG_8390_BUILTIN
-L_OBJS += 8390.o
-else
-  ifdef CONFIG_8390_MODULE
-  MX_OBJS += 8390.o
-  endif
-endif
-
-ifeq ($(CONFIG_HPLANCE),y)
-L_OBJS += hplance.o
-CONFIG_7990_BUILTIN = y
-else
-  ifeq ($(CONFIG_HPLANCE),m)
-  CONFIG_7990_MODULE = y
-  M_OBJS += hplance.o
-  endif
-endif
-
-ifeq ($(CONFIG_MVME147_NET),y)
-L_OBJS += mvme147.o
-CONFIG_7990_BUILTIN = y
-else
-  ifeq ($(CONFIG_MVME147_NET),m)
-  CONFIG_7990_MODULE = y
-  M_OBJS += mvme147.o
-  endif
-endif
-
-# If we need generic LANCE support, either in the kernel or as a module,
-# build it in the appropriate way.
-ifdef CONFIG_7990_BUILTIN
-L_OBJS += 7990.o
-else
-  ifdef CONFIG_7990_MODULE
-  M_OBJS += 7990.o
-  endif
-endif
-
-# If anything built-in uses the 82596, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-ifdef CONFIG_82596_BUILTIN
-L_OBJS += 82596.o
-else
-  ifdef CONFIG_82596_MODULE
-  M_OBJS += 82596.o
-  endif
-endif
-
-ifeq ($(CONFIG_EQUALIZER),y)
-L_OBJS += eql.o
-else
-  ifeq ($(CONFIG_EQUALIZER),m)
-  M_OBJS += eql.o
-  endif
-endif
-
-ifeq ($(CONFIG_MIPS_JAZZ_SONIC),y)
-L_OBJS += jazzsonic.o
-else
-  ifeq ($(CONFIG_MIPS_JAZZ_SONIC),m)
-  M_OBJS += jazzsonic.o
-  endif
-endif
-
-ifeq ($(CONFIG_BAGETLANCE),y)
-L_OBJS += bagetlance.o
-else
-  ifeq ($(CONFIG_BAGETLANCE),m)
-  M_OBJS += bagetlance.o
-  endif
-endif
-
-ifeq ($(CONFIG_DECLANCE),y)
-L_OBJS += declance.o
-else
-  ifeq ($(CONFIG_DECLANCE),m)
-  M_OBJS += declance.o
-  endif
-endif
-
-ifeq ($(CONFIG_ATARILANCE),y)
-L_OBJS += atarilance.o
-else
-  ifeq ($(CONFIG_ATARILANCE),m)
-  M_OBJS += atarilance.o
-  endif
-endif
-
-ifeq ($(CONFIG_ATARI_BIONET),y)
-L_OBJS += atari_bionet.o
-else
-  ifeq ($(CONFIG_ATARI_BIONET),m)
-  M_OBJS += atari_bionet.o
-  endif
-endif
-
-ifeq ($(CONFIG_ATARI_PAMSNET),y)
-L_OBJS += atari_pamsnet.o
-else
-  ifeq ($(CONFIG_ATARI_PAMSNET),m)
-  M_OBJS += atari_pamsnet.o
-  endif
-endif
-
-ifeq ($(CONFIG_A2065),y)
-L_OBJS += a2065.o
-else
-  ifeq ($(CONFIG_A2065),m)
-  M_OBJS += a2065.o
-  endif
-endif
-
-ifeq ($(CONFIG_HYDRA),y)
-L_OBJS += hydra.o
-else
-  ifeq ($(CONFIG_HYDRA),m)
-  M_OBJS += hydra.o
-  endif
-endif
-
-ifeq ($(CONFIG_ARIADNE),y)
-L_OBJS += ariadne.o
-else
-  ifeq ($(CONFIG_ARIADNE),m)
-  M_OBJS += ariadne.o
-  endif
-endif
-
-ifeq ($(CONFIG_DGRS),y)
-L_OBJS += dgrs.o
-else
-  ifeq ($(CONFIG_DGRS),m)
-  M_OBJS += dgrs.o
-  endif
-endif
-
-ifeq ($(CONFIG_CS89x0),y)
-L_OBJS += cs89x0.o
-else
-  ifeq ($(CONFIG_CS89x0),m)
-  M_OBJS += cs89x0.o
-  endif
-endif
-
-ifeq ($(CONFIG_LTPC),y)
-L_OBJS += ltpc.o
-else
-  ifeq ($(CONFIG_LTPC),m)
-  M_OBJS += ltpc.o
-  endif
-endif
-
-ifeq ($(CONFIG_COPS),y)
-L_OBJS += cops.o
-else
-  ifeq ($(CONFIG_COPS),m)
-  M_OBJS += cops.o
-  endif
-endif
-
-ifeq ($(CONFIG_IPDDP),y)
-L_OBJS += ipddp.o
-else
-  ifeq ($(CONFIG_IPDDP),m)
-  M_OBJS += ipddp.o
-  endif
-endif
-
-ifeq ($(CONFIG_RCPCI),y)
-L_OBJS += rcpci.o
-else
-  ifeq ($(CONFIG_RCPCI),m)
-  M_OBJS += rcpci.o
-  endif
-endif
-
-ifeq ($(CONFIG_MACE),y)
-L_OBJS += mace.o
-else
-  ifeq ($(CONFIG_MACE),m)
-  M_OBJS += mace.o
-  endif
-endif
-
-ifeq ($(CONFIG_MACSONIC),y)
-L_OBJS += macsonic.o
-endif
-
-ifeq ($(CONFIG_BMAC),y)
-L_OBJS += bmac.o
-else
-  ifeq ($(CONFIG_BMAC),m)
-  M_OBJS += bmac.o
-  endif
-endif
-
-ifeq ($(CONFIG_NCR885E),y)
-L_OBJS += ncr885e.o
-else
-  ifeq ($(CONFIG_NCR885E),m)
-  M_OBJS += ncr885e.o
-  endif
-endif
-
-ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
-L_OBJS += starfire.o
-else
-  ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
-  M_OBJS += starfire.o
-  endif
-endif
-
-#
-# HIPPI adapters
-#
-
-ifeq ($(CONFIG_ROADRUNNER),y)
-L_OBJS += rrunner.o
-else
-  ifeq ($(CONFIG_ROADRUNNER),m)
-  M_OBJS += rrunner.o
-  endif
-endif
-
-ifeq ($(CONFIG_IRDA),y)
-SUB_DIRS += irda
-MOD_IN_SUB_DIRS += irda
-else
-  ifeq ($(CONFIG_IRDA),m)
-  MOD_IN_SUB_DIRS += irda
-  endif
-endif
-
-ifeq ($(CONFIG_TR),y)
-SUB_DIRS += tokenring
-MOD_IN_SUB_DIRS += tokenring
-else
-  ifeq ($(CONFIG_TR),m)
-  MOD_IN_SUB_DIRS += tokenring
-  endif
-endif
-
-ifeq ($(CONFIG_WAN),y)
-SUB_DIRS += wan
-MOD_IN_SUB_DIRS += wan
-else
-  ifeq ($(CONFIG_WAN),m)
-  MOD_IN_SUB_DIRS += wan
-  endif
-endif
-
-ifeq ($(CONFIG_NET_FC),y)
-SUB_DIRS += fc
-MOD_IN_SUB_DIRS += fc
-else
-  ifeq ($(CONFIG_NET_FC),m)
-  MOD_IN_SUB_DIRS += fc
-  endif
-endif
-
-include $(TOPDIR)/Rules.make
-
-clean:
-       rm -f core *.o *.a *.s
-
-rcpci.o: rcpci45.o rclanmtl.o
-       $(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
index 43032d95d2136e4b6735c01ebf0a75761b090f83..fbd75ca052aae531283e717496622fe947321153 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/init.h>
 #include <linux/version.h>
 
 #include <linux/delay.h>
index 6f7eda2ed7945c0608103eebe2cf06c8a1a25a3e..a9b0f16c08a913854cca139abf6849f528e7e629 100644 (file)
@@ -344,7 +344,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
                isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
        } else {
                /* Packet is in one chunk. */
-               isa_eth_io_copy_and_csum(skb, xfer_start, count, 0);
+               isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
        }
 }
 
index f5e403e3e17d10aa8eb1f9d7a8f3b7c4837c1548..d7c7fb23900e22058368c34e19684e754f780f5a 100644 (file)
@@ -33,7 +33,6 @@ static const char *version =
 #include <linux/malloc.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
-#include <linux/malloc.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/errno.h>
index 4467b8af60fd62e77b4bf4a040ea3577509d92c4..b147dfef9d5f1dad40ee4d35d504b443114232da 100644 (file)
@@ -2683,7 +2683,7 @@ static int __init init_ray_cs(void)
     DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
 #ifdef CONFIG_PROC_FS    
     /* [proc-namespace][fixme] It shouldn't be under root, damnit! */
-    create_proc_info_entry("ray_cs", 0, proc_root, ray_cs_proc_read);
+    create_proc_info_entry("ray_cs", 0, &proc_root, ray_cs_proc_read);
 #endif    
     if (translate != 0) translate = 1;
     return 0;
@@ -2714,7 +2714,7 @@ static void __exit exit_ray_cs(void)
         ray_detach(dev_list);
     }
 #ifdef CONFIG_PROC_FS    
-    remove_proc_entry("ray_cs", proc_root);
+    remove_proc_entry("ray_cs", &proc_root);
 #endif   
 } /* exit_ray_cs */
 
index 17a33841ecf7f6f436420296f0c37b12c58d4770..9026441624bcced7f7b758a8d5521ec4f079d427 100644 (file)
@@ -71,7 +71,6 @@ History:
 #include <linux/version.h>
 
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
index 2056501c2b20bdd2c007d6f93d5627da596d7715..ed78f8cf9340cb6ef55d753f4467835cd45ff6b5 100644 (file)
@@ -58,7 +58,7 @@ else
 endif
 
 ifeq ($(CONFIG_BLK_DEV_SD),y)
-L_OBJS += sd.o sd_ioctl.o
+L_OBJS += sd.o
 else
   ifeq ($(CONFIG_BLK_DEV_SD),m)
   M_OBJS += sd_mod.o
@@ -729,5 +729,5 @@ scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
 sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
        $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
 
-sd_mod.o: sd.o sd_ioctl.o
-       $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
+sd_mod.o: sd.o
+       $(LD) $(LD_RFLAG) -r -o $@ sd.o
index 93d084cbfe9324c2999bc22b1ec7c1cd107228d1..59a6bee98f9eb1dd75be81ddff8782ee27d2d9d0 100644 (file)
 #include "atari_scsi.h"
 #endif
 
-#ifdef CONFIG_MAC_SCSI_OLD
+#if defined(CONFIG_MAC_SCSI) || defined(CONFIG_MAC_SCSI_OLD)
 #include "mac_scsi.h"
 #endif
 
 #include "sun3_scsi.h"
 #endif
 
-#ifdef CONFIG_MAC_SCSI
-#include "mac_scsi.h"
-#endif
-
 #ifdef CONFIG_SCSI_MAC_ESP
 #include "mac_esp.h"
 #endif
index eab18bad12d763e538a3357d79c50360c31a9216..5203b6e3692349fdb9d68eda40f600fa2025301c 100644 (file)
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
-#include <asm/io.h>
 #include <asm/irq.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <linux/spinlock.h>
 #endif
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "inia100.h"
 #include <linux/stat.h>
-#include <linux/malloc.h>
 #include <linux/config.h>
 
-
 #else
 
-#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
+#include <asm/system.h>
+#include "../block/blk.h"
+#endif
+
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "inia100.h"
-#endif
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = INIA100;
index a2876d17cdb1ac8348697b06f22fddfe22de55d2..9b4de06f3fafe165f9e48e28fb7e9c00106d6c08 100644 (file)
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/string.h>
+#include <linux/hdreg.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 
 #include <linux/smp.h>
 
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
 #define MAJOR_NR SCSI_DISK0_MAJOR
 #include <linux/blk.h>
+#include <linux/blkpg.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include <scsi/scsi_ioctl.h>
 #include "constants.h"
+#include <scsi/scsicam.h>      /* must follow "hosts.h" */
 
 #include <linux/genhd.h>
 
@@ -87,8 +91,6 @@ static int *sd_sizes;
 static int *sd_blocksizes;
 static int *sd_hardsizes;      /* Hardware sector size */
 
-extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-
 static int check_scsidisk_media_change(kdev_t);
 static int fop_revalidate_scsidisk(kdev_t);
 
@@ -102,6 +104,83 @@ static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
 
+static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+{
+    kdev_t dev = inode->i_rdev;
+    int error;
+    struct Scsi_Host * host;
+    Scsi_Device * SDev;
+    int diskinfo[4];
+    struct hd_geometry *loc = (struct hd_geometry *) arg;
+    
+    SDev = rscsi_disks[DEVICE_NR(dev)].device;
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(SDev) )
+      {
+        return -ENODEV;
+      }
+
+    switch (cmd) {
+    case HDIO_GETGEO:   /* Return BIOS disk parameters */
+       if (!loc)  return -EINVAL;
+       error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
+       if (error)
+           return error;
+       host = rscsi_disks[DEVICE_NR(dev)].device->host;
+
+/* default to most commonly used values */
+
+        diskinfo[0] = 0x40;
+        diskinfo[1] = 0x20;
+        diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
+
+/* override with calculated, extended default, or driver values */
+
+       if(host->hostt->bios_param != NULL)
+           host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
+                                   dev,
+                                   &diskinfo[0]);
+        else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
+                               dev, &diskinfo[0]);
+
+       put_user(diskinfo[0], &loc->heads);
+       put_user(diskinfo[1], &loc->sectors);
+       put_user(diskinfo[2], &loc->cylinders);
+       put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start);
+       return 0;
+    case BLKGETSIZE:   /* Return device size */
+       if (!arg)  return -EINVAL;
+       error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+       if (error)
+           return error;
+       put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects,
+                (long *) arg);
+       return 0;
+
+    case BLKROSET:
+    case BLKROGET:
+    case BLKRASET:
+    case BLKRAGET:
+    case BLKFLSBUF:
+    case BLKSSZGET:
+    case BLKPG:
+       return blk_ioctl(inode->i_rdev, cmd, arg);
+
+    case BLKRRPART: /* Re-read partition tables */
+        if (!capable(CAP_SYS_ADMIN))
+                return -EACCES;
+       return revalidate_scsidisk(dev, 1);
+
+    default:
+       return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg);
+    }
+}
+
 static void sd_devname(unsigned int disknum, char *buffer)
 {
        if (disknum < 26)
diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c
deleted file mode 100644 (file)
index 486d911..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * drivers/scsi/sd_ioctl.c
- *
- * ioctl handling for SCSI disks
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/hdreg.h>
-#include <linux/errno.h>
-
-#include <asm/uaccess.h>
-
-#define MAJOR_NR       SCSI_DISK0_MAJOR
-#include <linux/blk.h>
-#include <linux/blkpg.h>
-#include "scsi.h"
-#include <scsi/scsi_ioctl.h>
-#include "hosts.h"
-#include "sd.h"
-#include <scsi/scsicam.h>     /* must follow "hosts.h" */
-
-int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
-{
-    kdev_t dev = inode->i_rdev;
-    int error;
-    struct Scsi_Host * host;
-    Scsi_Device * SDev;
-    int diskinfo[4];
-    struct hd_geometry *loc = (struct hd_geometry *) arg;
-    
-    SDev = rscsi_disks[DEVICE_NR(dev)].device;
-    /*
-     * If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.
-     */
-    if( !scsi_block_when_processing_errors(SDev) )
-      {
-        return -ENODEV;
-      }
-
-    switch (cmd) {
-    case HDIO_GETGEO:   /* Return BIOS disk parameters */
-       if (!loc)  return -EINVAL;
-       error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
-       if (error)
-           return error;
-       host = rscsi_disks[DEVICE_NR(dev)].device->host;
-
-/* default to most commonly used values */
-
-        diskinfo[0] = 0x40;
-        diskinfo[1] = 0x20;
-        diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;
-
-/* override with calculated, extended default, or driver values */
-
-       if(host->hostt->bios_param != NULL)
-           host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],
-                                   dev,
-                                   &diskinfo[0]);
-        else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],
-                               dev, &diskinfo[0]);
-
-       put_user(diskinfo[0], &loc->heads);
-       put_user(diskinfo[1], &loc->sectors);
-       put_user(diskinfo[2], &loc->cylinders);
-       put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start);
-       return 0;
-    case BLKGETSIZE:   /* Return device size */
-       if (!arg)  return -EINVAL;
-       error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
-       if (error)
-           return error;
-       put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects,
-                (long *) arg);
-       return 0;
-
-    case BLKROSET:
-    case BLKROGET:
-    case BLKRASET:
-    case BLKRAGET:
-    case BLKFLSBUF:
-    case BLKSSZGET:
-    case BLKPG:
-       return blk_ioctl(inode->i_rdev, cmd, arg);
-
-    case BLKRRPART: /* Re-read partition tables */
-        if (!capable(CAP_SYS_ADMIN))
-                return -EACCES;
-       return revalidate_scsidisk(dev, 1);
-
-    default:
-       return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg);
-    }
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
index 15fcf29ec9eb91fb0dd5d4468695eb319e98d149..20dca257180f2b4c2570cdb48b469584e78570be 100644 (file)
@@ -37,7 +37,7 @@ endif
 
 ifeq ($(CONFIG_USB_UHCI),m)
       M_OBJS += usb-uhci.o
-    MIX_OBJS += uhci.o uhci-debug.o
+      MI_OBJS += uhci.o uhci-debug.o
 endif
 
 ifeq ($(CONFIG_USB_OHCI),y)
@@ -45,7 +45,7 @@ ifeq ($(CONFIG_USB_OHCI),y)
 endif
 ifeq ($(CONFIG_USB_OHCI),m)
       M_OBJS += usb-ohci.o
-      MIX_OBJS += ohci.o ohci-debug.o
+      MI_OBJS += ohci.o ohci-debug.o
 endif
 
 ifeq ($(CONFIG_USB_OHCI_HCD),y)
@@ -53,7 +53,7 @@ ifeq ($(CONFIG_USB_OHCI_HCD),y)
 endif
 ifeq ($(CONFIG_USB_OHCI_HCD),m)
       M_OBJS += usb-ohci-hcd.o
-      MIX_OBJS += ohci-hcd.o ohci-root-hub.o
+      MI_OBJS += ohci-hcd.o ohci-root-hub.o
 endif
 
 ifeq ($(CONFIG_USB_MOUSE),y)
@@ -61,7 +61,7 @@ ifeq ($(CONFIG_USB_MOUSE),y)
 endif
 ifeq ($(CONFIG_USB_MOUSE),m)
   M_OBJS += mouse.o    
-  MIX_OBJS += mouse.o
+  MI_OBJS += mouse.o
 endif
 
 ifeq ($(CONFIG_USB_HP_SCANNER),y)
@@ -69,7 +69,7 @@ ifeq ($(CONFIG_USB_HP_SCANNER),y)
 endif
 ifeq ($(CONFIG_USB_HP_SCANNER),m)
   M_OBJS  +=hp_scanner.o
-  MIX_OBJS +=hp_scanner.o
+  MI_OBJS +=hp_scanner.o
 endif
 
 ifeq ($(CONFIG_USB_HUB),y)
@@ -77,7 +77,7 @@ ifeq ($(CONFIG_USB_HUB),y)
 endif
 ifeq ($(CONFIG_USB_HUB),m)
   M_OBJS += hub.o
-  MIX_OBJS += hub.o    
+  MI_OBJS += hub.o     
 endif
 
 ifeq ($(CONFIG_USB_ACM),y)
@@ -85,7 +85,7 @@ ifeq ($(CONFIG_USB_ACM),y)
 endif
 ifeq ($(CONFIG_USB_ACM),m)
   M_OBJS += acm.o
-  MIX_OBJS += acm.o
+  MI_OBJS += acm.o
 endif
 
 ifeq ($(CONFIG_USB_PRINTER),y)
@@ -94,7 +94,7 @@ endif
 
 ifeq ($(CONFIG_USB_PRINTER),m)
   M_OBJS += printer.o
-  MIX_OBJS += printer.o  
+  MI_OBJS += printer.o  
 endif
 
 ifeq ($(CONFIG_USB_SERIAL),y)
@@ -103,7 +103,7 @@ endif
 
 ifeq ($(CONFIG_USB_SERIAL),m)
   M_OBJS += usb-serial.o
-  MIX_OBJS += usb-serial.o  
+  MI_OBJS += usb-serial.o  
 endif
 
 ifneq ($(CONFIG_ADB_KEYBOARD),y)
@@ -118,7 +118,7 @@ endif
 
 ifeq ($(CONFIG_USB_KBD),m)
   M_OBJS += usb-keyboard.o
-  MIX_OBJS += keyboard.o $(KEYMAP).o
+  MI_OBJS += keyboard.o $(KEYMAP).o
 endif
 
 ifeq ($(CONFIG_USB_AUDIO),y)
@@ -127,7 +127,7 @@ endif
 
 ifeq ($(CONFIG_USB_AUDIO),m)
   M_OBJS += audio.o
-  MIX_OBJS += audio.o
+  MI_OBJS += audio.o
 endif
 
 ifeq ($(CONFIG_USB_CPIA),y)
@@ -136,7 +136,7 @@ endif
 
 ifeq ($(CONFIG_USB_CPIA),m)
   M_OBJS += cpia.o
-  MIX_OBJS += cpia.o
+  MI_OBJS += cpia.o
 endif
 
 ifeq ($(CONFIG_USB_DC2XX),y)
@@ -144,7 +144,7 @@ ifeq ($(CONFIG_USB_DC2XX),y)
 endif
 ifeq ($(CONFIG_USB_DC2XX),m)
   M_OBJS += dc2xx.o
-  MIX_OBJS += dc2xx.o
+  MI_OBJS += dc2xx.o
 endif
 
 ifeq ($(CONFIG_USB_SCSI),y)
@@ -156,9 +156,9 @@ endif
 
 ifeq ($(CONFIG_USB_SCSI),m)
   M_OBJS += usb-scsi.o
-  MIX_OBJS += usb_scsi.o
+  MI_OBJS += usb_scsi.o
   ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
-    MIX_OBJS += usb_scsi_debug.o
+    MI_OBJS += usb_scsi_debug.o
   endif
 endif
 
@@ -168,7 +168,7 @@ endif
 
 ifeq ($(CONFIG_USB_EZUSB),m)
   M_OBJS += ezusb.o
-  MIX_OBJS += ezusb.o
+  MI_OBJS += ezusb.o
 endif
 
 ifeq ($(CONFIG_USB_USS720),y)
@@ -177,7 +177,7 @@ endif
 
 ifeq ($(CONFIG_USB_USS720),m)
   M_OBJS += uss720.o
-  MIX_OBJS += uss720.o
+  MI_OBJS += uss720.o
 endif
 
 include $(TOPDIR)/Rules.make
index e67fb748a8537d4a7b1350fa3434cff7ba8dae6d..0b59e0d1bb3b34ffb04debdf188f0432eefff563 100644 (file)
@@ -3,15 +3,24 @@ Serial devices. It should also work for the Etek converter, but I do
 not know the vendor id, and device id of that device (if anyone does, 
 please let me know.)
 
+If your device is not compatible with the above models, you can try
+out the "generic" interface. This interface does not provide any type
+of control messages sent to the device, and does not support any kind
+of device flow control. All that is required of your device is that
+it has at least one bulk in endpoint, or one bulk out endpoint.
+To enable the driver to recognize your device, build the driver as
+a module and load it by the following invocation:
+       insmod usb-serial.o vendor=0x#### product=0x####
+where the #### is replaced with the hex representation of your device's
+vendor id and product id.
+
 The driver can handle enumerating the device, and sending and receiving
-data from the converter. However, since I do not have a spec for this
-device, and the raw dumps from the Win98 driver are confusing, no control
-signals are handled, and the data will most likely come through on a baud
+data from the converter. However, since I do not have a spec for the Belkin,
+Peracom, and eTek devices, and the raw dumps from the Win98 driver are 
+confusing, and eTek keeps giving me the run around, no control signals are 
+currently handled, and the data will most likely come through on a baud
 rate that you are not expecting.
 
-But I am working on figuring the control settings out. This release is to
-let others try it out, and give some feedback.
-
 The major number that the driver uses is 240 (in the local/experimental
 range.) It will stay there until some agreements are reached on how to
 handle the configuration problem that USB provides.
index 534b369caba3fd0af322432688ea41ae23f33cbd..368f0bf47a26c8085cee3c5a1e1756cbefbfa3f9 100644 (file)
@@ -1,32 +1,41 @@
 /*
  * USB Serial Converter driver
  *
- * Greg Kroah-Hartman (greg@kroah.com)
+ *     (C) Copyright (C) 1999
+ *         Greg Kroah-Hartman (greg@kroah.com)
  *
- * This was based on the ACM driver by Armin Fuerst (which was based
- * on a driver by Brad Keryan)
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
  *
- * Currently only works for the Belkin and Peracom Serial converters.
- * Should also work on the Etek serial converter, if anyone knows the
- * vendor and device ids for that device.
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was 
+ * based on a driver by Brad Keryan)
  *
+ * See README.serial for more information on using this driver.
  * 
+ * version 0.2.0 (11/10/99) gkh
+ *     Split up internals to make it easier to add different types of serial 
+ *     converters to the code.
+ *     Added a "generic" driver that gets it's vendor and product id
+ *     from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+ *     for the idea and sample code (from the usb scanner driver.)
+ *     Cleared up any licensing questions by releasing it under the GNU GPL.
+ *
  * version 0.1.2 (10/25/99) gkh
- *  Fixed bug in detecting device.
+ *     Fixed bug in detecting device.
  *
  * version 0.1.1 (10/05/99) gkh
- *  Changed the major number to not conflict with anything else.
+ *     Changed the major number to not conflict with anything else.
  *
  * version 0.1 (09/28/99) gkh
- *  Can recognize the two different devices and start up a read from
- * device when asked to. Writes also work. No control signals yet, this
- * all is vendor specific data (i.e. no spec), also no control for
- * different baud rates or other bit settings.
- * Currently we are using the same devid as the acm driver. This needs
- * to change.
+ *     Can recognize the two different devices and start up a read from
+ *     device when asked to. Writes also work. No control signals yet, this
+ *     all is vendor specific data (i.e. no spec), also no control for
+ *     different baud rates or other bit settings.
+ *     Currently we are using the same devid as the acm driver. This needs
+ *     to change.
  * 
- * (C) Copyright 1999 Greg Kroah-Hartman (greg@kroah.com)
- *
  */
 
 #include <linux/kernel.h>
@@ -43,8 +52,8 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
-
 #include "usb.h"
+
 /*#define SERIAL_DEBUG 1*/
 
 #ifdef SERIAL_DEBUG
 #endif
 
 
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_DESCRIPTION("USB Serial Driver");
+
+static __u16   vendor  = 0;
+static __u16   product = 0;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+
 /* USB Serial devices vendor ids and device ids that this driver supports */
 #define BELKIN_VENDOR_ID               0x056c
 #define BELKIN_SERIAL_CONVERTER                0x8007
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
 static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
 
-typedef enum {
-       unknown = 0,
-       Belkin = 1,
-       Peracom = 2
-       } SERIAL_TYPE;
+
+#define MUST_HAVE_NOT  0x01
+#define MUST_HAVE      0x02
+#define DONT_CARE      0x03
+
+#define        HAS             0x02
+#define HAS_NOT                0x01
+
+
+/* local function prototypes */
+static int serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static void serial_put_char (struct tty_struct *tty, unsigned char ch);
+static int serial_write_room (struct tty_struct *tty);
+static int serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+
+
+/* function prototypes for the eTek type converters (this included Belkin and Peracom) */
+static int etek_serial_open (struct tty_struct *tty, struct file * filp);
+static void etek_serial_close (struct tty_struct *tty, struct file * filp);
+static int etek_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch);
+static int etek_write_room (struct tty_struct *tty);
+static int etek_chars_in_buffer (struct tty_struct *tty);
+static void etek_throttle (struct tty_struct * tty);
+static void etek_unthrottle (struct tty_struct * tty);
+
+
+/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
+static int generic_serial_open (struct tty_struct *tty, struct file * filp);
+static void generic_serial_close (struct tty_struct *tty, struct file * filp);
+static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch);
+static int generic_write_room (struct tty_struct *tty);
+static int generic_chars_in_buffer (struct tty_struct *tty);
+
+
+/* This structure defines the individual serial converter. */
+struct usb_serial_device_type {
+       char    *name;
+       __u16   *idVendor;
+       __u16   *idProduct;
+       char    needs_interrupt_in;
+       char    needs_bulk_in;
+       char    needs_bulk_out;
+       // add function calls
+
+       int  (*open)(struct tty_struct * tty, struct file * filp);
+       void (*close)(struct tty_struct * tty, struct file * filp);
+       int  (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);
+       void (*put_char)(struct tty_struct *tty, unsigned char ch);
+       int  (*write_room)(struct tty_struct *tty);
+       int  (*chars_in_buffer)(struct tty_struct *tty);
+       void (*throttle)(struct tty_struct * tty);
+       void (*unthrottle)(struct tty_struct * tty);
+
+};
+
+
+/* All of the device info needed for the Belkin Serial Converter */
+static __u16   belkin_vendor_id        = BELKIN_VENDOR_ID;
+static __u16   belkin_product_id       = BELKIN_SERIAL_CONVERTER;
+static struct usb_serial_device_type belkin_device = {
+       "Belkin",
+       &belkin_vendor_id,      /* the Belkin vendor id */
+       &belkin_product_id,     /* the Belkin serial converter product id */
+       MUST_HAVE,              /* this device must have an interrupt in endpoint */
+       MUST_HAVE,              /* this device must have a bulk in endpoint */
+       MUST_HAVE,              /* this device must have a bulk out endpoint */
+       etek_serial_open,
+       etek_serial_close,
+       etek_serial_write,
+       etek_serial_put_char,
+       etek_write_room,
+       etek_chars_in_buffer,
+       etek_throttle,
+       etek_unthrottle
+};
+
+/* All of the device info needed for the Peracom Serial Converter */
+static __u16   peracom_vendor_id       = PERACOM_VENDOR_ID;
+static __u16   peracom_product_id      = PERACOM_SERIAL_CONVERTER;
+static struct usb_serial_device_type peracom_device = {
+       "Peracom",
+       &peracom_vendor_id,     /* the Peracom vendor id */
+       &peracom_product_id,    /* the Peracom serial converter product id */
+       MUST_HAVE,              /* this device must have an interrupt in endpoint */
+       MUST_HAVE,              /* this device must have a bulk in endpoint */
+       MUST_HAVE,              /* this device must have a bulk out endpoint */
+       etek_serial_open,
+       etek_serial_close,
+       etek_serial_write,
+       etek_serial_put_char,
+       etek_write_room,
+       etek_chars_in_buffer,
+       etek_throttle,
+       etek_unthrottle
+};
+
+/* All of the device info needed for the Generic Serial Converter */
+static struct usb_serial_device_type generic_device = {
+       "Generic",
+       &vendor,                /* use the user specified vendor id */
+       &product,               /* use the user specified product id */
+       DONT_CARE,              /* don't have to have an interrupt in endpoint */
+       DONT_CARE,              /* don't have to have a bulk in endpoint */
+       DONT_CARE,              /* don't have to have a bulk out endpoint */
+       generic_serial_open,
+       generic_serial_close,
+       generic_serial_write,
+       generic_serial_put_char,
+       generic_write_room,
+       generic_chars_in_buffer,
+       NULL,                   /* generic driver does not implement any flow control */
+       NULL                    /* generic driver does not implement any flow control */
+};
+
+
+/* To add support for another serial converter, create a usb_serial_device_type
+   structure for that device, and add it to this list, making sure that the last
+   entry is NULL. */
+static struct usb_serial_device_type *usb_serial_devices[] = {
+       &generic_device,
+       &belkin_device,
+       &peracom_device,
+       NULL
+};
+
+
 
 struct usb_serial_state {
-       struct usb_device *     dev;
-       SERIAL_TYPE             type;           /* what manufacturer's type of converter */
-       void *                  irq_handle;
-       unsigned int            irqpipe;
-       struct tty_struct       *tty;           /* the coresponding tty for this device */
-       char                    present;
-       char                    active;
-
-       char                    interrupt_in_inuse;
+       struct usb_device *             dev;
+       struct usb_serial_device_type * type;
+       void *                          irq_handle;
+       unsigned int                    irqpipe;
+       struct tty_struct *             tty;            /* the coresponding tty for this device */
+       char                            present;
+       char                            active;
+
+       char                    has_interrupt_in;       /* if this device has an interrupt in pipe or not */
+       char                    interrupt_in_inuse;     /* if the interrupt in endpoint is in use */
        __u8                    interrupt_in_endpoint;
        __u8                    interrupt_in_interval;
-       __u16                   interrupt_in_size;
+       __u16                   interrupt_in_size;      /* the size of the interrupt in endpoint */
        unsigned int            interrupt_in_pipe;
        unsigned char *         interrupt_in_buffer;
        void *                  interrupt_in_transfer;
 
-       char                    bulk_in_inuse;
+       char                    has_bulk_in;            /* if thie device has a bulk in pipe or not */
+       char                    bulk_in_inuse;          /* if the bulk in endpoint is in use */
        __u8                    bulk_in_endpoint;
        __u8                    bulk_in_interval;
-       __u16                   bulk_in_size;
+       __u16                   bulk_in_size;           /* the size of the bulk in endpoint */
        unsigned int            bulk_in_pipe;
        unsigned char *         bulk_in_buffer;
        void *                  bulk_in_transfer;
 
-       char                    bulk_out_inuse;
+       char                    has_bulk_out;           /* if this device has a bulk out pipe or not */
+       char                    bulk_out_inuse;         /* if the bulk out endpoint is in use */
        __u8                    bulk_out_endpoint;
        __u8                    bulk_out_interval;
-       __u16                   bulk_out_size;
+       __u16                   bulk_out_size;          /* the size of the bulk out endpoint */
        unsigned int            bulk_out_pipe;
        unsigned char *         bulk_out_buffer;
        void *                  bulk_out_transfer;
@@ -197,36 +349,25 @@ static int usb_serial_irq (int state, void *buffer, int len, void *dev_id)
 
 
 
-
-/* tty interface functions */
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
 static int serial_open (struct tty_struct *tty, struct file * filp)
 {
        struct usb_serial_state *serial;
        
        debug_info("USB: serial_open\n");
 
+       /* assign a serial object to the tty pointer */
        serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start];
        tty->driver_data = serial;
        serial->tty = tty;
         
-       if (!serial->present) {
-               debug_info("USB Serial: no device registered\n");
-               return -EINVAL;
+       /* pass on to the driver specific version of this function */
+       if (serial->type->open) {
+               return (serial->type->open(tty, filp));
        }
-
-       if (serial->active) {
-               debug_info ("USB Serial: device already open\n");
-               return -EINVAL;
-       }
-       serial->active = 1;
-       /*Start reading from the device*/
-       serial->bulk_in_inuse = 1;
-       serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
-
-       /* Need to do device specific setup here (control lines, baud rate, etc.) */
-       /* FIXME!!! */
-                                                 
+               
        return (0);
 }
 
@@ -246,28 +387,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
                return;
        }
 
-       /* Need to change the control lines here */
-       /* FIXME */
-       
-       if (serial->bulk_out_inuse){
-               usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
-               serial->bulk_out_inuse = 0;
+       /* pass on to the driver specific version of this function */
+       if (serial->type->close) {
+               serial->type->close(tty, filp);
        }
-       if (serial->bulk_in_inuse){
-               usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
-               serial->bulk_in_inuse = 0;
-       }
-
-       /* release the irq? */
-       
-       serial->active = 0;
-}
+}      
 
 
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
        struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
-       int written;
        
        debug_info("USB Serial: serial_write\n");
 
@@ -281,26 +410,14 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
                return (-EINVAL);
        }
        
-       if (serial->bulk_out_inuse) {
-               debug_info ("USB Serial: already writing\n");
-               return (0);
-       }
-
-       written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count;
-         
-       if (from_user) {
-               copy_from_user(serial->bulk_out_buffer, buf, written);
+       /* pass on to the driver specific version of this function */
+       if (serial->type->write) {
+               return (serial->type->write(tty, from_user, buf, count));
        }
-       else {
-               memcpy (serial->bulk_out_buffer, buf, written);
-       }  
 
-       /* send the data out the bulk port */
-       serial->bulk_out_inuse = 1;
-       serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial);
-
-       return (written);
-} 
+       /* no specific driver, so return that we didn't write anything */
+       return (0);
+}
 
 
 static void serial_put_char (struct tty_struct *tty, unsigned char ch)
@@ -319,18 +436,13 @@ static void serial_put_char (struct tty_struct *tty, unsigned char ch)
                return;
        }
 
-       if (serial->bulk_out_inuse) {
-               debug_info ("USB Serial: already writing\n");
-               return;
+       /* pass on to the driver specific version of this function */
+       if (serial->type->put_char) {
+               serial->type->put_char(tty, ch);
        }
 
-       /* send the single character out the bulk port */
-       serial->bulk_out_buffer[0] = ch;
-       serial->bulk_out_inuse = 1;
-       serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial);
-
        return;
-}                   
+}      
 
 
 static int serial_write_room (struct tty_struct *tty) 
@@ -349,11 +461,12 @@ static int serial_write_room (struct tty_struct *tty)
                return (-EINVAL);
        }
        
-       if (serial->bulk_out_inuse) {
-               return (0);
+       /* pass on to the driver specific version of this function */
+       if (serial->type->write_room) {
+               return (serial->type->write_room(tty));
        }
 
-       return serial->bulk_out_size;
+       return (0);
 }
 
 
@@ -373,8 +486,9 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
                return (-EINVAL);
        }
        
-       if (serial->bulk_out_inuse) {
-               return (serial->bulk_out_size);
+       /* pass on to the driver specific version of this function */
+       if (serial->type->chars_in_buffer) {
+               return (serial->type->chars_in_buffer(tty));
        }
 
        return (0);
@@ -397,9 +511,10 @@ static void serial_throttle (struct tty_struct * tty)
                return;
        }
 
-
-       /* Change the control signals */
-       /* FIXME!!! */
+       /* pass on to the driver specific version of this function */
+       if (serial->type->throttle) {
+               serial->type->throttle(tty);
+       }
 
        return;
 }
@@ -422,6 +537,153 @@ static void serial_unthrottle (struct tty_struct * tty)
        }
 
 
+       /* pass on to the driver specific version of this function */
+       if (serial->type->unthrottle) {
+               serial->type->unthrottle(tty);
+       }
+
+       return;
+}
+
+
+/*****************************************************************************
+ * eTek specific driver functions
+ *****************************************************************************/
+static int etek_serial_open (struct tty_struct *tty, struct file *filp)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+       debug_info("USB: etek_serial_open\n");
+
+       if (!serial->present) {
+               debug_info("USB Serial: no device registered\n");
+               return -EINVAL;
+       }
+
+       if (serial->active) {
+               debug_info ("USB Serial: device already open\n");
+               return -EINVAL;
+       }
+       serial->active = 1;
+       /*Start reading from the device*/
+       serial->bulk_in_inuse = 1;
+       serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+       /* Need to do device specific setup here (control lines, baud rate, etc.) */
+       /* FIXME!!! */
+                                                 
+       return (0);
+}
+
+
+static void etek_serial_close(struct tty_struct *tty, struct file * filp)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+       debug_info("USB: etek_serial_close\n");
+       
+       /* Need to change the control lines here */
+       /* FIXME */
+       
+       /* shutdown our bulk reads and writes */
+       if (serial->bulk_out_inuse){
+               usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+               serial->bulk_out_inuse = 0;
+       }
+       if (serial->bulk_in_inuse){
+               usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+               serial->bulk_in_inuse = 0;
+       }
+
+       /* release the irq? */
+       
+       serial->active = 0;
+}
+
+
+static int etek_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+       int written;
+       
+       debug_info("USB Serial: etek_serial_write\n");
+
+       if (serial->bulk_out_inuse) {
+               debug_info ("USB Serial: already writing\n");
+               return (0);
+       }
+
+       written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count;
+         
+       if (from_user) {
+               copy_from_user(serial->bulk_out_buffer, buf, written);
+       }
+       else {
+               memcpy (serial->bulk_out_buffer, buf, written);
+       }  
+
+       /* send the data out the bulk port */
+       serial->bulk_out_inuse = 1;
+       serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial);
+
+       return (written);
+} 
+
+
+static void etek_serial_put_char (struct tty_struct *tty, unsigned char ch)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+       
+       debug_info("USB Serial: etek_serial_put_char\n");
+       
+       if (serial->bulk_out_inuse) {
+               debug_info ("USB Serial: already writing\n");
+               return;
+       }
+
+       /* send the single character out the bulk port */
+       serial->bulk_out_buffer[0] = ch;
+       serial->bulk_out_inuse = 1;
+       serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial);
+
+       return;
+}                   
+
+
+static int etek_write_room (struct tty_struct *tty) 
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+       debug_info("USB Serial: etek_write_room\n");
+       
+       if (serial->bulk_out_inuse) {
+               return (0);
+       }
+
+       return (serial->bulk_out_size);
+}
+
+
+static int etek_chars_in_buffer (struct tty_struct *tty) 
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+       debug_info("USB Serial: etek_chars_in_buffer\n");
+       
+       if (serial->bulk_out_inuse) {
+               return (serial->bulk_out_size);
+       }
+
+       return (0);
+}
+
+
+static void etek_throttle (struct tty_struct * tty)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+       debug_info("USB Serial: etek_throttle\n");
+       
        /* Change the control signals */
        /* FIXME!!! */
 
@@ -429,6 +691,160 @@ static void serial_unthrottle (struct tty_struct * tty)
 }
 
 
+static void etek_unthrottle (struct tty_struct * tty)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+       debug_info("USB Serial: etek_unthrottle\n");
+       
+       /* Change the control signals */
+       /* FIXME!!! */
+
+       return;
+}
+
+
+/*****************************************************************************
+ * generic devices specific driver functions
+ *****************************************************************************/
+static int generic_serial_open (struct tty_struct *tty, struct file *filp)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+
+       debug_info("USB: generic_serial_open\n");
+
+       if (!serial->present) {
+               debug_info("USB Serial: no device registered\n");
+               return -EINVAL;
+       }
+
+       if (serial->active) {
+               debug_info ("USB Serial: device already open\n");
+               return -EINVAL;
+       }
+       serial->active = 1;
+       /* if we have a bulk interrupt, start reading from it */
+       if (serial->has_bulk_in) {
+               /*Start reading from the device*/
+               serial->bulk_in_inuse = 1;
+               serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+       }
+                                                 
+       return (0);
+}
+
+
+static void generic_serial_close(struct tty_struct *tty, struct file * filp)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+       debug_info("USB: generic_serial_close\n");
+       
+       /* shutdown any bulk reads that might be going on */
+       if (serial->bulk_out_inuse){
+               usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+               serial->bulk_out_inuse = 0;
+       }
+       if (serial->bulk_in_inuse){
+               usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+               serial->bulk_in_inuse = 0;
+       }
+
+       serial->active = 0;
+}
+
+
+static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; 
+       int written;
+       
+       debug_info("USB Serial: generic_serial_write\n");
+
+       /* only do something if we have a bulk out endpoint */
+       if (serial->has_bulk_out) {
+               if (serial->bulk_out_inuse) {
+                       debug_info ("USB Serial: already writing\n");
+                       return (0);
+               }
+
+               written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count;
+         
+               if (from_user) {
+                       copy_from_user(serial->bulk_out_buffer, buf, written);
+               }
+               else {
+                       memcpy (serial->bulk_out_buffer, buf, written);
+               }  
+
+               /* send the data out the bulk port */
+               serial->bulk_out_inuse = 1;
+               serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial);
+
+               return (written);
+       }
+       
+       /* no bulk out, so return 0 bytes written */
+       return (0);
+} 
+
+
+static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch)
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+       
+       debug_info("USB Serial: generic_serial_put_char\n");
+       
+       /* if we have a bulk out endpoint, then shove a character out it */
+       if (serial->has_bulk_out) {
+               if (serial->bulk_out_inuse) {
+                       debug_info ("USB Serial: already writing\n");
+                       return;
+               }
+
+               /* send the single character out the bulk port */
+               serial->bulk_out_buffer[0] = ch;
+               serial->bulk_out_inuse = 1;
+               serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial);
+       }
+
+       return;
+}                   
+
+
+static int generic_write_room (struct tty_struct *tty) 
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+       debug_info("USB Serial: generic_write_room\n");
+       
+       if (serial->has_bulk_out) {
+               if (serial->bulk_out_inuse) {
+                       return (0);
+               }
+               return (serial->bulk_out_size);
+       }
+       
+       return (0);
+}
+
+
+static int generic_chars_in_buffer (struct tty_struct *tty) 
+{
+       struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; 
+
+       debug_info("USB Serial: generic_chars_in_buffer\n");
+       
+       if (serial->has_bulk_out) {
+               if (serial->bulk_out_inuse) {
+                       return (serial->bulk_out_size);
+               }
+       }
+
+       return (0);
+}
+
+
 static int Get_Free_Serial (void)
 {
        int i;
@@ -443,122 +859,172 @@ static int Get_Free_Serial (void)
 
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
 {
-       struct usb_serial_state *serial;
+       struct usb_serial_state *serial = NULL;
        struct usb_interface_descriptor *interface;
        struct usb_endpoint_descriptor *endpoint;
-       SERIAL_TYPE type;
+       struct usb_endpoint_descriptor *interrupt_in_endpoint = NULL;
+       struct usb_endpoint_descriptor *bulk_in_endpoint = NULL;
+       struct usb_endpoint_descriptor *bulk_out_endpoint = NULL;
+//     SERIAL_TYPE type;
+       struct usb_serial_device_type *type;
+       int device_num;
        int serial_num;
 //     int ret;
        int i;
+       char interrupt_pipe;
+       char bulk_in_pipe;
+       char bulk_out_pipe;
        
-       /* look at the device descriptor to see if it is a type that we recognize */
-       type = unknown;
-       if ((dev->descriptor.idVendor == BELKIN_VENDOR_ID) &&
-           (dev->descriptor.idProduct == BELKIN_SERIAL_CONVERTER)) {
-               /* This is the Belkin serial convertor */
-               type = Belkin;
-               }
-       
-       if ((dev->descriptor.idVendor == PERACOM_VENDOR_ID) &&
-           (dev->descriptor.idProduct == PERACOM_SERIAL_CONVERTER)) {
-               /* This is the Peracom serial convertor */
-               type = Peracom;
-               }
-
-       if (type == unknown)
-               return NULL;    
-
-       printk (KERN_INFO "USB serial converter detected.\n");
-
-       if (0>(serial_num = Get_Free_Serial())) {
-               debug_info("USB Serial: Too many devices connected\n");
-               return NULL;
-       }
-       
-       serial = &serial_state_table[serial_num];
-
-               memset(serial, 0, sizeof(serial));
-               serial->dev = dev;
-       serial->type = type;
-
-       /* we should have 1 bulk in, 1 bulk out, and 1 interrupt in endpoints */
-       interface = &dev->actconfig->interface[ifnum].altsetting[0];
-       for (i = 0; i < interface->bNumEndpoints; ++i) {
-               endpoint = &interface->endpoint[i];
+       /* loop through our list of known serial converters, and see if this device matches */
+       device_num = 0;
+       while (usb_serial_devices[device_num] != NULL) {
+               type = usb_serial_devices[device_num];
+               #ifdef SERIAL_DEBUG
+                       printk ("Looking at %s\nVendor id=%.4x\nProduct id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+               #endif          
+
+               /* look at the device descriptor */
+               if ((dev->descriptor.idVendor == *(type->idVendor)) &&
+                   (dev->descriptor.idProduct == *(type->idProduct))) {
+
+                       debug_info("descriptor matches...looking at the endpoints\n")
+
+                       /* descriptor matches, let's try to find the endpoints needed */
+                       interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+                       
+                       /* check out the endpoints */
+                       interface = &dev->actconfig->interface[ifnum].altsetting[0];
+                       for (i = 0; i < interface->bNumEndpoints; ++i) {
+                               endpoint = &interface->endpoint[i];
                
-               if ((endpoint->bEndpointAddress & 0x80) &&
-                   ((endpoint->bmAttributes & 3) == 0x02)) {
-                       /* we found the bulk in endpoint */
-                       serial->bulk_in_inuse = 0;
-                       serial->bulk_in_endpoint = endpoint->bEndpointAddress;
-                       serial->bulk_in_size = endpoint->wMaxPacketSize;
-                       serial->bulk_in_interval = endpoint->bInterval;
-                       serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint);
-                       serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
-                       if (!serial->bulk_in_buffer) {
-                               printk("USB Serial: Couldn't allocate bulk_in_buffer\n");
-                               goto probe_error;
-                       }
-               }
+                               if ((endpoint->bEndpointAddress & 0x80) &&
+                                   ((endpoint->bmAttributes & 3) == 0x02)) {
+                                       /* we found a bulk in endpoint */
+                                       debug_info("found bulk in\n");
+                                       if (bulk_in_pipe == HAS) {
+                                               printk("USB Serial: can't have more than one bulk in endpoint\n");
+                                               goto probe_error;
+                                               }
+                                       bulk_in_pipe = HAS;
+                                       bulk_in_endpoint = endpoint;
+                               }
+
+                               if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+                                   ((endpoint->bmAttributes & 3) == 0x02)) {
+                                       /* we found a bulk out endpoint */
+                                       debug_info("found bulk out\n");
+                                       if (bulk_out_pipe == HAS) {
+                                               printk("USB Serial: can't have more than one bulk out endpoint\n");
+                                               goto probe_error;
+                                               }
+                                       bulk_out_pipe = HAS;
+                                       bulk_out_endpoint = endpoint;
+                               }
+               
+                               if ((endpoint->bEndpointAddress & 0x80) &&
+                                   ((endpoint->bmAttributes & 3) == 0x03)) {
+                                       /* we found a interrupt in endpoint */
+                                       debug_info("found interrupt in\n");
+                                       if (interrupt_pipe == HAS) {
+                                               printk("USB Serial: can't have more than one interrupt in endpoint\n");
+                                               goto probe_error;
+                                               }
+                                       interrupt_pipe = HAS;
+                                       interrupt_in_endpoint = endpoint;
+                               }
 
-               if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-                   ((endpoint->bmAttributes & 3) == 0x02)) {
-                       /* we found the bulk out endpoint */
-                       serial->bulk_out_inuse = 0;
-                       serial->bulk_out_endpoint = endpoint->bEndpointAddress;
-                       serial->bulk_out_size = endpoint->wMaxPacketSize;
-                       serial->bulk_out_interval = endpoint->bInterval;
-                       serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint);
-                       serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL);
-                       if (!serial->bulk_out_buffer) {
-                               printk("USB Serial: Couldn't allocate bulk_out_buffer\n");
-                               goto probe_error;
                        }
-               }
-               
-               if ((endpoint->bEndpointAddress & 0x80) &&
-                   ((endpoint->bmAttributes & 3) == 0x03)) {
-                       /* we found the interrupt in endpoint */
-                       serial->interrupt_in_inuse = 0;
-                       serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
-                       serial->interrupt_in_size = endpoint->wMaxPacketSize;
-                       serial->interrupt_in_interval = endpoint->bInterval;
-                       /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */
-                       serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
-                       if (!serial->interrupt_in_buffer) {
-                               printk("USB Serial: Couldn't allocate interrupt_in_buffer\n");
-                               goto probe_error;
+       
+                       /* verify that we found all of the endpoints that we need */
+                       if ((interrupt_pipe & type->needs_interrupt_in) &&
+                           (bulk_in_pipe & type->needs_bulk_in) &&
+                           (bulk_out_pipe & type->needs_bulk_out)) {
+                               /* found all that we need */
+                               printk (KERN_INFO "USB serial converter detected.\n");
+
+                               if (0>(serial_num = Get_Free_Serial())) {
+                                       debug_info("USB Serial: Too many devices connected\n");
+                                       return NULL;
+                               }
+       
+                               serial = &serial_state_table[serial_num];
+
+                               memset(serial, 0, sizeof(struct usb_serial_state));
+                               serial->dev = dev;
+                               serial->type = type;
+
+                               /* set up the endpoint information */
+                               if (bulk_in_endpoint) {
+                                       serial->has_bulk_in = 1;
+                                       serial->bulk_in_inuse = 0;
+                                       serial->bulk_in_endpoint = bulk_in_endpoint->bEndpointAddress;
+                                       serial->bulk_in_size = bulk_in_endpoint->wMaxPacketSize;
+                                       serial->bulk_in_interval = bulk_in_endpoint->bInterval;
+                                       serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint);
+                                       serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+                                       if (!serial->bulk_in_buffer) {
+                                               printk("USB Serial: Couldn't allocate bulk_in_buffer\n");
+                                               goto probe_error;
+                                       }
+                               }
+
+                               if (bulk_out_endpoint) {
+                                       serial->has_bulk_out = 1;
+                                       serial->bulk_out_inuse = 0;
+                                       serial->bulk_out_endpoint = bulk_out_endpoint->bEndpointAddress;
+                                       serial->bulk_out_size = bulk_out_endpoint->wMaxPacketSize;
+                                       serial->bulk_out_interval = bulk_out_endpoint->bInterval;
+                                       serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint);
+                                       serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL);
+                                       if (!serial->bulk_out_buffer) {
+                                               printk("USB Serial: Couldn't allocate bulk_out_buffer\n");
+                                               goto probe_error;
+                                       }
+                               }
+
+                               if (interrupt_in_endpoint) {
+                                       serial->has_interrupt_in = 1;
+                                       serial->interrupt_in_inuse = 0;
+                                       serial->interrupt_in_endpoint = interrupt_in_endpoint->bEndpointAddress;
+                                       serial->interrupt_in_size = interrupt_in_endpoint->wMaxPacketSize;
+                                       serial->interrupt_in_interval = interrupt_in_endpoint->bInterval;
+                                       /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */
+                                       serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+                                       if (!serial->interrupt_in_buffer) {
+                                               printk("USB Serial: Couldn't allocate interrupt_in_buffer\n");
+                                               goto probe_error;
+                                       }
+                               }
+
+                               #if 0
+                               /* set up an interrupt for out bulk in pipe */
+                               /* ask for a bulk read */
+                               serial->bulk_in_inuse = 1;
+                               serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+                               /* set up our interrupt to be the time for the bulk in read */
+                               ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle);
+                               if (ret) {
+                                       printk(KERN_INFO "USB Serial failed usb_request_irq (0x%x)\n", ret);
+                                       goto probe_error;
+                               }
+                               #endif
+
+                               serial->present = 1;
+                               MOD_INC_USE_COUNT;
+
+                               return serial;
+                       } else {
+                               printk(KERN_INFO "USB Serial, descriptors matched, but endpoints did not\n");
                        }
                }
 
+               /* look at the next type in our list */
+               ++device_num;
        }
-       
 
-       /* verify that we found all of the endpoints that we need */
-       if ((!serial->bulk_in_buffer) || 
-           (!serial->bulk_out_buffer) ||
-           (!serial->interrupt_in_buffer)) {
-               printk("USB Serial: did not find all of the required endpoints\n");
-               goto probe_error;
-       }
-               
 
-       /* set up an interrupt for out bulk in pipe */
-       /* ask for a bulk read */
-//     serial->bulk_in_inuse = 1;
-//     serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
-
-       /* set up our interrupt to be the time for the bulk in read */
-//     ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle);
-//     if (ret) {
-//             printk(KERN_INFO "USB Serial failed usb_request_irq (0x%x)\n", ret);
-//             goto probe_error;
-//     }
-       
-       serial->present = 1;
-       MOD_INC_USE_COUNT;
 
-       return serial;
 
 probe_error:
        if (serial) {
@@ -636,6 +1102,8 @@ int usb_serial_init(void)
        serial_tty_driver.flags                 = TTY_DRIVER_REAL_RAW;
        serial_tty_driver.refcount              = &serial_refcount;
        serial_tty_driver.table                 = serial_tty;
+       serial_tty_driver.proc_entry            = NULL;
+       serial_tty_driver.other                 = NULL;
        serial_tty_driver.termios               = serial_termios;
        serial_tty_driver.termios_locked        = serial_termios_locked;
        
index cf0f89722826f567aeb0fe0ca1aaf132a60d3f5e..befe7bcecab3346252e33c97491b22ece35ea53d 100644 (file)
@@ -823,7 +823,7 @@ static int balance_dirty_state(kdev_t dev)
        unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
        dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
-       tot = nr_lru_pages + nr_free_pages - nr_free_highpages;
+       tot = nr_free_buffer_pages();
        hard_dirty_limit = tot * bdf_prm.b_un.nfract / 100;
        soft_dirty_limit = hard_dirty_limit >> 1;
 
index d94f55e5f4b986d896bb308d03f3d85a4c323c83..8dda57102ac4283771e3c51a3fbd2a63ae954aa3 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -225,14 +225,16 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
                        page = bprm->page[i];
                        new = 0;
                        if (!page) {
+                               unsigned long pageaddr;
                                /*
                                 * Cannot yet use highmem page because
                                 * we cannot sleep with a kmap held.
                                 */
-                               page = __get_pages(GFP_USER, 0);
-                               bprm->page[i] = page;
-                               if (!page)
+                               pageaddr = __get_free_page(GFP_USER);
+                               if (!pageaddr)
                                        return -ENOMEM;
+                               page = mem_map + MAP_NR(pageaddr);
+                               bprm->page[i] = page;
                                new = 1;
                        }
                        kaddr = (char *)kmap(page, KM_WRITE);
index 1db720ca69570cf1e31cd1853e6c7c361da79cb9..c006ee6bca66f8a3e0b8a91db507b5881de195e1 100644 (file)
@@ -16,7 +16,8 @@
 #include <linux/elf.h>
 #include <linux/elfcore.h>
 #include <linux/module.h>
-#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_KCORE_AOUT
@@ -211,7 +212,7 @@ static void elf_kcore_store_hdr(char *bufp)
 #ifdef CONFIG_MODULES
        {
                struct module *m;
-               read_lock(&modlist_lock);
+               lock_kernel();  
                for (m=module_list; m; m=m->next) {
                        dhdr = (struct elf_phdr *) bufp;
                        bufp += sizeof(struct elf_phdr);
@@ -227,7 +228,7 @@ static void elf_kcore_store_hdr(char *bufp)
                        dhdr->p_align   = 0;
                        elf->e_phnum++;
                }
-               read_unlock(&modlist_lock);
+               lock_kernel();  
        }
 #endif
 
index fa2ee362ee0c43e3c9e0f522b0844ee6018a5185..7a1732ae4d0ac01481ff73ae9f5ba9e29385d881 100644 (file)
@@ -18,6 +18,8 @@ EXPORT_SYMBOL(proc_get_inode);
 EXPORT_SYMBOL(proc_dir_inode_operations);
 EXPORT_SYMBOL(proc_net);
 EXPORT_SYMBOL(proc_bus);
+EXPORT_SYMBOL(proc_lookup);
+EXPORT_SYMBOL(proc_readdir);
 
 #if defined(CONFIG_SUN_OPENPROMFS_MODULE)
 EXPORT_SYMBOL(proc_openprom_register);
index f5b36dc7fe23fa8b6ba48d4422e6c92b2b389c59..74b2c3965786dd1a166126183f2ec15ea8a0d141 100644 (file)
  *  04/19/99 blf  partial support for reading/writing specific EA's
  */
 
+#include "udfdecl.h"
 
 #if defined(__linux__) && defined(__KERNEL__)
 
-#include "udfdecl.h"
-
 #include "udf_sb.h"
 #include "udf_i.h"
 
@@ -38,7 +37,6 @@
 
 #else
 
-#include "udfdecl.h"
 #include <sys/types.h>
 #include <stdio.h>
 #include <unistd.h>
index 037a3d2f599b649cd37f6c8f8665b29d2ff6f0f1..8802360fee7de339fe6f7b085dbb12ec46dc181e 100644 (file)
@@ -6,7 +6,6 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
-#include <linux/udf_udf.h>
 #include <linux/udf_fs.h>
 #include <linux/config.h>
 
 #error "The UDF Module Current Requires Kernel Version 2.3.7 or greater"
 #endif
 
+#include <linux/fs.h>
 /* if we're not defined, we must be compiling outside of the kernel tree */
 #if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
 /* ... so override config */
 #define CONFIG_UDF_FS_MODULE
-#include <linux/fs.h>
 /* explicitly include udf_fs_sb.h and udf_fs_i.h */
 #include <linux/udf_fs_sb.h>
 #include <linux/udf_fs_i.h>
-#else
-#include <linux/fs.h> /* also gets udf_fs_i.h and udf_fs_sb.h */
 #endif
 
 struct dentry;
@@ -113,10 +110,10 @@ extern int udf_sync_file(struct file *, struct dentry *);
 #else
 
 #include <sys/types.h>
-#include <linux/udf_udf.h>
 
 #endif /* __KERNEL__ */
 
+#include <linux/udf_udf.h>
 #include "udfend.h"
 
 /* structures */
diff --git a/include/asm-ppc/div64.h b/include/asm-ppc/div64.h
new file mode 100644 (file)
index 0000000..114e6ab
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __PPC_DIV64
+#define __PPC_DIV64
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+#endif
index a1f3aa7f797aba8d98a88bc7f410b3462a207572..6fe5596e378d82a09ea4487e672a821e99fb697f 100644 (file)
 #define O_NDELAY       O_NONBLOCK
 #define O_SYNC         010000
 #define FASYNC         020000  /* fcntl, for BSD compatibility */
-#define O_DIRECTORY    040000  /* must be a directory */
-#define O_NOFOLLOW     0100000 /* don't follow links */
+#define O_DIRECTORY     040000 /* must be a directory */
+#define O_NOFOLLOW      100000 /* don't follow links */
+#define O_LARGEFILE     200000
+#define O_DIRECT       400000  /* direct disk access hint - currently ignored */
 
 #define F_DUPFD                0       /* dup */
 #define F_GETFD                1       /* get f_flags */
index 7030d2cf9373f6953f42f5d3c2df0d7e2fe245cb..a78c75b4ebc1ee05afc506ef39c7c383e9b90b92 100644 (file)
@@ -318,8 +318,8 @@ static inline unsigned long thread_saved_pc(struct thread_struct *t)
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define KSTK_EIP(tsk)  ((tsk)->thread.regs->nip)
-#define KSTK_ESP(tsk)  ((tsk)->thread.regs->gpr[1])
+#define KSTK_EIP(tsk)  ((tsk)->thread.regs->nip)
+#define KSTK_ESP(tsk)  ((tsk)->thread.regs->gpr[1])
 
 /*
  * NOTE! The task struct and the stack go together
index ac5170e83eb30df5520073aee3c44d5cabbeaa58..48e87859b0e2aec3fe44e8220b75e5bc80c2f0e9 100644 (file)
@@ -13,18 +13,18 @@ extern struct page *highmem_start_page;
 
 /* declarations for linux/mm/highmem.c */
 extern unsigned long highmem_mapnr;
-extern unsigned long nr_free_highpages;
+FASTCALL(unsigned int nr_free_highpages(void));
 
 extern struct page * prepare_highmem_swapout(struct page *);
 extern struct page * replace_with_highmem(struct page *);
 
 #else /* CONFIG_HIGHMEM */
 
+extern inline unsigned int nr_free_highpages(void) { return 0; }
 #define prepare_highmem_swapout(page) page
 #define replace_with_highmem(page) page
 #define kmap(page, type) page_address(page)
 #define kunmap(vaddr, type) do { } while (0)
-#define nr_free_highpages 0UL
 
 #endif /* CONFIG_HIGHMEM */
 
index aafe8d3a5e2402ec262f2f0a148d80d74e760f33..01140c30a79d5319431b0916e6ef37d6e3559ea6 100644 (file)
@@ -100,40 +100,40 @@ typedef struct _i2o_pci_bus {
        u8 reserved;
        u16 PciVendorID;
        u16 PciDeviceID;
-} i2o_pci_bus, *pi2o_pci_bus;
+} i2o_pci_bus;
 
 typedef struct _i2o_local_bus {
        u16 LbBaseIOPort;
        u16 reserved;
        u32 LbBaseMemoryAddress;
-} i2o_local_bus, *pi2o_local_bus;
+} i2o_local_bus;
 
 typedef struct _i2o_isa_bus {
        u16 IsaBaseIOPort;
        u8 CSN;
        u8 reserved;
        u32 IsaBaseMemoryAddress;
-} i2o_isa_bus, *pi2o_isa_bus;
+} i2o_isa_bus;
 
 typedef struct _i2o_eisa_bus_info {
        u16 EisaBaseIOPort;
        u8 reserved;
        u8 EisaSlotNumber;
        u32 EisaBaseMemoryAddress;
-} i2o_eisa_bus, *pi2o_eisa_bus;
+} i2o_eisa_bus;
 
 typedef struct _i2o_mca_bus {
        u16 McaBaseIOPort;
        u8 reserved;
        u8 McaSlotNumber;
        u32 McaBaseMemoryAddress;
-} i2o_mca_bus, *pi2o_mca_bus;
+} i2o_mca_bus;
 
 typedef struct _i2o_other_bus {
        u16 BaseIOPort;
        u16 reserved;
        u32 BaseMemoryAddress;
-} i2o_other_bus, *pi2o_other_bus;
+} i2o_other_bus;
 
 typedef struct _i2o_hrt_entry {
        u32 adapter_id;
@@ -149,7 +149,7 @@ typedef struct _i2o_hrt_entry {
                i2o_mca_bus mca_bus;
                i2o_other_bus other_bus;
        } bus;
-} i2o_hrt_entry, *pi2o_hrt_entry;
+} i2o_hrt_entry;
 
 typedef struct _i2o_hrt {
        u16 num_entries;
@@ -157,7 +157,7 @@ typedef struct _i2o_hrt {
        u8 hrt_version;
        u32 change_ind;
        i2o_hrt_entry hrt_entry[1];
-} i2o_hrt, *pi2o_hrt;
+} i2o_hrt;
 
 typedef struct _i2o_lct_entry {
        u32 entry_size:16;
@@ -174,7 +174,7 @@ typedef struct _i2o_lct_entry {
        u32 bios_info:8;
        u8 identity_tag[8];
        u32 event_capabilities;
-} i2o_lct_entry, *pi2o_lct_entry;
+} i2o_lct_entry;
 
 typedef struct _i2o_lct {
        u32 table_size:16;
@@ -183,7 +183,7 @@ typedef struct _i2o_lct {
        u32 iop_flags;
        u32 current_change_ind;
        i2o_lct_entry lct_entry[1];
-} i2o_lct, *pi2o_lct;
+} i2o_lct;
 
 typedef struct _i2o_status_block {
        u16 org_id;
@@ -199,6 +199,7 @@ typedef struct _i2o_status_block {
        u8 init_code;   
        u8 reserved2;
        u32 max_inbound_frames;
+       u32 cur_inbound_frames;
        u32 max_outbound_frames;
        char product_id[24];    
        u32 expected_lct_size;
@@ -211,9 +212,38 @@ typedef struct _i2o_status_block {
        u32 current_io_base;
        u32 reserved3:24;
        u32 cmd_status:8;
-} i2o_status_block, *pi2o_status_block;
+} i2o_status_block;
  
-
+/* Event indicator mask flags */
+#define I2O_EVT_IND_STATE_CHANGE               0x80000000
+#define I2O_EVT_IND_GENERAL_WARNING            0x40000000
+#define I2O_EVT_IND_CONFIGURATION_FLAG         0x20000000
+#define I2O_EVT_IND_LOCK_RELEASE               0x10000000
+#define I2O_EVT_IND_CAPABILITY_CHANGE          0x08000000
+#define I2O_EVT_IND_DEVICE_RESET               0x04000000
+#define I2O_EVT_IND_EVT_MASK_MODIFIED          0x02000000
+#define I2O_EVT_IND_FIELD_MODIFIED             0x01000000
+#define I2O_EVT_IND_VENDOR_EVT                 0x00800000
+#define I2O_EVT_IND_DEVICE_STATE               0x00400000
+
+/* Event data for generic events */
+#define I2O_EVT_STATE_CHANGE_NORMAL            0x00
+#define I2O_EVT_STATE_CHANGE_SUSPENDED         0x01
+#define I2O_EVT_STATE_CHANGE_RESTART           0x02
+#define I2O_EVT_STATE_CHANGE_NA_RECOVER                0x03
+#define I2O_EVT_STATE_CHANGE_NA_NO_RECOVER     0x04
+#define I2O_EVT_STATE_CHANGE_QUIESCE_REQUEST   0x05
+#define I2O_EVT_STATE_CHANGE_FAILED            0x10
+#define I2O_EVT_STATE_CHANGE_FAULTED           0x11
+
+#define I2O_EVT_GEN_WARNING_NORMAL             0x00
+#define I2O_EVT_GEN_WARNING_ERROR_THRESHOLD    0x01
+#define I2O_EVT_GEN_WARNING_MEDIA_FAULT                0x02
+
+#define I2O_EVT_CAPABILITY_OTHER               0x01
+#define I2O_EVT_CAPABILITY_CHANGED             0x02
+
+#define I2O_EVT_SENSOR_STATE_CHANGED           0x01
 
 #ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
 
@@ -246,7 +276,7 @@ struct i2o_message
  
 struct i2o_device
 {
-       pi2o_lct_entry lct_data;/* Device LCT information */
+       i2o_lct_entry *lct_data;/* Device LCT information */
        u32 flags;              
        int i2oversion;         /* I2O version supported. Actually there
                                 * should be high and low version */
@@ -286,7 +316,7 @@ struct i2o_controller
        char name[16];
        int unit;
        int type;
-       int enabled;                            /* Bus level enable */
+       int enabled;
 
 #define I2O_TYPE_PCI           0x01            /* PCI I2O controller */        
 
@@ -298,9 +328,9 @@ struct i2o_controller
        volatile u32 *reply_port;
        volatile u32 *irq_mask;                 /* Interrupt port */
 
-       pi2o_status_block status_block;         /* IOP status block */
-       pi2o_lct lct;
-       pi2o_hrt hrt;
+       i2o_status_block *status_block;         /* IOP status block */
+       i2o_lct *lct;
+       i2o_hrt *hrt;
 
        u32 mem_offset;                         /* MFA offset */
        u32 mem_phys;                           /* MFA physical */
@@ -464,22 +494,22 @@ extern int i2o_release_device(struct i2o_device *, struct i2o_handler *, u32);
 
 extern int i2o_post_this(struct i2o_controller *, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int);
-extern int i2o_issue_claim(struct i2o_controller *, int, int, int, int *, u32);
 extern int i2o_issue_params(int, struct i2o_controller *, int, void *,
                            int, void *, int); 
 
-extern int i2o_query_scalar(struct i2o_controller *, int, int, int, 
-                       void *, int);
-extern int i2o_set_scalar(struct i2o_controller *, int, int, int, 
-                       void *, int);
+extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int);
+extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int);
 
-extern int i2o_query_table(int, struct i2o_controller *, int, int, int, 
-                       void *, int, void *, int);
+extern int i2o_query_table(int, struct i2o_controller *, int, int, int, void *,
+                          int, void *, int);
 extern int i2o_clear_table(struct i2o_controller *, int, int); 
-extern int i2o_row_add_table(struct i2o_controller *, int, int, int,
-                       void *, int);
-extern int i2o_row_delete_table(struct i2o_controller *, int, int, int,
-                       void *, int);
+extern int i2o_row_add_table(struct i2o_controller *, int, int, int, void *,
+                            int);
+extern int i2o_row_delete_table(struct i2o_controller *, int, int, int, void *,
+                               int);
+
+extern int i2o_event_register(struct i2o_controller *, int, int, u32); 
+extern int i2o_event_ack(struct i2o_controller *, int, int, u32, void *, int);
 
 extern void i2o_run_queue(struct i2o_controller *);
 extern void i2o_report_status(const char *, const char *, u32 *);
@@ -615,7 +645,7 @@ extern const char *i2o_get_class_name(int);
 #define I2O_CMD_UTIL_PARAMS_GET                0x06
 #define I2O_CMD_UTIL_PARAMS_SET                0x05
 #define I2O_CMD_UTIL_EVT_REGISTER      0x13
-#define I2O_CMD_UTIL_ACK               0x14
+#define I2O_CMD_UTIL_EVT_ACK           0x14
 #define I2O_CMD_UTIL_CONFIG_DIALOG     0x10
 #define I2O_CMD_UTIL_DEVICE_RESERVE    0x0D
 #define I2O_CMD_UTIL_DEVICE_RELEASE    0x0F
index 441a0ae1e02399a2a09675e27fe0ecc73a7d1175..5683f062d0100c8da5b115be80f54730ce4fa6fd 100644 (file)
@@ -286,7 +286,6 @@ extern mem_map_t * mem_map;
  * goes to clearing the page. If you want a page without the clearing
  * overhead, just use __get_free_page() directly..
  */
-extern struct page * __get_pages(int gfp_mask, unsigned long order);
 #define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0)
 #define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order))
 extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long gfp_order));
@@ -335,7 +334,7 @@ extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
 
 extern void paging_init(void);
-extern void free_area_init(unsigned long);
+extern void free_area_init(unsigned int * zones_size);
 extern void mem_init(void);
 extern void show_mem(void);
 extern void oom(struct task_struct * tsk);
index bb3a3de158dca940a86e009e31033dc0576d5a24..3046cd391fdf784f0e69c61bb0042ed335c1f371 100644 (file)
@@ -287,6 +287,5 @@ __attribute__((section("__ksymtab"))) =                     \
 #define EXPORT_NO_SYMBOLS
 #endif /* MODULE */
 
-extern rwlock_t modlist_lock;
 extern unsigned long get_kcore_size(void);
 #endif /* _LINUX_MODULE_H */
index c2c0431f42dab574bf0cbd17b16fb1e0ae9d3f4c..934e873986434b36bd384ac01aa7a9f1042b1dcb 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * 1999 Copyright (C) Pavel Machek, pavel@ucw.cz. This code is GPL.
+ * 1999/11/04 Copyright (C) 1999 VMware, Inc. (Regis "HPReg" Duchesne)
+ *            Made nbd_end_request() use the io_request_lock
+ */
+
 #ifndef LINUX_NBD_H
 #define LINUX_NBD_H
 
@@ -27,12 +33,19 @@ extern int requests_out;
 static void 
 nbd_end_request(struct request *req)
 {
+       unsigned long flags;
+
 #ifdef PARANOIA
        requests_out++;
 #endif
+       spin_lock_irqsave(&io_request_lock, flags);
        if (end_that_request_first( req, !req->errors, "nbd" ))
-               return;
+               goto out;
        end_that_request_last( req );
+
+out:
+       spin_unlock_irqrestore(&io_request_lock, flags);
+       return;
 }
 
 #define MAX_NBD 128
index 19a3faf0584447310ded970c824689b848b12744..15a0c6d20230af44937c1c74f8334c1661bed87f 100644 (file)
@@ -27,7 +27,7 @@
 #define PAGE_CACHE_MASK                PAGE_MASK
 #define PAGE_CACHE_ALIGN(addr) (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
 
-#define page_cache_alloc()     __get_pages(GFP_USER, 0)
+#define page_cache_alloc()     (mem_map+MAP_NR(__get_free_pages(GFP_USER, 0)))
 #define page_cache_free(x)     __free_page(x)
 #define page_cache_release(x)  __free_page(x)
 
index 6782d70cf7548d69e77301f274ec472648e82dc6..b3ddba42d3e81e5c7b86992cffb8435c5683b2cf 100644 (file)
@@ -61,7 +61,9 @@ struct swap_info_struct {
 };
 
 extern int nr_swap_pages;
-extern int nr_free_pages;
+FASTCALL(unsigned int nr_free_pages(void));
+FASTCALL(unsigned int nr_free_buffer_pages(void));
+FASTCALL(unsigned int nr_free_highpages(void));
 extern int nr_lru_pages;
 extern struct list_head lru_cache;
 extern atomic_t nr_async_pages;
index 8b19e2415db307ec2cb699e2d60574e28782953d..36d75438053ddf36c55370ab5bd8321c5292d0ae 100644 (file)
 char modprobe_path[256] = "/sbin/modprobe";
 
 static inline void
-use_init_file_context(void)
+use_init_fs_context(void)
 {
-       struct fs_struct * fs;
-
-       lock_kernel();
+       struct fs_struct *our_fs, *init_fs;
 
        /*
-        * Don't use the user's root, use init's root instead.
-        * Note that we can use "init_task" (which is not actually
-        * the same as the user-level "init" process) because we
-        * started "init" with a CLONE_FS
+        * Make modprobe's fs context be a copy of init's.
+        *
+        * We cannot use the user's fs context, because it
+        * may have a different root than init.
+        * Since init was created with CLONE_FS, we can grab
+        * its fs context from "init_task".
+        *
+        * The fs context has to be a copy. If it is shared
+        * with init, then any chdir() call in modprobe will
+        * also affect init and the other threads sharing
+        * init_task's fs context.
+        *
+        * We created the exec_modprobe thread without CLONE_FS,
+        * so we can update the fields in our fs context freely.
         */
-       exit_fs(current);       /* current->fs->count--; */
-       fs = init_task.fs;
-       current->fs = fs;
-       atomic_inc(&fs->count);
+       lock_kernel();
+
+       our_fs = current->fs;
+       dput(our_fs->root);
+       dput(our_fs->pwd);
+
+       init_fs = init_task.fs;
+       our_fs->umask = init_fs->umask;
+       our_fs->root = dget(init_fs->root);
+       our_fs->pwd = dget(init_fs->pwd);
 
        unlock_kernel();
 }
@@ -49,7 +63,10 @@ static int exec_modprobe(void * module_name)
        char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL };
        int i;
 
-       use_init_file_context();
+       current->session = 1;
+       current->pgrp = 1;
+
+       use_init_fs_context();
 
        /* Prevent parent user process from sending signals to child.
           Otherwise, if the modprobe program does not exist, it might
@@ -104,7 +121,7 @@ int request_module(const char * module_name)
                return -EPERM;
        }
 
-       pid = kernel_thread(exec_modprobe, (void*) module_name, CLONE_FS);
+       pid = kernel_thread(exec_modprobe, (void*) module_name, 0);
        if (pid < 0) {
                printk(KERN_ERR "request_module[%s]: fork failed, errno %d\n", module_name, -pid);
                return pid;
@@ -126,8 +143,8 @@ int request_module(const char * module_name)
        spin_unlock_irq(&current->sigmask_lock);
 
        if (waitpid_result != pid) {
-               printk (KERN_ERR "kmod: waitpid(%d,NULL,0) failed, returning %d.\n",
-                       pid, waitpid_result);
+               printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n",
+                      module_name, pid, -waitpid_result);
        }
        return 0;
 }
index 62605eecda1b801bc61dfc2cce09552f712f9ceb..22a7b1ea9e1ab9f70ec04a1b454ad6dd61a462c5 100644 (file)
@@ -93,7 +93,6 @@ EXPORT_SYMBOL(exit_sighand);
 
 /* internal kernel memory management */
 EXPORT_SYMBOL(__get_free_pages);
-EXPORT_SYMBOL(__get_pages);
 EXPORT_SYMBOL(free_pages);
 EXPORT_SYMBOL(__free_page);
 EXPORT_SYMBOL(kmem_find_general_cachep);
index a79fa619f22f81c37d3805f7787679f2d315a5a6..08f44a42b126d61f818e00c545a8c6efc5415d16 100644 (file)
@@ -13,7 +13,6 @@
  * 0.99.14 version by Jon Tombs <jon@gtex02.us.es>,
  * Heavily modified by Bjorn Ekwall <bj0rn@blox.se> May 1994 (C)
  * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
- * Use rw spinlock instead of global kernel lock for module_list, by TA <tigran@sco.com>
  *
  * This source is covered by the GNU GPL, the same as all kernel sources.
  */
@@ -53,8 +52,6 @@ static void put_mod_name(char *buf);
 static struct module *find_module(const char *name);
 static void free_module(struct module *, int tag_freed);
 
-rwlock_t modlist_lock = RW_LOCK_UNLOCKED;
-
 
 /* needed for /proc/kcore, here because kernel_module is static (TA) */
 unsigned long get_kcore_size(void)
@@ -65,13 +62,13 @@ unsigned long get_kcore_size(void)
        if (module_list == &kernel_module)
                return ((unsigned long)high_memory - PAGE_OFFSET + PAGE_SIZE);
 
-       read_lock(&modlist_lock);
+       lock_kernel();
        for (m=module_list; m; m=m->next) {
                try = (unsigned long)m + m->size;
                if (try > size)
                        size = try;
        }
-       read_unlock(&modlist_lock);
+       unlock_kernel();
        return (size - PAGE_OFFSET + PAGE_SIZE);
 }
 
@@ -133,7 +130,7 @@ sys_create_module(const char *name_user, size_t size)
        long namelen, error;
        struct module *mod;
 
-       write_lock(&modlist_lock);
+       lock_kernel();
        if (!capable(CAP_SYS_MODULE)) {
                error = -EPERM;
                goto err0;
@@ -171,7 +168,7 @@ sys_create_module(const char *name_user, size_t size)
 err1:
        put_mod_name(name);
 err0:
-       write_unlock(&modlist_lock);
+       unlock_kernel();
        return error;
 }
 
@@ -188,7 +185,7 @@ sys_init_module(const char *name_user, struct module *mod_user)
        unsigned long mod_user_size;
        struct module_ref *dep;
 
-       write_lock(&modlist_lock);
+       lock_kernel();
        if (!capable(CAP_SYS_MODULE))
                goto err0;
        if ((namelen = get_mod_name(name_user, &name)) < 0) {
@@ -367,7 +364,7 @@ err2:
 err1:
        put_mod_name(name);
 err0:
-       write_unlock(&modlist_lock);
+       unlock_kernel();
        return error;
 }
 
@@ -379,7 +376,7 @@ sys_delete_module(const char *name_user)
        long error = -EPERM;
        int something_changed;
 
-       write_lock(&modlist_lock);
+       lock_kernel();
        if (!capable(CAP_SYS_MODULE))
                goto out;
 
@@ -432,7 +429,7 @@ restart:
                mod->flags &= ~MOD_JUST_FREED;
        error = 0;
 out:
-       write_unlock(&modlist_lock);
+       unlock_kernel();
        return error;
 }
 
@@ -446,21 +443,17 @@ qm_modules(char *buf, size_t bufsize, size_t *ret)
 
        nmod = space = 0;
 
-       read_lock(&modlist_lock);
        for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
                len = strlen(mod->name)+1;
                if (len > bufsize)
                        goto calc_space_needed;
-               if (copy_to_user(buf, mod->name, len)) {
-                       read_unlock(&modlist_lock);
+               if (copy_to_user(buf, mod->name, len))
                        return -EFAULT;
-               }
                buf += len;
                bufsize -= len;
                space += len;
        }
 
-       read_unlock(&modlist_lock);
        if (put_user(nmod, ret))
                return -EFAULT;
        else
@@ -471,7 +464,6 @@ calc_space_needed:
        while ((mod = mod->next) != &kernel_module)
                space += strlen(mod->name)+1;
 
-       read_unlock(&modlist_lock);
        if (put_user(space, ret))
                return -EFAULT;
        else
@@ -658,7 +650,7 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
        struct module *mod;
        int err;
 
-       read_lock(&modlist_lock);
+       lock_kernel();
        if (name_user == NULL)
                mod = &kernel_module;
        else {
@@ -704,7 +696,7 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
                break;
        }
 out:
-       read_unlock(&modlist_lock);
+       unlock_kernel();
        return err;
 }
 
@@ -723,7 +715,7 @@ sys_get_kernel_syms(struct kernel_sym *table)
        int i;
        struct kernel_sym ksym;
 
-       read_lock(&modlist_lock);
+       lock_kernel();
        for (mod = module_list, i = 0; mod; mod = mod->next) {
                /* include the count for the module name! */
                i += mod->nsyms + 1;
@@ -766,13 +758,12 @@ sys_get_kernel_syms(struct kernel_sym *table)
                }
        }
 out:
-       read_unlock(&modlist_lock);
+       unlock_kernel();
        return i;
 }
 
 /*
  * Look for a module by name, ignoring modules marked for deletion.
- * Callers must hold modlist_lock at least in read mode.
  */
 
 static struct module *
@@ -792,7 +783,6 @@ find_module(const char *name)
 
 /*
  * Free the given module.
- * Callers must hold modlist_lock in exclusive (write) mode.
  */
 
 static void
@@ -849,7 +839,6 @@ int get_module_list(char *p)
        char tmpstr[64];
        struct module_ref *ref;
 
-       read_lock(&modlist_lock);
        for (mod = module_list; mod != &kernel_module; mod = mod->next) {
                long len;
                const char *q;
@@ -915,7 +904,6 @@ int get_module_list(char *p)
        }
 
 fini:
-       read_unlock(&modlist_lock);
        return PAGE_SIZE - left;
 }
 
@@ -932,7 +920,6 @@ get_ksyms_list(char *buf, char **start, off_t offset, int length)
        off_t pos   = 0;
        off_t begin = 0;
 
-       read_lock(&modlist_lock);
        for (mod = module_list; mod; mod = mod->next) {
                unsigned i;
                struct module_symbol *sym;
@@ -967,7 +954,6 @@ leave_the_loop:
        len -= (offset - begin);
        if (len > length)
                len = length;
-       read_unlock(&modlist_lock);
        return len;
 }
 
@@ -984,7 +970,6 @@ get_module_symbol(char *modname, char *symname)
        struct module_symbol *sym;
        int i;
 
-       read_lock(&modlist_lock);
        for (mp = module_list; mp; mp = mp->next) {
                if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
                        (mp->flags & (MOD_RUNNING | MOD_DELETED)) == MOD_RUNNING &&
@@ -993,13 +978,11 @@ get_module_symbol(char *modname, char *symname)
                                i > 0; --i, ++sym) {
 
                                if (strcmp(sym->name, symname) == 0) {
-                                       read_unlock(&modlist_lock);
                                        return sym->value;
                                }
                        }
                }
        }
-       read_unlock(&modlist_lock);
        return 0;
 }
 
index def9ca7e36e90a2cdda9da11af2bf25608913494..863691221dc9a8c0306e2948c38a5e4ab6d652a7 100644 (file)
@@ -14,9 +14,9 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
+#include <linux/swap.h>
 
 unsigned long highmem_mapnr;
-unsigned long nr_free_highpages = 0;
 
 struct page * prepare_highmem_swapout(struct page * page)
 {
@@ -52,7 +52,7 @@ struct page * replace_with_highmem(struct page * page)
        struct page *highpage;
        unsigned long vaddr;
 
-       if (PageHighMem(page) || !nr_free_highpages)
+       if (PageHighMem(page) || !nr_free_highpages())
                return page;
 
        highpage = get_free_highpage(GFP_ATOMIC|__GFP_HIGHMEM);
index 5dbb24ae260898bddf73927e74ecc9517ae522a6..99e86653d12a02e1e9848446839300c48cb63770 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -64,7 +64,7 @@ int vm_enough_memory(long pages)
 
        free = atomic_read(&buffermem_pages);
        free += atomic_read(&page_cache_size);
-       free += nr_free_pages;
+       free += nr_free_pages();
        free += nr_swap_pages;
        return free > pages;
 }
index e748bc42888651bbd445ea90ea4ff7d5ce11908e..d59a08a7729d73db1d35e7749b97e446de504cef 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *  Swap reorganised 29.12.95, Stephen Tweedie
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ *  Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999
  */
 
 #include <linux/config.h>
@@ -22,7 +23,6 @@
 #include <asm/pgtable.h>
 
 int nr_swap_pages = 0;
-int nr_free_pages = 0;
 int nr_lru_pages;
 LIST_HEAD(lru_cache);
 
@@ -36,30 +36,46 @@ LIST_HEAD(lru_cache);
 #if CONFIG_AP1000
 /* the AP+ needs to allocate 8MB contiguous, aligned chunks of ram
    for the ring buffers */
-#define NR_MEM_LISTS 12
+#define MAX_ORDER 12
 #else
-#define NR_MEM_LISTS 10
+#define MAX_ORDER 10
 #endif
 
-struct free_area_struct {
+typedef struct free_area_struct {
        struct list_head free_list;
        unsigned int * map;
-       unsigned long count;
-};
+} free_area_t;
 
-#define MEM_TYPE_DMA           0
-#define MEM_TYPE_NORMAL                1
-#define MEM_TYPE_HIGH          2
-
-static const char *mem_type_strs[] = {"DMA", "Normal", "High"};
+#define ZONE_DMA               0
+#define ZONE_NORMAL            1
 
 #ifdef CONFIG_HIGHMEM
-#define NR_MEM_TYPES           3
+# define ZONE_HIGHMEM          2
+# define NR_ZONES              3
 #else
-#define NR_MEM_TYPES           2
+# define NR_ZONES              2
 #endif
 
-static struct free_area_struct free_area[NR_MEM_TYPES][NR_MEM_LISTS];
+typedef struct zone_struct {
+       spinlock_t lock;
+       unsigned long offset;
+       unsigned long size;
+       free_area_t free_area[MAX_ORDER];
+
+       unsigned long free_pages;
+       unsigned long pages_low, pages_high;
+       int low_on_memory;
+       char * name;
+} zone_t;
+
+static zone_t zones[NR_ZONES] =
+       {
+               { name: "DMA" },
+               { name: "Normal" },
+#ifdef CONFIG_HIGHMEM
+               { name: "HighMem" }
+#endif
+       };
 
 /*
  * Free_page() adds the page to the free lists. This is optimized for
@@ -88,35 +104,49 @@ spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED;
 #define memlist_next(x) ((x)->next)
 #define memlist_prev(x) ((x)->prev)
 
+/*
+ * Temporary debugging check.
+ */
+#define BAD_RANGE(zone,x) ((((x)-mem_map) < zone->offset) || (((x)-mem_map) >= zone->offset+zone->size))
+
+
 static inline void free_pages_ok(struct page *page, unsigned long map_nr, unsigned long order)
 {
        struct free_area_struct *area;
-       unsigned long index = map_nr >> (1 + order);
-       unsigned long mask = (~0UL) << order;
+       unsigned long index, page_idx, mask, offset;
        unsigned long flags;
        struct page *buddy;
+       zone_t *zone;
+       int i;
 
-       spin_lock_irqsave(&page_alloc_lock, flags);
-
-#define list(x) (mem_map+(x))
-
-#ifdef CONFIG_HIGHMEM
-       if (map_nr >= highmem_mapnr) {
-               area = free_area[MEM_TYPE_HIGH];
-               nr_free_highpages -= mask;
-       } else
-#endif
-       if (PageDMA(page))
-               area = free_area[MEM_TYPE_DMA];
-       else
-               area = free_area[MEM_TYPE_NORMAL];
+       /*
+        * Which zone is this page belonging to.
+        *
+        * (NR_ZONES is low, and we do not want (yet) to introduce
+        * put page->zone, it increases the size of mem_map[]
+        * unnecesserily. This small loop is basically equivalent
+        * to the previous #ifdef jungle, speed-wise.)
+        */
+       i = NR_ZONES-1;
+       zone = zones + i;
+       for ( ; i >= 0; i--, zone--)
+               if (map_nr >= zone->offset)
+                       break;
 
+       mask = (~0UL) << order;
+       offset = zone->offset;
+       area = zone->free_area;
        area += order;
+       page_idx = map_nr - zone->offset;
+       page_idx &= mask;
+       index = page_idx >> (1 + order);
+       mask = (~0UL) << order;
 
-       map_nr &= mask;
-       nr_free_pages -= mask;
+       spin_lock_irqsave(&zone->lock, flags);
 
-       while (mask + (1 << (NR_MEM_LISTS-1))) {
+       zone->free_pages -= mask;
+
+       while (mask + (1 << (MAX_ORDER-1))) {
                if (!test_and_change_bit(index, area->map))
                        /*
                         * the buddy page is still allocated.
@@ -125,21 +155,22 @@ static inline void free_pages_ok(struct page *page, unsigned long map_nr, unsign
                /*
                 * Move the buddy up one level.
                 */
-               buddy = list(map_nr ^ -mask);
-               page = list(map_nr);
+               buddy = mem_map + offset + (page_idx ^ -mask);
+               page = mem_map + offset + page_idx;
+               if (BAD_RANGE(zone,buddy))
+                       BUG();
+               if (BAD_RANGE(zone,page))
+                       BUG();
 
-               area->count--;
                memlist_del(&buddy->list);
                mask <<= 1;
                area++;
                index >>= 1;
-               map_nr &= mask;
+               page_idx &= mask;
        }
-       area->count++;
-       memlist_add_head(&(list(map_nr))->list, &area->free_list);
-#undef list
+       memlist_add_head(&mem_map[offset + page_idx].list, &area->free_list);
 
-       spin_unlock_irqrestore(&page_alloc_lock, flags);
+       spin_unlock_irqrestore(&zone->lock, flags);
 }
 
 /*
@@ -147,7 +178,6 @@ static inline void free_pages_ok(struct page *page, unsigned long map_nr, unsign
  */
 #define MARK_USED(index, order, area) \
        change_bit((index) >> (1+(order)), (area)->map)
-#define CAN_DMA(x) (PageDMA(x))
 #define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
 
 int __free_page(struct page *page)
@@ -182,16 +212,17 @@ int free_pages(unsigned long addr, unsigned long order)
        return 0;
 }
 
-static inline unsigned long EXPAND (struct page *map, unsigned long index,
+static inline unsigned long EXPAND (zone_t *zone, struct page *map, unsigned long index,
                 int low, int high, struct free_area_struct * area)
 {
        unsigned long size = 1 << high;
 
        while (high > low) {
+               if (BAD_RANGE(zone,map))
+                       BUG();
                area--;
                high--;
                size >>= 1;
-               area->count++;
                memlist_add_head(&(map)->list, &(area)->free_list);
                MARK_USED(index, high, area);
                index += size;
@@ -201,79 +232,62 @@ static inline unsigned long EXPAND (struct page *map, unsigned long index,
        return index;
 }
 
-static inline struct page * rmqueue (int order, unsigned type)
+static inline struct page * rmqueue (zone_t *zone, int order)
 {
-       struct free_area_struct * area = free_area[type]+order;
+       struct free_area_struct * area = zone->free_area + order;
        unsigned long curr_order = order, map_nr;
-       struct page *page;
        struct list_head *head, *curr;
+       unsigned long flags;
+       struct page *page;
 
+       spin_lock_irqsave(&zone->lock, flags);
        do {
                head = &area->free_list;
                curr = memlist_next(head);
 
                if (curr != head) {
+                       unsigned int index;
+
                        page = memlist_entry(curr, struct page, list);
                        memlist_del(curr);
-                       area->count--;
-                       map_nr = page - mem_map;        
-                       MARK_USED(map_nr, curr_order, area);
-                       nr_free_pages -= 1 << order;
-                       map_nr = EXPAND(page, map_nr, order, curr_order, area);
+                       map_nr = page - mem_map;
+                       index = map_nr - zone->offset;
+                       MARK_USED(index, curr_order, area);
+                       zone->free_pages -= 1 << order;
+                       map_nr = zone->offset + EXPAND(zone, page, index, order, curr_order, area);
+                       spin_unlock_irqrestore(&zone->lock, flags);
+
                        page = mem_map + map_nr;
+                       if (BAD_RANGE(zone,page))
+                               BUG();
                        return page;    
                }
                curr_order++;
                area++;
-       } while (curr_order < NR_MEM_LISTS);
+       } while (curr_order < MAX_ORDER);
+       spin_unlock_irqrestore(&zone->lock, flags);
 
        return NULL;
 }
 
-static inline int balance_lowmemory (int gfp_mask)
+static inline int balance_memory (zone_t *zone, int gfp_mask)
 {
        int freed;
-       static int low_on_memory = 0;
 
-#ifndef CONFIG_HIGHMEM
-       if (nr_free_pages > freepages.min) {
-               if (!low_on_memory)
+       if (zone->free_pages > zone->pages_low) {
+               if (!zone->low_on_memory)
                        return 1;
-               if (nr_free_pages >= freepages.high) {
-                       low_on_memory = 0;
+               /*
+                * Simple hysteresis: exit 'low memory mode' if
+                * the upper limit has been reached:
+                */
+               if (zone->free_pages >= zone->pages_high) {
+                       zone->low_on_memory = 0;
                        return 1;
                }
        }
+       zone->low_on_memory = 1;
 
-       low_on_memory = 1;
-#else
-       static int low_on_highmemory = 0;
-
-       if (gfp_mask & __GFP_HIGHMEM)
-       {
-               if (nr_free_pages > freepages.min) {
-                       if (!low_on_highmemory) {
-                               return 1;
-                       }
-                       if (nr_free_pages >= freepages.high) {
-                               low_on_highmemory = 0;
-                               return 1;
-                       }
-               }
-               low_on_highmemory = 1;
-       } else {
-               if (nr_free_pages-nr_free_highpages > freepages.min) {
-                       if (!low_on_memory) {
-                               return 1;
-                       }
-                       if (nr_free_pages-nr_free_highpages >= freepages.high) {
-                               low_on_memory = 0;
-                               return 1;
-                       }
-               }
-               low_on_memory = 1;
-       }
-#endif
        current->flags |= PF_MEMALLOC;
        freed = try_to_free_pages(gfp_mask);
        current->flags &= ~PF_MEMALLOC;
@@ -283,13 +297,12 @@ static inline int balance_lowmemory (int gfp_mask)
        return 1;
 }
 
-struct page * __get_pages(int gfp_mask, unsigned long order)
+struct page * __get_pages(zone_t *zone, unsigned int gfp_mask,
+                       unsigned long order)
 {
-       unsigned long flags;
        struct page *page;
-       unsigned type;
 
-       if (order >= NR_MEM_LISTS)
+       if (order >= MAX_ORDER)
                goto nopage;
 
        /*
@@ -303,32 +316,20 @@ struct page * __get_pages(int gfp_mask, unsigned long order)
         * further thought.
         */
        if (!(current->flags & PF_MEMALLOC))
-               goto lowmemory;
-
-ok_to_allocate:
-#ifdef CONFIG_HIGHMEM
-       if (gfp_mask & __GFP_HIGHMEM)
-               type = MEM_TYPE_HIGH;
-       else
-#endif
-       if (gfp_mask & __GFP_DMA)
-               type = MEM_TYPE_DMA;
-       else
-               type = MEM_TYPE_NORMAL;
-
-       spin_lock_irqsave(&page_alloc_lock, flags);
+               if (!balance_memory(zone, gfp_mask))
+                       goto nopage;
+       /*
+        * We are falling back to lower-level zones if allocation
+        * in a higher zone fails. This assumes a hierarchical
+        * dependency between zones, which is true currently. If
+        * you need something else then move this loop outside
+        * this function, into the zone-specific allocator.
+        */
        do {
-               page = rmqueue(order, type);
-               if (page) {
-#ifdef CONFIG_HIGHMEM
-                       if (type == MEM_TYPE_HIGH)
-                               nr_free_highpages -= 1 << order;
-#endif
-                       spin_unlock_irqrestore(&page_alloc_lock, flags);
+               page = rmqueue(zone, order);
+               if (page)
                        return page;
-               }
-       } while (type-- > 0) ;
-       spin_unlock_irqrestore(&page_alloc_lock, flags);
+       } while (zone-- != zones) ;
 
        /*
         * If we can schedule, do so, and make sure to yield.
@@ -342,17 +343,21 @@ ok_to_allocate:
 
 nopage:
        return NULL;
-
-lowmemory:
-       if (balance_lowmemory(gfp_mask))
-               goto ok_to_allocate;
-       goto nopage;
 }
 
 unsigned long __get_free_pages(int gfp_mask, unsigned long order)
 {
        struct page *page;
-       page = __get_pages(gfp_mask, order);
+       zone_t *zone;
+
+       if (gfp_mask & __GFP_DMA)
+               zone = zones + ZONE_DMA;
+       else
+               zone = zones + ZONE_NORMAL;
+       page = __get_pages(zone, gfp_mask, order);
+       if (gfp_mask & __GFP_DMA)
+               if (!PageDMA(page))
+                       BUG();
        if (!page)
                return 0;
        return page_address(page);
@@ -360,9 +365,44 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
 
 struct page * get_free_highpage(int gfp_mask)
 {
-       return __get_pages(gfp_mask, 0);
+       return __get_pages(zones + NR_ZONES-1, gfp_mask, 0);
 }
 
+/*
+ * Total amount of free (allocatable) RAM:
+ */
+unsigned int nr_free_pages (void)
+{
+       unsigned int sum;
+       zone_t *zone;
+
+       sum = 0;
+       for (zone = zones; zone < zones+NR_ZONES; zone++)
+               sum += zone->free_pages;
+       return sum;
+}
+
+/*
+ * Amount of free RAM allocatable as buffer memory:
+ */
+unsigned int nr_free_buffer_pages (void)
+{
+       unsigned int sum;
+       zone_t *zone;
+
+       sum = nr_lru_pages;
+       for (zone = zones; zone <= zones+ZONE_NORMAL; zone++)
+               sum += zone->free_pages;
+       return sum;
+}
+
+#if CONFIG_HIGHMEM
+unsigned int nr_free_highpages (void)
+{
+       return zones[ZONE_HIGHMEM].free_pages;
+}
+#endif
+
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
@@ -374,22 +414,31 @@ void show_free_areas(void)
        unsigned type;
 
        spin_lock_irqsave(&page_alloc_lock, flags);
-       printk("Free pages:      %6dkB (%6ldkB HighMem)\n",
-               nr_free_pages<<(PAGE_SHIFT-10),
-               nr_free_highpages<<(PAGE_SHIFT-10));
+       printk("Free pages:      %6dkB (%6dkB HighMem)\n",
+               nr_free_pages()<<(PAGE_SHIFT-10),
+               nr_free_highpages()<<(PAGE_SHIFT-10));
        printk("( Free: %d, lru_cache: %d (%d %d %d) )\n",
-               nr_free_pages,
+               nr_free_pages(),
                nr_lru_pages,
                freepages.min,
                freepages.low,
                freepages.high);
 
-       for (type = 0; type < NR_MEM_TYPES; type++) {
+       for (type = 0; type < NR_ZONES; type++) {
+               zone_t *zone = zones + type;
                unsigned long total = 0;
-               printk("  %s: ", mem_type_strs[type]);
-               for (order = 0; order < NR_MEM_LISTS; order++) {
-                       unsigned long nr = free_area[type][order].count;
 
+               printk("  %s: ", zone->name);
+               for (order = 0; order < MAX_ORDER; order++) {
+                       unsigned long i, nr;
+
+                       nr = 0;
+                       for (i = 0; i < zone->size; i += 1<<order) {
+                               struct page * page;
+                               page = mem_map + zone->offset + i;
+                               if (!page_count(page))
+                                       nr++;
+                       }
                        total += nr * ((PAGE_SIZE>>10) << order);
                        printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order));
                }
@@ -405,18 +454,24 @@ void show_free_areas(void)
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
 /*
- * set up the free-area data structures:
+ * Set up the zone data structures:
  *   - mark all pages reserved
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
-volatile int data;
-void __init free_area_init(unsigned long end_mem_pages)
+void __init free_area_init(unsigned int *zones_size)
 {
        mem_map_t * p;
        unsigned long i, j;
        unsigned long map_size;
+       unsigned int totalpages, offset;
+
+       totalpages = 0;
+       for (i = 0; i < NR_ZONES; i++)
+               totalpages += zones_size[i];
+       printk("totalpages: %08x\n", totalpages);
 
+       i = totalpages >> 7;
        /*
         * Select nr of pages we try to keep free for important stuff
         * with a minimum of 10 pages and a maximum of 256 pages, so
@@ -424,7 +479,7 @@ void __init free_area_init(unsigned long end_mem_pages)
         * This is fairly arbitrary, but based on some behaviour
         * analysis.
         */
-       i = end_mem_pages >> 7;
+       i = totalpages >> 7;
        if (i < 10)
                i = 10;
        if (i > 256)
@@ -434,11 +489,10 @@ void __init free_area_init(unsigned long end_mem_pages)
        freepages.high = i * 3;
 
        /*
-        * Most architectures just pick 'start_mem'. Some architectures
-        * (with lots of mem and discontinous memory maps) have to search
-        * for a good area.
+        * Some architectures (with lots of mem and discontinous memory
+        * maps) have to search for a good mem_map area:
         */
-       map_size = end_mem_pages*sizeof(struct page);
+       map_size = totalpages*sizeof(struct page);
        mem_map = (struct page *) alloc_bootmem(map_size);
        memset(mem_map, 0, map_size);
 
@@ -447,27 +501,39 @@ void __init free_area_init(unsigned long end_mem_pages)
         * up by free_all_bootmem() once the early boot process is
         * done.
         */
-       for (p = mem_map; p < mem_map + end_mem_pages; p++) {
+       for (p = mem_map; p < mem_map + totalpages; p++) {
                set_page_count(p, 0);
                p->flags = (1 << PG_DMA);
                SetPageReserved(p);
                init_waitqueue_head(&p->wait);
                memlist_init(&p->list);
        }
-       
-       for (j = 0 ; j < NR_MEM_TYPES ; j++) {
+
+       offset = 0;     
+       for (j = 0; j < NR_ZONES; j++) {
+               zone_t *zone = zones + j;
                unsigned long mask = -1;
-               for (i = 0 ; i < NR_MEM_LISTS ; i++) {
+               unsigned long size;
+
+               size = zones_size[j];
+               zone->size = size;
+               zone->offset = offset;
+               zone->pages_low = freepages.low;
+               zone->pages_high = freepages.high;
+               zone->low_on_memory = 0;
+
+               offset += size;
+               for (i = 0; i < MAX_ORDER; i++) {
                        unsigned long bitmap_size;
                        unsigned int * map;
-                       memlist_init(&free_area[j][i].free_list);
+                       memlist_init(&zone->free_area[i].free_list);
                        mask += mask;
-                       end_mem_pages = (end_mem_pages + ~mask) & mask;
-                       bitmap_size = end_mem_pages >> i;
+                       size = (size + ~mask) & mask;
+                       bitmap_size = size >> i;
                        bitmap_size = (bitmap_size + 7) >> 3;
                        bitmap_size = LONG_ALIGN(bitmap_size);
                        map = (unsigned int *) alloc_bootmem(bitmap_size);
-                       free_area[j][i].map = map;
+                       zone->free_area[i].map = map;
                        memset((void *) map, 0, bitmap_size);
                }
        }
index 102e97e3a65011b72c976926779e3f6b8a0a888d..14f5dc44482a8a97595258c842c11855a306c6c0 100644 (file)
@@ -503,7 +503,7 @@ int kswapd(void *unused)
                do {
                        /* kswapd is critical to provide GFP_ATOMIC
                           allocations (not GFP_HIGHMEM ones). */
-                       if (nr_free_pages - nr_free_highpages >= freepages.high)
+                       if (nr_free_buffer_pages() >= freepages.high)
                                break;
 
                        if (!do_try_to_free_pages(GFP_KSWAPD))