]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.64 2.1.64
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:02 +0000 (15:14 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:02 +0000 (15:14 -0500)
41 files changed:
CREDITS
Documentation/Configure.help
Makefile
arch/i386/kernel/head.S
arch/i386/kernel/setup.c
arch/i386/kernel/trampoline.S
arch/i386/kernel/traps.c
arch/i386/mm/fault.c
drivers/char/atixlmouse.c
drivers/char/msbusmouse.c
drivers/misc/parport_pc.c
drivers/net/README.de4x5
drivers/net/README.multicast
drivers/net/de4x5.c
drivers/net/de4x5.h
drivers/pci/pci.c
drivers/scsi/Config.in
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/scsi/psi_chip.h
drivers/scsi/seagate.c
drivers/scsi/st.c
drivers/scsi/st.h
drivers/sound/Config.in
drivers/sound/lowlevel/awe_config.h
fs/ext2/fsync.c
fs/isofs/symlink.c
fs/ncpfs/dir.c
fs/ncpfs/mmap.c
fs/ncpfs/sock.c
fs/nfs/dir.c
fs/nfs/inode.c
include/asm-i386/bugs.h
include/asm-i386/system.h
include/linux/head.h
include/linux/miscdevice.h
include/linux/ncp_fs.h
include/linux/pci.h
kernel/ksyms.c
net/Config.in
net/ipx/af_ipx.c

diff --git a/CREDITS b/CREDITS
index 892798e3503df423f624d79233aaaa97b8414305..22f6b28eba387dcbe2364658fa3419bc6e3920b7 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -981,7 +981,7 @@ S: Czech Republic
 
 N: John A. Martin
 E: jam@acm.org
-W: http://linux.wauug.org/~jam/
+W: http://www.tux.org/~jam/
 P: 1024/04456D53 9D A3 6C 6B 88 80 8A 61  D7 06 22 4F 95 40 CE D2
 P: 1024/3B986635 5A61 7EE6 9E20 51FB 59FB  2DA5 3E18 DD55 3B98 6635
 D: FSSTND contributor
@@ -1145,9 +1145,10 @@ S: 55127 Mainz
 S: Germany
 
 N: David C. Niemi
-E: niemi@erols.com
+E: niemi@tux.org
+W: http://www.tux.org/~niemi/
 D: Assistant maintainer of Mtools, fdutils, and floppy driver
-D: Administrator of WAUUG Linux Server, http://linux.wauug.org
+D: Administrator of Tux.Org Linux Server, http://www.tux.org
 S: 2364 Old Trail Drive
 S: Reston, Virginia 20191
 S: USA
index ea7bf41dcdf8ff43869da2bedaf803b6d497ba83..9347961228680e167db049c8810e79be7871e7d3 100644 (file)
@@ -2367,13 +2367,6 @@ CONFIG_SCSI_PPA_HAVE_PEDANTIC
   your EPP chipset is from the SMC series, you are likely to have to
   set this value greater than 0.
 
-EPP Timing
-CONFIG_SCSI_PPA_EPP_TIME
-  This is the "reset time period", a delay time. The lower the value,
-  the faster the access to the ZIP drive; too low a value may
-  cause all sorts of mid-level SCSI problems however. If unsure, go
-  with the default.
-
 Network device support?
 CONFIG_NETDEVICES
   You can say N here in case you don't intend to connect to any other
@@ -5260,7 +5253,7 @@ Radio support
 CONFIG_MISC_RADIO
   If you have a radio card (you will probably know if you do!), then
   you will want to say "y" here and make a character device file 
-  (usually /dev/radio) with major number 10 and minor 129 using mknod
+  (usually /dev/radio) with major number 10 and minor 152 using mknod
   ("man mknod").  And then, don't forget to pick up some useful tools
   to use said device (you _might_ find something at ftp.lmh.ox.ac.uk:
   /users/weejock/linux/radio/, but I haven't written anything too
index 02dba9d90732b8f863c3d11e0bd624d3a8921485..3102923867c848b8156c422e43f5d0f1c0ce252f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 63
+SUBLEVEL = 64
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
index ef2cfa9a20a9c93229b8b680d0bdc7375824af32..00a8e122edf4b7cb5fa8dc2853da048ba6270d71 100644 (file)
@@ -289,7 +289,7 @@ setup_idt:
        movw %dx,%ax            /* selector = 0x0010 = cs */
        movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
 
-       lea SYMBOL_NAME(idt),%edi
+       lea SYMBOL_NAME(idt_table),%edi
        mov $256,%ecx
 rp_sidt:
        movl %eax,(%edi)
@@ -328,23 +328,33 @@ ignore_int:
        iret
 
 /*
- * The interrupt descriptor table has room for 256 idt's
+ * The interrupt descriptor table has room for 256 idt's,
+ * the global descriptor table is dependent on the number
+ * of tasks we can have..
  */
+#define IDT_ENTRIES    256
+#ifdef CONFIG_APM
+#define GDT_ENTRIES    (11+2*NR_TASKS)
+#else
+#define GDT_ENTRIES    (8+2*NR_TASKS)
+#endif
+
+
+.globl SYMBOL_NAME(idt)
+.globl SYMBOL_NAME(gdt)
+
        ALIGN
-.word 0
+       .word 0
 idt_descr:
-       .word 256*8-1           # idt contains 256 entries
-       .long SYMBOL_NAME(idt)
+       .word IDT_ENTRIES*8-1           # idt contains 256 entries
+SYMBOL_NAME(idt):
+       .long SYMBOL_NAME(idt_table)
 
-       ALIGN
-.word 0
+       .word 0
 gdt_descr:
-#ifdef CONFIG_APM
-       .word (11+2*NR_TASKS)*8-1
-#else
-       .word (8+2*NR_TASKS)*8-1
-#endif
-       .long SYMBOL_NAME(gdt)
+       .word GDT_ENTRIES*8-1
+SYMBOL_NAME(gdt):
+       .long SYMBOL_NAME(gdt_table)
 
 /*
  * This is initialized to create a identity-mapping at 0-4M (for bootup
@@ -515,7 +525,7 @@ ENTRY(this_must_match_init_task)
 
 ALIGN
 /* 256 quadwords - 2048 bytes of idt */
-ENTRY(idt)
+ENTRY(idt_table)
        .fill 256,8,0           # idt is uninitialized
 
 /*
@@ -528,7 +538,7 @@ ENTRY(idt)
  * NOTE! Make sure the gdt descriptor in head.S matches this if you
  * change anything.
  */
-ENTRY(gdt)
+ENTRY(gdt_table)
        .quad 0x0000000000000000        /* NULL descriptor */
        .quad 0x0000000000000000        /* not used */
        .quad 0x00cf9a000000ffff        /* 0x10 kernel 4GB code at 0x00000000 */
index 8e5c9f83565c6e71723cc9d3e935b61ad69f7929..9868811a6a0ee72c2500d420efc5afee6b7e4742 100644 (file)
@@ -360,7 +360,7 @@ int get_cpuinfo(char * buffer)
                                        "fdiv_bug\t: %s\n"
                                        "hlt_bug\t\t: %s\n"
                                       "sep_bug\t\t: %s\n"
-                                      "pentium_f00f_bug\t\t: %s\n"
+                                      "f00f_bug\t: %s\n"
                                        "fpu\t\t: %s\n"
                                        "fpu_exception\t: %s\n"
                                        "cpuid\t\t: %s\n"
index d0a726f6b2c7351c26e4f005d072d7f53c4faa8e..f44b9abde53de58b174cab5618896ba6bd0285ae 100644 (file)
@@ -62,7 +62,7 @@ idt_48:
 
 gdt_48:
        .word   0x0800                  # gdt limit = 2048, 256 GDT entries
-       .long   gdt-0xc0000000          # gdt base = gdt (first SMP CPU)
+       .long   gdt_table-0xc0000000    # gdt base = gdt (first SMP CPU)
 
 .globl SYMBOL_NAME(trampoline_end)
 SYMBOL_NAME_LABEL(trampoline_end)
index bafc5f9ead572870817015caa8293ecdcd8d1589..3dd747b864d3da82c7d9300d1f3ce8927d01b7a0 100644 (file)
@@ -413,47 +413,26 @@ asmlinkage void math_emulate(long arg)
 
 #endif /* CONFIG_MATH_EMULATION */
 
-static struct
-{
-       short limit __attribute__((packed));
-       void * addr __attribute__((packed));
-       short __pad __attribute__((packed));
-} idt_d;
-
-void * idt2;
-
 __initfunc(void trap_init_f00f_bug(void))
 {
-       pgd_t * pgd;
-       pmd_t * pmd;
-       pte_t * pte;
-       unsigned long twopage;
-
-       printk("moving IDT ... ");
-
-       twopage = (unsigned long) vmalloc (2*PAGE_SIZE);
-
-       idt2 = (void *)(twopage + 4096-7*8);
-
-       memcpy(idt2,&idt,sizeof(idt));
-
-       idt_d.limit = 256*8-1;
-       idt_d.addr = idt2;
-       idt_d.__pad = 0;
-
-        __asm__ __volatile__("\tlidt %0": "=m" (idt_d));
+       unsigned long page;
 
        /*
-        * Unmap lower page:
+        * Allocate a new page in virtual address space, 
+        * and move the IDT to have entry #7 starting at
+        * the beginning of the page. We'll force a page
+        * fault for IDT entries #0-#6..
         */
-       pgd = pgd_offset(current->mm, twopage);
-       pmd = pmd_offset(pgd, twopage);
-       pte = pte_offset(pmd, twopage);
+       page = (unsigned long) vmalloc(PAGE_SIZE);
+       memcpy((void *) page, idt_table + 7, (256-7)*8);
 
-       pte_clear(pte);
-       flush_tlb_all();
-
-       printk(" ... done\n");
+       /*
+        * "idt" is magic - it overlaps the idt_descr
+        * variable so that updating idt will automatically
+        * update the idt descriptor..
+        */
+       idt = (struct desc_struct *)(page - 7*8);
+       __asm__ __volatile__("lidt %0": "=m" (idt_descr));
 }
 
 
index e3c54c6838a5000532b73fb54d87b03004f3fba8..674e8f8756eb128851e2fd2b182982c6dd4a0c18 100644 (file)
@@ -74,14 +74,6 @@ bad_area:
        return 0;
 }
 
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-
 asmlinkage void do_divide_error (struct pt_regs *, unsigned long);
 asmlinkage void do_debug (struct pt_regs *, unsigned long);
 asmlinkage void do_nmi (struct pt_regs *, unsigned long);
@@ -90,7 +82,6 @@ asmlinkage void do_overflow (struct pt_regs *, unsigned long);
 asmlinkage void do_bounds (struct pt_regs *, unsigned long);
 asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
 
-extern int * idt2;
 extern int pentium_f00f_bug;
 
 /*
@@ -105,18 +96,46 @@ extern int pentium_f00f_bug;
  */
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
+       struct task_struct *tsk;
+       struct mm_struct *mm;
        struct vm_area_struct * vma;
        unsigned long address;
        unsigned long page;
        unsigned long fixup;
        int write;
 
-       lock_kernel();
-
        /* get the address */
        __asm__("movl %%cr2,%0":"=r" (address));
+
+       /*
+        * Pentium F0 0F C7 C8 bug workaround. Do this first,
+        * to make sure we don't have locking problems with
+        * asynchronous traps (ie NMI). 
+        */
+       if ( !(error_code & 7) && pentium_f00f_bug ) {
+               unsigned long nr;
+               
+               nr = (address - (unsigned long) idt) >> 3;
+
+               if (nr < 7) {
+                       static void (*handler[])(struct pt_regs *, unsigned long) = {
+                               do_divide_error,        /* 0 - divide overflow */
+                               do_debug,               /* 1 - debug trap */
+                               do_nmi,                 /* 2 - NMI */
+                               do_int3,                /* 3 - int 3 */
+                               do_overflow,            /* 4 - overflow */
+                               do_bounds,              /* 5 - bound range */
+                               do_invalid_op };        /* 6 - invalid opcode */
+                       handler[nr](regs, 0);
+                       return;
+               }
+       }
+
+       lock_kernel();
+
+       tsk = current;
+       mm = tsk->mm;
+
        down(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -189,46 +208,6 @@ bad_area:
                goto out;
        }
 
-       printk("<%p/%p>\n", idt2, (void *)address);
-       /*
-        * Pentium F0 0F C7 C8 bug workaround:
-        */
-       if ( pentium_f00f_bug && (address >= (unsigned long)idt2) &&
-                       (address < (unsigned long)idt2+256*8) ) {
-
-               void (*handler) (void);
-               int nr = (address-(unsigned long)idt2)/8;
-               unsigned long low, high;
-
-               low = idt[nr].a;
-               high = idt[nr].b;
-
-               handler = (void (*) (void)) ((low&0x0000ffff) | (high&0xffff0000));
-               printk("<handler %p... ", handler);
-               unlock_kernel();
-
-               if (handler==divide_error)
-                       do_divide_error(regs,error_code);
-               else if (handler==debug)
-                       do_debug(regs,error_code);
-               else if (handler==nmi)
-                       do_nmi(regs,error_code);
-               else if (handler==int3)
-                       do_int3(regs,error_code);
-               else if (handler==overflow)
-                       do_overflow(regs,error_code);
-               else if (handler==bounds)
-                       do_bounds(regs,error_code);
-               else if (handler==invalid_op)
-                       do_invalid_op(regs,error_code);
-               else {
-                       printk("INVALID HANDLER!\n");
-                       for (;;) __cli();
-               }
-               printk("... done>\n");
-               goto out;
-       }
-
        /* Are we prepared to handle this kernel fault?  */
        if ((fixup = search_exception_table(regs->eip)) != 0) {
                printk(KERN_DEBUG "%s: Exception at [<%lx>] cr2=%lx (fixup: %lx)\n",
index 7ffee43bcf6073263bbfe188968d6bd6d81759d2..51451a0a27302c6481b41c5b25325775244099d3 100644 (file)
@@ -136,16 +136,16 @@ static int open_mouse(struct inode * inode, struct file * file)
 }
 
 
-static long write_mouse(struct inode * inode, struct file * file,
-       const char * buffer, unsigned long count)
+static ssize_t write_mouse(struct file * file, const char * buffer,
+       size_t count, loff_t *ppos)
 {
        return -EINVAL;
 }
 
-static long read_mouse(struct inode * inode, struct file * file,
-       char * buffer, unsigned long count)
+static ssize_t read_mouse(struct file * file, char * buffer,
+       size_t count, loff_t *ppos)
 {
-       int i;
+       ssize_t i;
 
        if (count < 3)
                return -EINVAL;
index a8c32ce6d9c4f3775becd59faf1d47353a6729eb..75b7e7f3229343203d947b2ad8f2af22d1afd0b4 100644 (file)
@@ -129,15 +129,14 @@ static int open_mouse(struct inode * inode, struct file * file)
        return 0;
 }
 
-
-static long write_mouse(struct inode * inode, struct file * file,
-       const char * buffer, unsigned long count)
+static ssize_t write_mouse(struct file * file,
+       const char * buffer, size_t count, loff_t *ppos)
 {
        return -EINVAL;
 }
 
-static long read_mouse(struct inode * inode, struct file * file,
-       char * buffer, unsigned long count)
+static ssize_t read_mouse(struct file * file,
+       char * buffer, size_t count, loff_t *ppos)
 {
        int i, dx, dy;
 
index 477b350e34c851e46db431df690d03b4956f7ce4..c5a7a2a1168ce91aa537b062f69bc2b5ce0a71df 100644 (file)
@@ -889,9 +889,9 @@ int parport_pc_init(int *io, int *irq, int *dma)
 }
 
 #ifdef MODULE
-static int io[PC_MAX_PORTS+1] = { 0, };
-static int dma[PC_MAX_PORTS] = { PARPORT_DMA_AUTO, };
-static int irq[PC_MAX_PORTS] = { PARPORT_IRQ_AUTO, };
+static int io[PC_MAX_PORTS+1] = { [0 ... PC_MAX_PORTS] = 0 };
+static int dma[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int irq[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO };
 MODULE_PARM(io, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
index 1184377233a892f201ec62edee86b4432559171a..3e838c22258f13288f93a97bc2fbebd79fd203d3 100644 (file)
@@ -1,7 +1,23 @@
-This driver has been upgraded to include generic DECchip support through the
-use of the on-board SROM  that is found on all  DECchip cards except for the
-DC21040. The driver  will work with the following  set of cards and probably
-more:
+    Originally,   this  driver  was    written  for the  Digital   Equipment
+    Corporation series of EtherWORKS ethernet cards:
+
+        DE425 TP/COAX EISA
+       DE434 TP PCI
+       DE435 TP/COAX/AUI PCI
+       DE450 TP/COAX/AUI PCI
+       DE500 10/100 PCI Fasternet
+
+    but it  will  now attempt  to  support all  cards which   conform to the
+    Digital Semiconductor   SROM   Specification.    The  driver   currently
+    recognises the following chips:
+
+        DC21040     (no SROM)
+       DC21041[A]
+       DC21140[A]
+       DC21142 
+       DC21143 
+
+    So far the driver is known to work with the following cards:
 
         KINGSTON
        Linksys
@@ -9,34 +25,119 @@ more:
        SMC8432
        SMC9332 (w/new SROM)
        ZNYX31[45]
-       DIGITAL EtherWORKS PCI/EISA (DE425, DE434, DE435, DE450, DE500)
-
-Auto media detection is provided so that the  media choice isn't compiled in
-and is  flexible enough to be able  to  reconfigure on-the-fly. 
-
-The ability to load this driver as  a loadable module  has been included and
-will now load  (and   unload) as many  DECchip  cards  as  it can  find  and
-configure with just one invocation of 'insmod'.
+       ZNYX346 10/100 4 port (can act as a 10/100 bridge!) 
 
-The performance we've achieved  so far has  been measured through the 'ttcp'
-tool at 1.06MB/s for  TCP  and 1.17MB/s for  UDP.   This measures  the total
-stack performance which  includes the  card, so don't   expect to get   much
-nearer the 1.25MB/s theoretical ethernet rate.
+    The driver has been tested on a relatively busy network using the DE425,
+    DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
+    16M of data to a DECstation 5000/200 as follows:
 
                 TCP           UDP
              TX     RX     TX     RX
-    DE425   1030k  997k   1170k  1128k                 (EISA on a Dell 433DE)
-    DE434   1063k  995k   1170k  1125k                 (PCI: DECpc XL 466d2)
-    DE435   1063k  995k   1170k  1125k                 (PCI: DECpc XL 466d2)
-    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode (PCI: DECpc XL 466d2)
+    DE425   1030k  997k   1170k  1128k
+    DE434   1063k  995k   1170k  1125k
+    DE435   1063k  995k   1170k  1125k
+    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode
+
+    All  values are typical (in   kBytes/sec) from a  sample  of 4 for  each
+    measurement. Their error is +/-20k on a quiet (private) network and also
+    depend on what load the CPU has.
+
+    =========================================================================
+
+    The ability to load this  driver as a loadable  module has been included
+    and used extensively  during the driver development  (to save those long
+    reboot sequences).  Loadable module support  under PCI and EISA has been
+    achieved by letting the driver autoprobe as if it were compiled into the
+    kernel. Do make sure  you're not sharing  interrupts with anything  that
+    cannot accommodate  interrupt  sharing!
+
+    To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) for fixed  autoprobes (not  recommended),  edit the source code  near
+    line 5537 to reflect the I/O address  you're using, or assign these when
+    loading by:
+
+                   insmod de4x5 io=0xghh           where g = bus number
+                                                       hh = device number   
+
+       NB: autoprobing for modules is now supported by default. You may just
+           use:
+
+                   insmod de4x5
+
+           to load all available boards. For a specific board, still use
+          the 'io=?' above.
+    3) compile  de4x5.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the de4x5 configuration turned off and reboot.
+    5) insmod de4x5 [io=0xghh]
+    6) run the net startup bits for your new eth?? interface(s) manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    To unload a module, turn off the associated interface(s) 
+    'ifconfig eth?? down' then 'rmmod de4x5'.
+
+    Automedia detection is included so that in  principal you can disconnect
+    from, e.g.  TP, reconnect  to BNC  and  things will still work  (after a
+    pause whilst the   driver figures out   where its media went).  My tests
+    using ping showed that it appears to work....
+
+    By  default,  the driver will  now   autodetect any  DECchip based card.
+    Should you have a need to restrict the driver to DIGITAL only cards, you
+    can compile with a  DEC_ONLY define, or if  loading as a module, use the
+    'dec_only=1'  parameter. 
+
+    The SMC9332 card  has a non-compliant SROM  which needs fixing -  I have
+    patched this  driver to detect it  because the SROM format used complies
+    to a previous DEC-STD format.
+
+    I have removed the buffer copies needed for receive on Intels.  I cannot
+    remove them for   Alphas since  the  Tulip hardware   only does longword
+    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
+    longword aligned data copies (which makes them really slow). No comment.
+
+    I  have added SROM decoding  routines to make this  driver work with any
+    card that  supports the Digital  Semiconductor SROM spec. This will help
+    all  cards running the dc2114x  series chips in particular.  Cards using
+    the dc2104x  chips should run correctly with  the basic  driver.  I'm in
+    debt to <mjacob@feral.com> for the  testing and feedback that helped get
+    this feature working.  So far we have  tested KINGSTON, SMC8432, SMC9332
+    (with the latest SROM complying  with the SROM spec  V3: their first was
+    broken), ZNYX342  and  LinkSys. ZYNX314 (dual  21041  MAC) and  ZNYX 315
+    (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
+    wired IRQs.
 
-All  values are   typical  (in kBytes/sec) from   a  sample of   4  for each
-measurement. Their error  is approx +/-20k on a  quiet (private) network and
-also depend on what load the CPU has, CPU speed etc.
+    I have added a temporary fix for interrupt problems when some SCSI cards
+    share the same interrupt as the DECchip based  cards. The problem occurs
+    because  the SCSI card wants to  grab the interrupt  as a fast interrupt
+    (runs the   service routine with interrupts turned   off) vs.  this card
+    which really needs to run the service routine with interrupts turned on.
+    This driver will  now   add the interrupt service   routine  as  a  fast
+    interrupt if it   is bounced from the   slow interrupt.  THIS IS NOT   A
+    RECOMMENDED WAY TO RUN THE DRIVER  and has been done  for a limited time
+    until  people   sort  out their  compatibility    issues and the  kernel
+    interrupt  service code  is  fixed.   YOU  SHOULD SEPARATE OUT  THE FAST
+    INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+    run on the same interrupt. PCMCIA/CardBus is another can of worms...
 
-I've had  reports  that Alphas  can get 80+Mb/s   when using  100BASE-TX and
-similar figures for 133MHz Pentium Pros.
+    Finally, I think  I have really  fixed  the module  loading problem with
+    more than one DECchip based  card.  As a  side effect, I don't mess with
+    the  device structure any  more which means that  if more than 1 card in
+    2.0.x is    installed (4  in   2.1.x),  the  user   will have   to  edit
+    linux/drivers/net/Space.c  to make room for  them. Hence, module loading
+    is  the preferred way to use   this driver, since  it  doesn't have this
+    limitation.
 
-Enjoy!
+    Where SROM  media detection is used and  full duplex is specified in the
+    SROM, the feature is ignored unless de4x5_full_duplex  is set at compile
+    time OR during a module  load (insmod de4x5 de4x5_full_duplex=1).   This
+    is because there  is no way  to automatically  detect full duplex  links
+    except through  autonegotiation.   When I  include  the  autonegotiation
+    feature  in  the  SROM  autoconf   code,   this detection  will    occur
+    automatically.
 
-Dave
index 8bc9397ec6a650dba9400468541061a2fa447094..b7e234e0394cdfabf64f8dc9b87d8535eb61bd79 100644 (file)
@@ -26,7 +26,7 @@ arcnet                NO              NO              NO              N/A
 at1700         PROMISC         PROMISC         YES             Software
 atp            PROMISC         PROMISC         YES             Software
 cs89x0         YES             YES             YES             Software
-de4x5          YES             NO              YES             Hardware
+de4x5          YES             YES             YES             Hardware
 de600          NO              NO              NO              N/A
 de620          PROMISC         PROMISC         YES             Software
 depca          YES             PROMISC         YES             Hardware
index a199c7f8a22826880e992255c4630c549ad08af5..d58deaf5dda3773b424cfd998abe905a143d8d41 100644 (file)
     Digital Semiconductor   SROM   Specification.    The  driver   currently
     recognises the following chips:
 
-        DC21040     (no SROM)
-       DC21041[A]
-       DC21140[A]
+        DC21040  (no SROM) 
+       DC21041[A]  
+       DC21140[A] 
+       DC21142 
+       DC21143 
 
-    I plan to  add DC2114[23]  support ASAP,  time permitting.   So far  the
-    driver is known to work with the following cards:
+    So far the driver is known to work with the following cards:
 
         KINGSTON
        Linksys
     1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
     2) for fixed  autoprobes (not  recommended),  edit the source code  near
-    line 5005 to reflect the I/O address  you're using, or assign these when
+    line 5539 to reflect the I/O address  you're using, or assign these when
     loading by:
 
                    insmod de4x5 io=0xghh           where g = bus number
     INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
     run on the same interrupt. PCMCIA/CardBus is another can of worms...
 
+    Finally, I think  I have really  fixed  the module  loading problem with
+    more than one DECchip based  card.  As a  side effect, I don't mess with
+    the  device structure any  more which means that  if more than 1 card in
+    2.0.x is    installed (4  in   2.1.x),  the  user   will have   to  edit
+    linux/drivers/net/Space.c  to make room for  them. Hence, module loading
+    is  the preferred way to use   this driver, since  it  doesn't have this
+    limitation.
+
+    Where SROM  media detection is used and  full duplex is specified in the
+    SROM, the feature is ignored unless de4x5_full_duplex  is set at compile
+    time OR during a module  load (insmod de4x5 de4x5_full_duplex=1).   This
+    is because there  is no way  to automatically  detect full duplex  links
+    except through  autonegotiation.   When I  include  the  autonegotiation
+    feature  in  the  SROM  autoconf   code,   this detection  will    occur
+    automatically.
+
     TO DO:
     ------
 
+    o check what revision numbers the 21142 and 21143 have
+    o
 
     Revision History
     ----------------
                          Added byte counters from <phil@tazenda.demon.co.uk>
                          Added SA_INTERRUPT temporary fix from 
                           <mjacob@feral.com>.
+      0.53   12-Nov-97    Fix the *_probe() to include 'eth??' name during
+                           module load: bug reported by
+                          <Piete.Brooks@cl.cam.ac.uk>
+                         Fix multi-MAC, one SROM, to work with 2114x chips:
+                          bug reported by <cmetz@inner.net>.
+                         Make above search independent of BIOS device scan
+                          direction.
+                         Completed DC2114[23] autosense functions.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.53 1997/11/12 davies@maniac.ultranet.com\n";
 
 #include <linux/module.h>
 
@@ -319,7 +346,6 @@ static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -340,25 +366,28 @@ static const char *version = "de4x5.c:V0.52 1997/4/26 davies@maniac.ultranet.com
 #define c_char const char
 
 #include <linux/version.h>
-#if    LINUX_VERSION_CODE < ((2 << 16) | (1 << 8))
-#define        net_device_stats      enet_statistics
-#define copy_to_user(a,b,c)   memcpy_tofs(a,b,c)
-#define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
-#define le16_to_cpu(a) cpu_to_le16(a) 
-#define le32_to_cpu(a) cpu_to_le32(a) 
-#ifdef __powerpc__
-#define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
-#define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
-                       (((a) & 0x0000ff00U) <<  8) |\
-                       (((a) & 0x00ff0000U) >>  8) |\
-                       (((a) & 0xff000000U) >> 24))
-#else
-#define cpu_to_le16(a) (a)
-#define cpu_to_le32(a) (a)
-#endif  /* __powerpc__ */
-#include       <asm/segment.h>
+#if    LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#  define __initfunc(__arginit) __arginit
+#  define test_and_set_bit      set_bit
+#  define net_device_stats      enet_statistics
+#  define copy_to_user(a,b,c)   memcpy_tofs(a,b,c)
+#  define copy_from_user(a,b,c) memcpy_fromfs(a,b,c)
+#  define le16_to_cpu(a)        cpu_to_le16(a) 
+#  define le32_to_cpu(a)        cpu_to_le32(a) 
+#  ifdef __powerpc__
+#    define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8))
+#    define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\
+                           (((a) & 0x0000ff00U) <<  8) |\
+                           (((a) & 0x00ff0000U) >>  8) |\
+                           (((a) & 0xff000000U) >> 24))
+#  else
+#    define cpu_to_le16(a)      (a)
+#    define cpu_to_le32(a)      (a)
+#  endif  /* __powerpc__ */
+#  include <asm/segment.h>
 #else
-#include       <asm/uaccess.h>
+#  include <asm/uaccess.h>
+#  include <linux/init.h>
 #endif  /* LINUX_VERSION_CODE */
 #define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
 
@@ -392,6 +421,7 @@ struct mii_phy {
     u_int ana;              /* NWay Advertisement                        */
     u_int fdx;              /* Full DupleX capabilites for each media    */
     u_int ttm;              /* Transmit Threshold Mode for each media    */
+    u_int mci;              /* 21142 MII Connector Interrupt info        */
 };
 
 #define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
@@ -444,7 +474,8 @@ static c_char srom_repair_info[][100] = {
 #ifdef DE4X5_DEBUG
 static int de4x5_debug = DE4X5_DEBUG;
 #else
-static int de4x5_debug = (0);
+/*static int de4x5_debug = (DEBUG_MII | DEBUG_SROM | DEBUG_PCICFG | DEBUG_MEDIA | DEBUG_VERSION);*/
+static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
 #endif
 
 #ifdef DE4X5_AUTOSENSE              /* Should be done on a per adapter basis */
@@ -503,6 +534,7 @@ static s32 de4x5_full_duplex = 0;
 #define PCI_MAX_BUS_NUM      8
 #define DE4X5_PCI_TOTAL_SIZE 0x80       /* I/O address extent */
 #define DE4X5_CLASS_CODE     0x00020000 /* Network controller, Ethernet */
+#define NO_MORE_PCI          -2         /* PCI bus search all done */
 
 /*
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
@@ -785,11 +817,13 @@ static void    load_packet(struct device *dev, char *buf, u32 flags, struct sk_b
 static int     dc21040_autoconf(struct device *dev);
 static int     dc21041_autoconf(struct device *dev);
 static int     dc21140m_autoconf(struct device *dev);
+static int     dc2114x_autoconf(struct device *dev);
 static int     srom_autoconf(struct device *dev);
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-static int     test_sym_link(struct device *dev, int msec);
+static int     test_for_100Mb(struct device *dev, int msec);
+static int     wait_for_link(struct device *dev);
 static int     test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
 static int     is_spd_100(struct device *dev);
 static int     is_100_up(struct device *dev);
@@ -823,7 +857,7 @@ static short   srom_data(u_int command, u_long address);
 /*static void    srom_busy(u_int command, u_long address);*/
 static void    sendto_srom(u_int command, u_long addr);
 static int     getfrom_srom(u_long addr);
-static void    srom_map_media(struct device *dev);
+static int     srom_map_media(struct device *dev);
 static int     srom_infoleaf_info(struct device *dev);
 static void    srom_init(struct device *dev);
 static void    srom_exec(struct device *dev, u_char *p);
@@ -845,16 +879,15 @@ static int     test_bad_enet(struct device *dev, int status);
 
 static void    eisa_probe(struct device *dev, u_long iobase);
 static void    pci_probe(struct device *dev, u_long iobase);
-static struct  device *alloc_device(struct device *dev, u_long iobase);
-static struct  device *insert_device(struct device *dev, u_long iobase,
-                                    int (*init)(struct device *));
+static void    srom_search(int index);
 static char    *build_setup_frame(struct device *dev, int mode);
 static void    disable_ast(struct device *dev);
 static void    enable_ast(struct device *dev, u32 time_out);
 static long    de4x5_switch_mac_port(struct device *dev);
+static int     gep_rd(struct device *dev);
+static void    gep_wr(s32 data, struct device *dev);
 static void    timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
 static void    yawn(struct device *dev, int state);
-static int     de4x5_dev_index(char *s);
 static void    link_modules(struct device *dev, struct device *tmp);
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
@@ -878,15 +911,25 @@ static int     compact_infoblock(struct device *dev, u_char count, u_char *p);
 int  init_module(void);
 void cleanup_module(void);
 static struct  device *unlink_modules(struct device *p);
-static int autoprobed = 0, loading_module = 1;
+static struct  device *insert_device(struct device *dev, u_long iobase,
+                                    int (*init)(struct device *));
+static int count_adapters(void);
+static int loading_module = 1;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+MODULE_PARM(de4x5_debug, "i");
+MODULE_PARM(de4x5_full_duplex, "i");
+MODULE_PARM(dec_only, "i");
+#endif /* LINUX_VERSION_CODE */
 # else
-static int autoprobed = 0, loading_module = 0;
+static int loading_module = 0;
 #endif /* MODULE */
 
 static char name[DE4X5_NAME_LENGTH + 1];
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
-static int num_de4x5s = 0, num_eth = 0;
+static int num_de4x5s = 0;
 static int cfrv = 0, useSROM = 0;
+static int lastEISA = 0, lastPCI = -1;
+static struct device *lastModule = NULL;
 
 /*
 ** List the SROM infoleaf functions and chipsets
@@ -943,28 +986,17 @@ static int (*dc_infoblock[])(struct device *dev, u_char, u_char *) = {
 \f
 /*
 ** Autoprobing in modules is allowed here. See the top of the file for
-** more info. Until I fix (un)register_netdevice() we won't be able to use it
-** though.
+** more info.
 */
 __initfunc(int
 de4x5_probe(struct device *dev))
 {
-    int status = -ENODEV;
     u_long iobase = dev->base_addr;
 
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
     
-    /*
-    ** Walk the device list to check that at least one device
-    ** initialised OK
-    */
-    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
-    
-    if (dev->priv) status = 0;
-    if (iobase == 0) autoprobed = 1;
-
-    return status;
+    return (dev->priv ? 0 : -ENODEV);
 }
 
 __initfunc(static int
@@ -1140,7 +1172,6 @@ de4x5_hw_init(struct device *dev, u_long iobase))
        /* Initialise the SROM pointers if possible */
        if (lp->useSROM) {
            lp->state = INITIALISED;
-           de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
            if (srom_infoleaf_info(dev)) {
                return -ENXIO;
            }
@@ -1191,7 +1222,7 @@ de4x5_open(struct device *dev)
     u_long iobase = dev->base_addr;
     int i, status = 0;
     s32 omr;
-    
+
     /* Allocate the RX buffers */
     for (i=0; i<lp->rxRingSize; i++) {
        if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
@@ -1230,6 +1261,7 @@ de4x5_open(struct device *dev)
            printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
        }
     }
+
     dev->tbusy = 0;                         
     dev->start = 1;
     dev->interrupt = UNMASK_INTERRUPTS;
@@ -1267,7 +1299,7 @@ static int
 de4x5_init(struct device *dev)
 {  
     /* Lock out other processes whilst setting up the hardware */
-    set_bit(0, (void *)&dev->tbusy);
+    test_and_set_bit(0, (void *)&dev->tbusy);
     
     de4x5_sw_reset(dev);
     
@@ -1301,8 +1333,9 @@ de4x5_sw_reset(struct device *dev)
     ** without these values. Cache align 16 long.
     */
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
+    bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
     outl(bmr, DE4X5_BMR);
-    
+
     omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
     if (lp->chipset == DC21140) {
        omr |= (OMR_SDP | OMR_SB);
@@ -1323,13 +1356,13 @@ de4x5_sw_reset(struct device *dev)
     }
     
     barrier();
-    
+
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
     
     load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
-    
+
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
     sti();                                       /* Ensure timer interrupts */
     for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
@@ -1337,7 +1370,7 @@ de4x5_sw_reset(struct device *dev)
        if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
     }
     outl(omr, DE4X5_OMR);                        /* Stop everything! */
-    
+
     if (j == 0) {
        printk("%s: Setup frame timed out, status %08x\n", dev->name, 
               inl(DE4X5_STS));
@@ -1346,7 +1379,7 @@ de4x5_sw_reset(struct device *dev)
     
     lp->tx_new = (++lp->tx_new) % lp->txRingSize;
     lp->tx_old = lp->tx_new;
-    
+
     return status;
 }
 
@@ -1365,7 +1398,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
        return 0;
     }
 
-    set_bit(0, (void*)&dev->tbusy);              /* Stop send re-tries */
+    test_and_set_bit(0, (void*)&dev->tbusy);     /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
        return -1;                                
     }
@@ -1380,7 +1413,8 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
     sti();
 
     /* Test if cache is already locked - requeue skb if so */
-    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) 
+       return -1;
 
     /* Transmit descriptor ring full or stale skb */
     if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
@@ -1401,7 +1435,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
 
        while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
            cli();
-           set_bit(0, (void*)&dev->tbusy);
+           test_and_set_bit(0, (void*)&dev->tbusy);
            load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
 #if    LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8))
            lp->stats.tx_bytes += skb->len;
@@ -1897,15 +1931,15 @@ __initfunc(static void
 eisa_probe(struct device *dev, u_long ioaddr))
 {
     int i, maxSlots, status, device;
+    u_char irq;
     u_short vendor;
     u32 cfid;
     u_long iobase;
     struct bus_type *lp = &bus;
     char name[DE4X5_STRLEN];
-    struct device *tmp;
-    
-    if (autoprobed) return;                /* Been here before ! */
     
+    if (lastEISA == MAX_EISA_SLOTS) return; /* No more EISA devices to search */
+
     lp->bus = EISA;
     
     if (ioaddr == 0) {                     /* Autoprobing */
@@ -1918,7 +1952,7 @@ eisa_probe(struct device *dev, u_long ioaddr))
        maxSlots = i + 1;
     }
     
-    for (status= -ENODEV;(i<maxSlots)&&(dev!=NULL);i++,iobase+=EISA_SLOT_INC) {
+    for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
        if (EISA_signature(name, EISA_ID)) {
            cfid = (u32) inl(PCI_CFID);
            cfrv = (u_short) inl(PCI_CFRV);
@@ -1926,32 +1960,34 @@ eisa_probe(struct device *dev, u_long ioaddr))
            vendor = (u_short) cfid;
            
            /* Read the EISA Configuration Registers */
-           dev->irq = inb(EISA_REG0);
-           dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03];
+           irq = inb(EISA_REG0);
+           irq = de4x5_irq[(irq >> 1) & 0x03];
 
-           if (is_DC2114x) device |= (cfrv & 0x00f0);
+           if (is_DC2114x) device |= (cfrv & CFRV_RN);
            lp->chipset = device;
-           DevicePresent(DE4X5_APROM);
+
            /* Write the PCI Configuration Registers */
            outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
            outl(0x00006000, PCI_CFLT);
            outl(iobase, PCI_CBIO);
            
+           DevicePresent(DE4X5_APROM);
            if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-               if ((tmp = alloc_device(dev, iobase)) != NULL) {
-                   if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
-                       num_de4x5s++;
-                       if (loading_module) link_modules(dev, tmp);
-                   } else if (loading_module && (tmp != dev)) {
-                       kfree(tmp);
-                   }
+               dev->irq = irq;
+               if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+                   num_de4x5s++;
+                   if (loading_module) link_modules(lastModule, dev);
+                   lastEISA = i;
+                   return;
                }
-           } else if (autoprobed) {
+           } else if (ioaddr != 0) {
                printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
            }
        }
     }
-    
+
+    if (ioaddr == 0) lastEISA = i;
+
     return;
 }
 
@@ -1973,20 +2009,23 @@ eisa_probe(struct device *dev, u_long ioaddr))
 __initfunc(static void
 pci_probe(struct device *dev, u_long ioaddr))
 {
-    u_char irq;
+    u_char irq, timer;
     u_char pb, pbus, dev_num, dnum, dev_fn;
     u_short dev_id, vendor, index, status;
     u_int class = DE4X5_CLASS_CODE;
     u_int device, iobase;
     struct bus_type *lp = &bus;
-    struct device *tmp;
 
-    if (autoprobed) return;
-    
-    if (!pcibios_present()) return;          /* No PCI bus in this machine! */
+    if (lastPCI == NO_MORE_PCI) return;
+
+    if (!pcibios_present()) {
+       lastPCI = NO_MORE_PCI;
+       return;          /* No PCI bus in this machine! */
+    }
     
     lp->bus = PCI;
-    
+    lp->bus_num = 0;
+
     if ((ioaddr < 0x1000) && loading_module) {
        pbus = (u_short)(ioaddr >> 8);
        dnum = (u_short)(ioaddr & 0xff);
@@ -1995,7 +2034,7 @@ pci_probe(struct device *dev, u_long ioaddr))
        dnum = 0;
     }
 
-    for (index=0
+    for (index=lastPCI+1
         (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
         index++) {
        dev_num = PCI_SLOT(dev_fn);
@@ -2010,6 +2049,12 @@ pci_probe(struct device *dev, u_long ioaddr))
                continue;
            }
 
+           /* Search for an SROM on this bus */
+           if (lp->bus_num != pb) {
+               lp->bus_num = pb;
+               srom_search(index);
+           }
+
            /* Get the chip configuration revision register */
            pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
 
@@ -2018,14 +2063,9 @@ pci_probe(struct device *dev, u_long ioaddr))
            lp->bus_num = pb;
            
            /* Set the chipset information */
-           if (is_DC2114x) device |= (cfrv & 0x00f0);
+           if (is_DC2114x) device |= (cfrv & CFRV_RN);
            lp->chipset = device;
 
-           if (is_DC21142 || is_DC21143) {
-               printk("de4x5: Detected a %s chip. Currently this is unsupported in this driver.\nPlease email the author to request its inclusion!\n", (is_DC21142?"DC21142":"DC21143"));
-               continue;
-           }
-
            /* Get the board I/O address */
            pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
            iobase &= CBIO_MASK;
@@ -2044,127 +2084,106 @@ pci_probe(struct device *dev, u_long ioaddr))
            }
            if (!(status & PCI_COMMAND_MASTER)) continue;
 
+           /* Check the latency timer for values > 0x60 */
+           pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer);
+           if (timer < 0x60) {
+               pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60);
+           }
+
            DevicePresent(DE4X5_APROM);
            if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-               if ((tmp = alloc_device(dev, iobase)) != NULL) {
-                   tmp->irq = irq;
-                   if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
-                       num_de4x5s++;
-                       if (loading_module) link_modules(dev, tmp);
-                   } else if (loading_module && (tmp != dev)) {
-                       kfree(tmp);
+               dev->irq = irq;
+               if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+                   num_de4x5s++;
+                   if (loading_module) {
+                       link_modules(lastModule, dev);
+                       lastPCI = index;
                    }
+                   return;
                }
-           } else if (autoprobed) {
+           } else if (ioaddr != 0) {
                printk("%s: region already allocated at 0x%04x.\n", dev->name, 
                       (u_short)iobase);
            }
        }
     }
-    
+
+    if (loading_module) lastPCI = NO_MORE_PCI;
+
     return;
 }
 
 /*
-** Search the entire 'eth' device list for a fixed probe. If a match isn't
-** found then check for an autoprobe or unused device location. If they
-** are not available then insert a new device structure at the end of
-** the current list.
+** This function searches the current bus (which is >0) for a DECchip with an
+** SROM, so that in multiport cards that have one SROM shared between multiple 
+** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
+** For single port cards this is a time waster...
 */
-__initfunc(static struct device *
-alloc_device(struct device *dev, u_long iobase))
+__initfunc(static void
+srom_search(int index))
 {
-    struct device *adev = NULL;
-    int fixed = 0, new_dev = 0;
+    u_char irq, pb, dev_fn;
+    u_short dev_id, dev_num, vendor, status;
+    u_int class = DE4X5_CLASS_CODE;
+    u_int device, iobase;
+    int i, j;
+    struct bus_type *lp = &bus;
 
-    if (!dev) return dev;
-    num_eth = de4x5_dev_index(dev->name);
+    for (; 
+        (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+        index++) {
 
-    if (loading_module) {
-       if (dev->priv) {
-           dev = insert_device(dev, iobase, de4x5_probe);
+       if (lp->bus_num != pb) return;
+       dev_num = PCI_SLOT(dev_fn);
+       device = 0;
+       pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+       pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+       device = dev_id;
+       device <<= 8;
+       if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) {
+           continue;
        }
-       num_eth++;
-       return dev;
-    }
 
-    while (1) {
-       if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) {
-           adev=dev;
-       } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
-           fixed = 1;
-       } else {
-           if (dev->next == NULL) {
-               new_dev = 1;
-           } else if (strncmp(dev->next->name, "eth", 3) != 0) {
-               new_dev = 1;
-           }
-       }
-       if ((dev->next == NULL) || new_dev || fixed) break;
-       dev = dev->next;
-       num_eth++;
-    }
-    if (adev && !fixed) {
-       dev = adev;
-       num_eth = de4x5_dev_index(dev->name);
-       new_dev = 0;
-    }
+       /* Get the chip configuration revision register */
+       pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv);
 
-    if (((dev->next == NULL) &&  
-       ((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) ||
-       new_dev) {
-       num_eth++;                         /* New device */
-       dev = insert_device(dev, iobase, de4x5_probe);
-    }
-    
-    return dev;
-}
+       /* Set the device number information */
+       lp->device = dev_num;
+       lp->bus_num = pb;
+           
+       /* Set the chipset information */
+       if (is_DC2114x) device |= (cfrv & CFRV_RN);
+       lp->chipset = device;
 
-/*
-** If at end of eth device list and can't use current entry, malloc
-** one up. If memory could not be allocated, print an error message.
-*/
-__initfunc(static struct device *
-insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
-{
-    struct device *new;
+       /* Get the board I/O address */
+       pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
+       iobase &= CBIO_MASK;
 
-    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
-    if (new == NULL) {
-       printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
-       return NULL;
-    } else {
-       memset((char *)new, 0, sizeof(struct device)+8);
-       new->name = (char *)(new + 1);
-       new->base_addr = iobase;       /* assign the io address */
-       new->init = init;              /* initialisation routine */
-       if (!loading_module) {
-           new->next = dev->next;
-           dev->next = new;
-           if (num_eth > 9999) {
-               sprintf(new->name,"eth????");/* New device name */
-           } else {
-               sprintf(new->name,"eth%d", num_eth);/* New device name */
+       /* Fetch the IRQ to be used */
+       pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
+       if ((irq == 0) || (irq == (u_char) 0xff)) continue;
+           
+       /* Check if I/O accesses are enabled */
+       pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+       if (!(status & PCI_COMMAND_IO)) continue;
+
+       /* Search for a valid SROM attached to this DECchip */
+       DevicePresent(DE4X5_APROM);
+       for (j=0, i=0; i<ETH_ALEN; i++) {
+           j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
+       }
+       if ((j != 0) && (j != 0x5fa)) {
+           last.chipset = device;
+           last.bus = pb;
+           last.irq = irq;
+           for (i=0; i<ETH_ALEN; i++) {
+               last.addr[i] = (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
            }
+           return;
        }
     }
 
-    return new;
-}
-
-__initfunc(static int
-de4x5_dev_index(char *s))
-{
-    int i=0, j=0;
-
-    for (;*s; s++) {
-       if (isdigit(*s)) {
-           j=1;
-           i = (i * 10) + (*s - '0');
-       } else if (j) break;
-    }
-
-    return i;
+    return;
 }
 
 __initfunc(static void
@@ -2199,13 +2218,15 @@ autoconf_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int next_tick = DE4X5_AUTOSENSE_MS;;
-    
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
     lp->linkOK = 0;
     lp->c_media = AUTO;                     /* Bogus last media */
     disable_ast(dev);
     inl(DE4X5_MFC);                         /* Zero the lost frames counter */
     lp->media = INIT;
+    lp->tcount = 0;
+
     if (lp->useSROM) {
        next_tick = srom_autoconf(dev);
     } else if (lp->chipset == DC21040) {
@@ -2609,7 +2630,10 @@ dc21140m_autoconf(struct device *dev)
            next_tick &= ~TIMER_CB;
        } else {
            if (lp->useSROM) {
-               srom_map_media(dev);
+               if (srom_map_media(dev) < 0) {
+                   lp->tcount++;
+                   return next_tick;
+               }
                srom_exec(dev, lp->phy[lp->active].gep);
                if (lp->infoblock_media == ANS) {
                    ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
@@ -2691,11 +2715,11 @@ dc21140m_autoconf(struct device *dev)
        
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
         if (lp->timeout < 0) {
-           lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
-                                                 (~inl(DE4X5_GEP) & GEP_LNP));
+           lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : 
+                                                 (~gep_rd(dev) & GEP_LNP));
            SET_100Mb_PDET;
        }
-        if ((slnk = test_sym_link(dev, 6200)) < 0) {
+        if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
            next_tick = slnk & ~TIMER_CB;
        } else {
            if (is_spd_100(dev) && is_100_up(dev)) {
@@ -2716,7 +2740,7 @@ dc21140m_autoconf(struct device *dev)
            de4x5_init_connection(dev);
        } else {
            if (!lp->linkOK && (lp->autosense == AUTO)) {
-               if (!(is_spd_100(dev) && is_100_up(dev))) {
+               if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
                    lp->media = INIT;
                    lp->tcount++;
                    next_tick = DE4X5_AUTOSENSE_MS;
@@ -2732,7 +2756,7 @@ dc21140m_autoconf(struct device *dev)
            de4x5_init_connection(dev);
        } else {
            if (!lp->linkOK && (lp->autosense == AUTO)) {
-               if (!(!is_spd_100(dev) && is_10_up(dev))) {
+               if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
                    lp->media = INIT;
                    lp->tcount++;
                    next_tick = DE4X5_AUTOSENSE_MS;
@@ -2754,133 +2778,380 @@ dc21140m_autoconf(struct device *dev)
     return next_tick;
 }
 
-static int
-srom_autoconf(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
-    return lp->infoleaf_fn(dev);
-}
-
 /*
-** This mapping keeps the original media codes and FDX flag unchanged.
-** While it isn't strictly necessary, it helps me for the moment...
+** This routine may be merged into dc21140m_autoconf() sometime as I'm
+** changing how I figure out the media - but trying to keep it backwards
+** compatible with the de500-xa and de500-aa.
+** Whether it's BNC, AUI, SYM or MII is sorted out in the infoblock
+** functions and set during de4x5_mac_port() and/or de4x5_reset_phy().
+** This routine just has to figure out whether 10Mb/s or 100Mb/s is
+** active.
+** When autonegotiation is working, the ANS part searches the SROM for
+** the highest common speed (TP) link that both can run and if that can
+** be full duplex. That infoblock is executed and then the link speed set.
+**
+** Only _10Mb and _100Mb are tested here.
 */
-static void
-srom_map_media(struct device *dev)
+static int
+dc2114x_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
+    int next_tick = DE4X5_AUTOSENSE_MS;
 
-    lp->fdx = 0;
-    switch(lp->infoblock_media) {
-      case SROM_10BASETF:
-       lp->fdx = TRUE;
-      case SROM_10BASET:
-       if (lp->chipset == DC21140) {
-           lp->media = _10Mb;
-       } else {
-           lp->media = TP;
+    switch (lp->media) {
+      case INIT:
+        if (lp->timeout < 0) {
+           DISABLE_IRQs;
+           lp->tx_enable = FALSE;
+           lp->linkOK = 0;
+            lp->timeout = -1;
+           de4x5_save_skbs(dev);          /* Save non transmitted skb's */
        }
+       if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+           next_tick &= ~TIMER_CB;
+       } else {
+            lp->media = SPD_DET;
+           if ((lp->infoblock_media == ANS) && 
+                                   ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+                   ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+                   ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+                   mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+                   lp->media = ANS;
+           }
+           lp->local_state = 0;
+           next_tick = dc2114x_autoconf(dev);
+        }
        break;
-
-      case SROM_10BASE2:
-       lp->media = BNC;
-       break;
-
-      case SROM_10BASE5:
-       lp->media = AUI;
-       break;
-
-      case SROM_100BASETF:
-       lp->fdx = TRUE;
-      case SROM_100BASET:
-       lp->media = _100Mb;
-       break;
-
-      case SROM_100BASET4:
-       lp->media = _100Mb;
-       break;
-
-      case SROM_100BASEFF:
-       lp->fdx = TRUE;
-      case SROM_100BASEF: 
-       lp->media = _100Mb;
-       break;
-
+       
       case ANS:
-       lp->media = ANS;
-       break;
-
-      default: 
-       printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
-                                                         lp->infoblock_media);
-       break;
-    }
-
-    return;
-}
-
-static void
-de4x5_init_connection(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    if (lp->media != lp->c_media) {
-        de4x5_dbg_media(dev);
-       lp->c_media = lp->media;          /* Stop scrolling media messages */
-    }
-
-    cli();
-    de4x5_restore_skbs(dev);
-    de4x5_setup_intr(dev);
-    lp->tx_enable = YES;
-    dev->tbusy = 0;
-    sti();
-    outl(POLL_DEMAND, DE4X5_TPD);
-    mark_bh(NET_BH);
-
-    return;
-}
-
-/*
-** General PHY reset function. Some MII devices don't reset correctly
-** since their MII address pins can float at voltages that are dependent
-** on the signal pin use. Do a double reset to ensure a reset.
-*/
-static int
-de4x5_reset_phy(struct device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int next_tick = 0;
-
-    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
-       if (lp->timeout < 0) {
-           if (lp->useSROM) {
-               if (lp->phy[lp->active].rst) { /* MII device specific reset */
-                   srom_exec(dev, lp->phy[lp->active].rst);
-                   srom_exec(dev, lp->phy[lp->active].rst);
-               } else if (lp->rst) {          /* Type 5 infoblock reset */
-                   srom_exec(dev, lp->rst);
-                   srom_exec(dev, lp->rst);
-               }
+       switch (lp->local_state) {
+         case 0:
+           if (lp->timeout < 0) {
+               mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+           }
+           cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+           if (cr < 0) {
+               next_tick = cr & ~TIMER_CB;
            } else {
-               PHY_HARD_RESET;
+               if (cr) {
+                   lp->local_state = 0;
+                   lp->media = SPD_DET;
+               } else {
+                   lp->local_state++;
+               }
+               next_tick = dc2114x_autoconf(dev);
            }
-           if (lp->useMII) {
-               mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
-            }
-        }
-       if (lp->useMII) {
-           next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
-       }
-    } else if (lp->chipset == DC21140) {
-       PHY_HARD_RESET;
-    }
-
-    return next_tick;
-}
+           break;
+           
+         case 1:
+           if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+               next_tick = sr & ~TIMER_CB;
+           } else {
+               lp->media = SPD_DET;
+               lp->local_state = 0;
+               if (sr) {                         /* Success! */
+                   lp->tmp = MII_SR_ASSC;
+                   anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+                   ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+                   if (!(anlpa & MII_ANLPA_RF) && 
+                        (cap = anlpa & MII_ANLPA_TAF & ana)) {
+                       if (cap & MII_ANA_100M) {
+                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+                           lp->media = _100Mb;
+                       } else if (cap & MII_ANA_10M) {
+                           lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+                           lp->media = _10Mb;
+                       }
+                   }
+               }                       /* Auto Negotiation failed to finish */
+               next_tick = dc2114x_autoconf(dev);
+           }                           /* Auto Negotiation failed to start */
+           break;
+       }
+       break;
+       
+      case AUI:
+       if (!lp->tx_enable) {
+           if (lp->timeout < 0) {
+               omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
+               outl(omr & ~OMR_FDX, DE4X5_OMR);
+           }
+           irqs = 0;
+           irq_mask = 0;
+           sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+           if (sts < 0) {
+               next_tick = sts & ~TIMER_CB;
+           } else {
+               if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+                   lp->media = BNC;
+                   next_tick = dc2114x_autoconf(dev);
+               } else {
+                   lp->local_state = 1;
+                   de4x5_init_connection(dev);
+               }
+           }
+       } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+           lp->media = AUI_SUSPECT;
+           next_tick = 3000;
+       }
+       break;
+       
+      case AUI_SUSPECT:
+       next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
+       break;
+       
+      case BNC:
+       switch (lp->local_state) {
+         case 0:
+           if (lp->timeout < 0) {
+               omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
+               outl(omr & ~OMR_FDX, DE4X5_OMR);
+           }
+           irqs = 0;
+           irq_mask = 0;
+           sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+           if (sts < 0) {
+               next_tick = sts & ~TIMER_CB;
+           } else {
+               lp->local_state++;             /* Ensure media connected */
+               next_tick = dc2114x_autoconf(dev);
+           }
+           break;
+           
+         case 1:
+           if (!lp->tx_enable) {
+               if ((sts = ping_media(dev, 3000)) < 0) {
+                   next_tick = sts & ~TIMER_CB;
+               } else {
+                   if (sts) {
+                       lp->local_state = 0;
+                       lp->tcount++;
+                       lp->media = INIT;
+                   } else {
+                       de4x5_init_connection(dev);
+                   }
+               }
+           } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+               lp->media = BNC_SUSPECT;
+               next_tick = 3000;
+           }
+           break;
+       }
+       break;
+       
+      case BNC_SUSPECT:
+       next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
+       break;
+       
+      case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+         if (srom_map_media(dev) < 0) {
+             lp->tcount++;
+             lp->media = INIT;
+             return next_tick;
+         }
+         if (lp->media == _100Mb) {
+             if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+                 lp->media = SPD_DET;
+                 return  (slnk & ~TIMER_CB);
+             }
+         } else {
+             if (wait_for_link(dev) < 0) {
+                 lp->media = SPD_DET;
+                 return PDET_LINK_WAIT;
+             }
+         } 
+         if (((lp->media == _100Mb) && is_100_up(dev)) ||
+             ((lp->media == _10Mb)  && is_10_up(dev)) ||
+              (lp->media == BNC) || (lp->media == AUI)) {
+             next_tick = dc2114x_autoconf(dev);
+         } else {
+             lp->tcount++;
+             lp->media = INIT;
+         }
+         break;
+       
+      case _10Mb:
+        next_tick = 3000;
+       if (!lp->tx_enable) {
+           SET_10Mb;
+           de4x5_init_connection(dev);
+       } else {
+           if (!lp->linkOK && (lp->autosense == AUTO)) {
+               if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+                   lp->media = INIT;
+                   lp->tcount++;
+                   next_tick = DE4X5_AUTOSENSE_MS;
+               }
+           }
+       }
+       break;
+
+      case _100Mb:
+        next_tick = 3000;
+       if (!lp->tx_enable) {
+           SET_100Mb;
+           de4x5_init_connection(dev);
+       } else {
+           if (!lp->linkOK && (lp->autosense == AUTO)) {
+               if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+                   lp->media = INIT;
+                   lp->tcount++;
+                   next_tick = DE4X5_AUTOSENSE_MS;
+               }
+           }
+       }
+       break;
+
+      default:
+       lp->tcount++;
+printk("Huh?: media:%02x\n", lp->media);
+       lp->media = INIT;
+       break;
+    }
+    
+    return next_tick;
+}
+
+static int
+srom_autoconf(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    return lp->infoleaf_fn(dev);
+}
+
+/*
+** This mapping keeps the original media codes and FDX flag unchanged.
+** While it isn't strictly necessary, it helps me for the moment...
+** The early return avoids a media state / SROM media space clash.
+*/
+static int
+srom_map_media(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    lp->fdx = 0;
+    if (lp->infoblock_media == lp->media) 
+      return 0;
+
+    switch(lp->infoblock_media) {
+      case SROM_10BASETF:
+       if (!de4x5_full_duplex) return -1;
+       lp->fdx = TRUE;
+      case SROM_10BASET:
+       if (de4x5_full_duplex && !lp->fdx) return -1;
+       if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
+           lp->media = _10Mb;
+       } else {
+           lp->media = TP;
+       }
+       break;
+
+      case SROM_10BASE2:
+       lp->media = BNC;
+       break;
+
+      case SROM_10BASE5:
+       lp->media = AUI;
+       break;
+
+      case SROM_100BASETF:
+        if (!de4x5_full_duplex) return -1;
+       lp->fdx = TRUE;
+      case SROM_100BASET:
+       if (de4x5_full_duplex && !lp->fdx) return -1;
+       lp->media = _100Mb;
+       break;
+
+      case SROM_100BASET4:
+       lp->media = _100Mb;
+       break;
+
+      case SROM_100BASEFF:
+       if (!de4x5_full_duplex) return -1;
+       lp->fdx = TRUE;
+      case SROM_100BASEF: 
+       if (de4x5_full_duplex && !lp->fdx) return -1;
+       lp->media = _100Mb;
+       break;
+
+      case ANS:
+       lp->media = ANS;
+       break;
+
+      default: 
+       printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
+                                                         lp->infoblock_media);
+       return -1;
+       break;
+    }
+
+    return 0;
+}
+
+static void
+de4x5_init_connection(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+       lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
+
+    cli();
+    de4x5_restore_skbs(dev);
+    de4x5_setup_intr(dev);
+    lp->tx_enable = YES;
+    dev->tbusy = 0;
+    sti();
+    outl(POLL_DEMAND, DE4X5_TPD);
+    mark_bh(NET_BH);
+
+    return;
+}
+
+/*
+** General PHY reset function. Some MII devices don't reset correctly
+** since their MII address pins can float at voltages that are dependent
+** on the signal pin use. Do a double reset to ensure a reset.
+*/
+static int
+de4x5_reset_phy(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int next_tick = 0;
+
+    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
+       if (lp->timeout < 0) {
+           if (lp->useSROM) {
+               if (lp->phy[lp->active].rst) {
+                   srom_exec(dev, lp->phy[lp->active].rst);
+                   srom_exec(dev, lp->phy[lp->active].rst);
+               } else if (lp->rst) {          /* Type 5 infoblock reset */
+                   srom_exec(dev, lp->rst);
+                   srom_exec(dev, lp->rst);
+               }
+           } else {
+               PHY_HARD_RESET;
+           }
+           if (lp->useMII) {
+               mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+            }
+        }
+       if (lp->useMII) {
+           next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+       }
+    } else if (lp->chipset == DC21140) {
+       PHY_HARD_RESET;
+    }
+
+    return next_tick;
+}
 
 static int
 test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
@@ -2891,7 +3162,9 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32
     
     if (lp->timeout < 0) {
        lp->timeout = msec/100;
-       reset_init_sia(dev, csr13, csr14, csr15);
+       if (!lp->useSROM) {      /* Already done if by SROM, else dc2104[01] */
+           reset_init_sia(dev, csr13, csr14, csr15);
+       }
 
        /* set up the interrupt mask */
        outl(irq_mask, DE4X5_IMR);
@@ -2901,7 +3174,7 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32
        outl(sts, DE4X5_STS);
        
        /* clear csr12 NRA and SRA bits */
-       if (lp->chipset == DC21041) {
+       if ((lp->chipset == DC21041) || lp->useSROM) {
            csr12 = inl(DE4X5_SISR);
            outl(csr12, DE4X5_SISR);
        }
@@ -2940,24 +3213,37 @@ test_tp(struct device *dev, s32 msec)
     return sisr;
 }
 
+/*
+** Samples the 100Mb Link State Signal. The sample interval is important
+** because too fast a rate can give erroneous results and confuse the
+** speed sense algorithm.
+*/
+#define SAMPLE_INTERVAL 500  /* ms */
+#define SAMPLE_DELAY    2000 /* ms */
 static int
-test_sym_link(struct device *dev, int msec)
+test_for_100Mb(struct device *dev, int msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int iobase = dev->base_addr;
-    int gep = 0;
-    
+    int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
+
     if (lp->timeout < 0) {
-       lp->timeout = msec/100;
+       if ((msec/SAMPLE_INTERVAL) <= 0) return 0;
+       if (msec > SAMPLE_DELAY) {
+           lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
+           gep = SAMPLE_DELAY | TIMER_CB;
+           return gep;
+       } else {
+           lp->timeout = msec/SAMPLE_INTERVAL;
+       }
     }
     
     if (lp->phy[lp->active].id || lp->useSROM) {
-       gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
+       gep = is_100_up(dev) | is_spd_100(dev);
     } else {
-       gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
+       gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
     }
-    if (!(gep & GEP_SLNK) && --lp->timeout) {
-       gep = 100 | TIMER_CB;
+    if (!(gep & ret) && --lp->timeout) {
+       gep = SAMPLE_INTERVAL | TIMER_CB;
     } else {
        lp->timeout = -1;
     }
@@ -2965,6 +3251,24 @@ test_sym_link(struct device *dev, int msec)
     return gep;
 }
 
+static int
+wait_for_link(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    if (lp->timeout < 0) {
+       lp->timeout = 1;
+    }
+    
+    if (lp->timeout--) {
+       return TIMER_CB;
+    } else {
+       lp->timeout = -1;
+    }
+    
+    return 0;
+}
+
 /*
 **
 **
@@ -2999,16 +3303,18 @@ is_spd_100(struct device *dev)
     u_long iobase = dev->base_addr;
     int spd;
     
-    if (lp->useSROM && !lp->useMII) {
-       spd = (lp->asBitValid & 
-              (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
-                (lp->linkOK & ~lp->asBitValid);
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
        spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
        spd = ~(spd ^ lp->phy[lp->active].spd.value);
        spd &= lp->phy[lp->active].spd.mask;
+    } else if (!lp->useSROM) {                      /* de500-xa */
+       spd = ((~gep_rd(dev)) & GEP_SLNK);
     } else {
-       spd = ((~inl(DE4X5_GEP)) & GEP_SLNK);
+       if ((lp->ibn == 2) || !lp->asBitValid)
+           return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+       spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
+                 (lp->linkOK & ~lp->asBitValid);
     }
     
     return spd;
@@ -3020,16 +3326,18 @@ is_100_up(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
-    if (lp->useSROM && !lp->useMII) {
-       return ((lp->asBitValid & 
-                (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
-               (lp->linkOK & ~lp->asBitValid));
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
        /* Double read for sticky bits & temporary drops */
        mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+       return ((~gep_rd(dev)) & GEP_SLNK);
     } else {
-       return ((~inl(DE4X5_GEP)) & GEP_SLNK);
+       if ((lp->ibn == 2) || !lp->asBitValid)
+           return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+        return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+               (lp->linkOK & ~lp->asBitValid));
     }
 }
 
@@ -3039,16 +3347,20 @@ is_10_up(struct device *dev)
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
-    if (lp->useSROM && !lp->useMII) {
-       return ((lp->asBitValid & 
-                (lp->asPolarity ^ (inl(DE4X5_GEP) & lp->asBit))) |
-               (lp->linkOK & ~lp->asBitValid));
-    } else if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+    if (lp->useMII) {
        /* Double read for sticky bits & temporary drops */
        mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+       return ((~gep_rd(dev)) & GEP_LNP);
     } else {
-       return ((~inl(DE4X5_GEP)) & GEP_LNP);
+       if ((lp->ibn == 2) || !lp->asBitValid)
+           return (((lp->chipset & ~0x00ff) == DC2114x) ?
+                   (~inl(DE4X5_SISR)&SISR_LS10):
+                   0);
+
+       return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+               (lp->linkOK & ~lp->asBitValid));
     }
 }
 
@@ -3060,6 +3372,8 @@ is_anc_capable(struct device *dev)
     
     if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
        return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+       return (inl(DE4X5_SISR) & SISR_LPN) >> 11;
     } else {
        return 0;
     }
@@ -3271,11 +3585,6 @@ de4x5_cache_state(struct device *dev, int flag)
        lp->cache.csr0 = inl(DE4X5_BMR);
        lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
        lp->cache.csr7 = inl(DE4X5_IMR);
-       if (lp->chipset != DC21140) {
-           lp->cache.csr13 = inl(DE4X5_SICR);
-           lp->cache.csr14 = inl(DE4X5_STRR);
-           lp->cache.csr15 = inl(DE4X5_SIGR);
-       }
        break;
 
       case DE4X5_RESTORE_STATE:
@@ -3283,8 +3592,8 @@ de4x5_cache_state(struct device *dev, int flag)
        outl(lp->cache.csr6, DE4X5_OMR);
        outl(lp->cache.csr7, DE4X5_IMR);
        if (lp->chipset == DC21140) {
-           outl(lp->cache.gepc, DE4X5_GEP);
-           outl(lp->cache.gep, DE4X5_GEP);
+           gep_wr(lp->cache.gepc, dev);
+           gep_wr(lp->cache.gep, dev);
        } else {
            reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
                                                              lp->cache.csr15);
@@ -3392,15 +3701,32 @@ de4x5_setup_intr(struct device *dev)
 **
 */
 static void
-reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
+reset_init_sia(struct device *dev, s32 csr13, s32 csr14, s32 csr15)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    
+
     RESET_SIA;
-    outl(sigr, DE4X5_SIGR);
-    outl(strr, DE4X5_STRR);
-    outl(sicr, DE4X5_SICR);
+    if (lp->useSROM) {
+       if (lp->ibn == 3) {
+           srom_exec(dev, lp->phy[lp->active].rst);
+           srom_exec(dev, lp->phy[lp->active].gep);
+           outl(1, DE4X5_SICR);
+           return;
+       } else {
+           csr15 = lp->cache.csr15;
+           csr14 = lp->cache.csr14;
+           csr13 = lp->cache.csr13;
+           outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
+           outl(csr15 | lp->cache.gep, DE4X5_SIGR);
+       }
+    } else {
+       outl(csr15, DE4X5_SIGR);
+    }
+    outl(csr14, DE4X5_STRR);
+    outl(csr13, DE4X5_SICR);
+
+    de4x5_ms_delay(10);
 
     return;
 }
@@ -3523,7 +3849,10 @@ PCI_signature(char *name, struct bus_type *lp)
        if (lp->chipset != DC21041) {
            useSROM = TRUE;             /* card is not recognisably DEC */
        }
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+       useSROM = TRUE;
     }
+
     
     return status;
 }
@@ -3531,17 +3860,31 @@ PCI_signature(char *name, struct bus_type *lp)
 /*
 ** Set up the Ethernet PROM counter to the start of the Ethernet address on
 ** the DC21040, else  read the SROM for the other chips.
+** The SROM may not be present in a multi-MAC card, so first read the
+** MAC address and check for a bad address. If there is a bad one then exit
+** immediately with the prior srom contents intact (the h/w address will
+** be fixed up later).
 */
 static void
 DevicePresent(u_long aprom_addr)
 {
-    int i;
+    int i, j=0;
     struct bus_type *lp = &bus;
     
     if (lp->chipset == DC21040) {
        outl(0, aprom_addr);           /* Reset Ethernet Address ROM Pointer */
     } else {                           /* Read new srom */
-       u_short tmp, *p = (short *)&lp->srom;
+       u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
+       for (i=0; i<(ETH_ALEN>>1); i++) {
+           tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
+           *p = le16_to_cpu(tmp);
+           j += *p++;
+       }
+       if ((j == 0) || (j == 0x2fffd)) {
+           return;
+       }
+
+       p=(short *)&lp->srom;
        for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
            tmp = srom_rd(aprom_addr, i);
            *p++ = le16_to_cpu(tmp);
@@ -3567,6 +3910,7 @@ get_hw_addr(struct device *dev)
     struct bus_type *lp = &bus;
 
     broken = de4x5_bad_srom(lp);
+
     for (i=0,k=0,j=0;j<3;j++) {
        k <<= 1;
        if (k > 0xffff) k-=0xffff;
@@ -3673,6 +4017,10 @@ srom_repair(struct device *dev, int card)
     return;
 }
 
+/*
+** Assume that the irq's do not follow the PCI spec - this is seems
+** to be true so far (2 for 2).
+*/
 static int
 test_bad_enet(struct device *dev, int status)
 {
@@ -3689,10 +4037,8 @@ test_bad_enet(struct device *dev, int status)
                if (dev->dev_addr[i] != 0) break;
            }
            for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
-           if (((*((int *)dev->dev_addr) & 0x00ffffff) == 0x95c000) &&
-               (lp->chipset == DC21040)) {
-               dev->irq = last.irq;
-           }
+           dev->irq = last.irq;
+
            status = 0;
        }
     } else if (!status) {
@@ -3753,9 +4099,6 @@ srom_address(u_int command, u_long addr, u_char offset)
     de4x5_us_delay(1);
     
     i = (getfrom_srom(addr) >> 3) & 0x01;
-    if (i != 0) {
-       printk("Bad SROM address phase.....\n");
-    }
     
     return;
 }
@@ -3868,14 +4211,13 @@ static void
 srom_init(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
     u_char count;
 
     p+=2;
     if (lp->chipset == DC21140) {
        lp->cache.gepc = (*p++ | GEP_CTRL);
-       outl(lp->cache.gepc, DE4X5_GEP);
+       gep_wr(lp->cache.gepc, dev);
     }
 
     /* Block count */
@@ -3888,9 +4230,13 @@ srom_init(struct device *dev)
        } else if (*(p+1) == 5) {
            type5_infoblock(dev, 1, p);
            p += ((*p & BLOCK_LEN) + 1);
+       } else if (*(p+1) == 4) {
+           p += ((*p & BLOCK_LEN) + 1);
        } else if (*(p+1) == 3) {
            type3_infoblock(dev, 1, p);
            p += ((*p & BLOCK_LEN) + 1);
+       } else if (*(p+1) == 2) {
+           p += ((*p & BLOCK_LEN) + 1);
        } else if (*(p+1) == 1) {
            type1_infoblock(dev, 1, p);
            p += ((*p & BLOCK_LEN) + 1);
@@ -3902,20 +4248,33 @@ srom_init(struct device *dev)
     return;
 }
 
+/*
+** A generic routine that writes GEP control, data and reset information
+** to the GEP register (21140) or csr15 GEP portion (2114[23]).
+*/
 static void
 srom_exec(struct device *dev, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     u_char count = (p ? *p++ : 0);
+    u_short *w = (u_short *)p;
+
+    if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
 
+    if (lp->chipset != DC21140) RESET_SIA;
     while (count--) {
-       if (lp->chipset == DC21140) {
-           outl(*p++, DE4X5_GEP);
-       }
+       gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? 
+                                                  *p++ : TWIDDLE(w++)), dev);
        udelay(2000);                       /* 2ms per action */
     }
 
+    if (lp->chipset != DC21140) {
+       outl(lp->cache.csr14, DE4X5_STRR);
+       outl(lp->cache.csr13, DE4X5_SICR);
+    }
+
     return;
 }
 
@@ -3971,15 +4330,70 @@ dc21140_infoleaf(struct device *dev)
 static int 
 dc21142_infoleaf(struct device *dev)
 {
-printk("dc21142_infoleaf()\n");
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+       next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+       next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+       lp->media = NC;
+        if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
+       lp->media = INIT;
+       lp->tcount = 0;
+       lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
 }
 
 static int 
 dc21143_infoleaf(struct device *dev)
 {
-printk("dc21143_infoleaf()\n");
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+       next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+       next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+    if (lp->tcount == count) {
+       lp->media = NC;
+        if (lp->media != lp->c_media) {
+           de4x5_dbg_media(dev);
+           lp->c_media = lp->media;
+       }
+       lp->media = INIT;
+       lp->tcount = 0;
+       lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
 }
 
 /*
@@ -3990,7 +4404,6 @@ static int
 compact_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char flags, csr6;
 
     /* Recursively figure out the info blocks */
@@ -4003,7 +4416,9 @@ compact_infoblock(struct device *dev, u_char count, u_char *p)
     }
 
     if ((lp->media == INIT) && (lp->timeout < 0)) {
-        outl(lp->cache.gepc, DE4X5_GEP);
+        lp->ibn = COMPACT;
+        lp->active = 0;
+       gep_wr(lp->cache.gepc, dev);
        lp->infoblock_media = (*p++) & COMPACT_MC;
        lp->cache.gep = *p++;
        csr6 = *p++;
@@ -4013,7 +4428,7 @@ compact_infoblock(struct device *dev, u_char count, u_char *p)
        lp->defMedium = (flags & 0x40) ? -1 : 0;
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+       lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
        lp->useMII = FALSE;
 
        de4x5_switch_mac_port(dev);
@@ -4024,12 +4439,11 @@ compact_infoblock(struct device *dev, u_char count, u_char *p)
 
 /*
 ** This block describes non MII media for the DC21140[A] only.
- */
+*/
 static int 
 type0_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
     u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
@@ -4042,7 +4456,9 @@ type0_infoblock(struct device *dev, u_char count, u_char *p)
     }
 
     if ((lp->media == INIT) && (lp->timeout < 0)) {
-        outl(lp->cache.gepc, DE4X5_GEP);
+        lp->ibn = 0;
+        lp->active = 0;
+        gep_wr(lp->cache.gepc, dev);
        p+=2;
        lp->infoblock_media = (*p++) & BLOCK0_MC;
        lp->cache.gep = *p++;
@@ -4053,7 +4469,7 @@ type0_infoblock(struct device *dev, u_char count, u_char *p)
        lp->defMedium = (flags & 0x40) ? -1 : 0;
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
+       lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
        lp->useMII = FALSE;
 
        de4x5_switch_mac_port(dev);
@@ -4081,7 +4497,6 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
 
     p += 2;
     if (lp->state == INITIALISED) {
-       lp->ibn = 1;
        lp->active = *p++;
        lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
        lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
@@ -4093,9 +4508,10 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
     } else if ((lp->media == INIT) && (lp->timeout < 0)) {
         lp->ibn = 1;
         lp->active = *p;
-       lp->infoblock_csr6 = OMR_PS | OMR_HBD;
+       lp->infoblock_csr6 = OMR_MII_100;
        lp->useMII = TRUE;
        lp->infoblock_media = ANS;
+       lp->media = ANS;
        de4x5_switch_mac_port(dev);
     }
 
@@ -4105,14 +4521,49 @@ type1_infoblock(struct device *dev, u_char count, u_char *p)
 static int 
 type2_infoblock(struct device *dev, u_char count, u_char *p)
 {
-    return DE4X5_AUTOSENSE_MS;
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 2;
+        lp->active = 0;
+       p += 2;
+       lp->infoblock_media = (*p) & MEDIA_CODE;
+
+        if ((*p++) & EXT_FIELD) {
+           lp->cache.csr13 = TWIDDLE(p); p += 2;
+           lp->cache.csr14 = TWIDDLE(p); p += 2;
+           lp->cache.csr15 = TWIDDLE(p); p += 2;
+       } else {
+           lp->cache.csr13 = CSR13;
+           lp->cache.csr14 = CSR14;
+           lp->cache.csr15 = CSR15;
+       }
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16);
+       lp->infoblock_csr6 = OMR_SIA;
+       lp->useMII = FALSE;
+
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
 }
 
 static int 
 type3_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+    u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
     if (--count > lp->tcount) {
@@ -4123,20 +4574,55 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
        }
     }
 
+    p += 2;
     if (lp->state == INITIALISED) {
-       lp->ibn = 3; p += 2;
         lp->active = *p++;
-       lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
-       lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+       lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
+       lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
        lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
        lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
        lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
-       lp->phy[lp->active].ttm = TWIDDLE(p);
+       lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+       lp->phy[lp->active].mci = *p;
        return 0;
-    } else if (lp->media == INIT) {
+    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 3;
+       lp->active = *p;
+       lp->infoblock_csr6 = OMR_MII_100;
+       lp->useMII = TRUE;
+       lp->infoblock_media = ANS;
+
+       de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
+}
+
+static int 
+type4_infoblock(struct device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+       if (*(p+len) < 128) {
+           return dc_infoblock[COMPACT](dev, count, p+len);
+       } else {
+           return dc_infoblock[*(p+len+1)](dev, count, p+len);
+       }
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 4;
+        lp->active = 0;
        p+=2;
-       lp->infoblock_media = (*p++) & BLOCK0_MC;
-       lp->cache.gep = *p++;
+       lp->infoblock_media = (*p++) & MEDIA_CODE;
+        lp->cache.csr13 = CSR13;              /* Hard coded defaults */
+       lp->cache.csr14 = CSR14;
+       lp->cache.csr15 = CSR15;
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16); p += 2;
        csr6 = *p++;
        flags = *p++;
 
@@ -4144,19 +4630,13 @@ type3_infoblock(struct device *dev, u_char count, u_char *p)
        lp->defMedium = (flags & 0x40) ? -1 : 0;
        lp->asBit = 1 << ((csr6 >> 1) & 0x07);
        lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-       lp->infoblock_csr6 = (csr6 & 0x71) << 18;
-       lp->useMII = TRUE;
+       lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+       lp->useMII = FALSE;
 
        de4x5_switch_mac_port(dev);
     }
 
-    return dc21140m_autoconf(dev);
-}
-
-static int 
-type4_infoblock(struct device *dev, u_char count, u_char *p)
-{
-    return DE4X5_AUTOSENSE_MS;
+    return dc2114x_autoconf(dev);
 }
 
 /*
@@ -4167,8 +4647,7 @@ static int
 type5_infoblock(struct device *dev, u_char count, u_char *p)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    u_char i, j, len = (*p & BLOCK_LEN)+1;
+    u_char len = (*p & BLOCK_LEN)+1;
 
     /* Recursively figure out the info blocks */
     if (--count > lp->tcount) {
@@ -4183,19 +4662,7 @@ type5_infoblock(struct device *dev, u_char count, u_char *p)
     if ((lp->state == INITIALISED) || (lp->media == INIT)) {
        p+=2;
         lp->rst = p;
-       i = *p++;
-       for (j=0;i;--i) {
-           if (lp->chipset == DC21140) {
-               if (!j) {
-                   outl(*p++ | GEP_CTRL, DE4X5_GEP);
-                   j++;
-               }
-               outl(*p++, DE4X5_GEP);
-           } else if (lp->chipset == DC21142) {
-           } else if (lp->chipset == DC21143) {
-           }
-       }
-           
+        srom_exec(dev, lp->rst);
     }
 
     return DE4X5_AUTOSENSE_MS;
@@ -4327,8 +4794,7 @@ getfrom_mii(u32 command, u_long ioaddr)
 }
 
 /*
-** Here's 3 ways to calculate the OUI from the ID registers. One's a brain
-** dead approach, 2 aren't (clue: mine isn't!).
+** Here's 3 ways to calculate the OUI from the ID registers.
 */
 static int
 mii_get_oui(u_char phyaddr, u_long ioaddr)
@@ -4394,7 +4860,7 @@ mii_get_phy(struct device *dev)
        if (i==0) n++;                             /* Count cycles */
        while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
        id = mii_get_oui(i, DE4X5_MII); 
-       if ((id == 0) || (id == -1)) continue;     /* Valid ID? */
+       if ((id == 0) || (id == 65535)) continue;  /* Valid ID? */
        for (j=0; j<limit; j++) {                  /* Search PHY table */
            if (id != phy_info[j].id) continue;    /* ID match? */
            for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
@@ -4405,11 +4871,18 @@ mii_get_phy(struct device *dev)
                lp->mii_cnt++;
                lp->active++;
            } else {
-               i = DE4X5_MAX_MII;                 /* Stop the search */
-               j = limit;
+               goto purgatory;                    /* Stop the search */
            }
+           break;
+       }
+       if ((j == limit) && (i < DE4X5_MAX_MII)) {
+           printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name);
+           de4x5_debug |= DEBUG_MII;
+           de4x5_dbg_mii(dev, i);
+           printk("\n");
        }
     }
+  purgatory:
     lp->active = 0;
     if (lp->phy[0].id) {                           /* Reset the PHY devices */
        for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
@@ -4419,7 +4892,8 @@ mii_get_phy(struct device *dev)
            de4x5_dbg_mii(dev, k);
        }
     }
-    
+    if (!lp->mii_cnt) lp->useMII = FALSE;
+
     return lp->mii_cnt;
 }
 
@@ -4480,6 +4954,8 @@ de4x5_switch_mac_port(struct device *dev)
     int iobase = dev->base_addr;
     s32 omr;
 
+    STOP_DE4X5;
+
     /* Assert the OMR_PS bit in CSR6 */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
                                                                     OMR_FDX));
@@ -4490,10 +4966,12 @@ de4x5_switch_mac_port(struct device *dev)
     /* Soft Reset */
     RESET_DE4X5;
     
-    /* Restore the GEP */
+    /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
     if (lp->chipset == DC21140) {
-       outl(lp->cache.gepc, DE4X5_GEP);
-       outl(lp->cache.gep, DE4X5_GEP);
+       gep_wr(lp->cache.gepc, dev);
+       gep_wr(lp->cache.gep, dev);
+    } else if ((lp->chipset & ~0x0ff) == DC2114x) {
+       reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
     }
 
     /* Restore CSR6 */
@@ -4505,6 +4983,36 @@ de4x5_switch_mac_port(struct device *dev)
     return omr;
 }
 
+static void
+gep_wr(s32 data, struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+       outl(data, DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+       outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
+    }
+
+    return;
+}
+
+static int
+gep_rd(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+       return inl(DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+       return (inl(DE4X5_SIGR) & 0x000fffff);
+    }
+
+    return 0;
+}
+
 static void
 timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
@@ -4660,25 +5168,18 @@ de4x5_dbg_media(struct device *dev)
     
     if (lp->media != lp->c_media) {
        if (de4x5_debug & DEBUG_MEDIA) {
-           if (lp->chipset != DC21140) {
-               printk("%s: media is %s\n", dev->name,
-                      (lp->media == NC  ? "unconnected!" :
-                       (lp->media == TP  ? "TP." :
-                        (lp->media == ANS ? "TP/Nway." :
-                         (lp->media == BNC ? "BNC." : 
-                          (lp->media == AUI ? "AUI." : 
-                           (lp->media == BNC_AUI ? "BNC/AUI." : 
-                            (lp->media == EXT_SIA ? "EXT SIA." : 
-                             "???."
-                             ))))))));
-           } else {
-               printk("%s: mode is %s\n", dev->name,
-                   (lp->media == NC ? "link down or incompatible connection.":
-                    (lp->media == _100Mb  ? "100Mb/s." :
-                     (lp->media == _10Mb   ? "10Mb/s." :
-                      "\?\?\?"
-                      ))));
-           }
+           printk("%s: media is %s%s\n", dev->name,
+                  (lp->media == NC  ? "unconnected, link down or incompatible connection" :
+                   (lp->media == TP  ? "TP" :
+                    (lp->media == ANS ? "TP/Nway" :
+                     (lp->media == BNC ? "BNC" : 
+                      (lp->media == AUI ? "AUI" : 
+                       (lp->media == BNC_AUI ? "BNC/AUI" : 
+                        (lp->media == EXT_SIA ? "EXT SIA" : 
+                         (lp->media == _100Mb  ? "100Mb/s" :
+                          (lp->media == _10Mb   ? "10Mb/s" :
+                           "???"
+                           ))))))))), (lp->fdx?" full duplex.":"."));
        }
        lp->c_media = lp->media;
     }
@@ -4750,7 +5251,8 @@ de4x5_dbg_rx(struct sk_buff *skb, int len)
 
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
+** effective uid is checked in those cases. In the normal course of events
+** this function is only used for my testing.
 */
 static int
 de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
@@ -4792,7 +5294,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        build_setup_frame(dev, PHYS_ADDR_ONLY);
        /* Set up the descriptor and give ownership to the card */
-       while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+       while (test_and_set_bit(0, (void *)&dev->tbusy) != 0);
        load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
                                                        SETUP_FRAME_LEN, NULL);
        lp->tx_new = (++lp->tx_new) % lp->txRingSize;
@@ -4805,6 +5307,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            omr = inl(DE4X5_OMR);
            omr |= OMR_PR;
            outl(omr, DE4X5_OMR);
+           dev->flags |= IFF_PROMISC;
        } else {
            status = -EPERM;
        }
@@ -4815,6 +5318,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
            omr = inl(DE4X5_OMR);
            omr &= ~OMR_PR;
            outb(omr, DE4X5_OMR);
+           dev->flags &= ~IFF_PROMISC;
        } else {
            status = -EPERM;
        }
@@ -4824,13 +5328,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        printk("%s: Boo!\n", dev->name);
        
        break;
-      case DE4X5_GET_MCA:              /* Get the multicast address table */
-       break;
-      case DE4X5_SET_MCA:              /* Set a multicast address */
-       break;
-      case DE4X5_CLR_MCA:              /* Clear all multicast addresses */
-       break;
-      case DE4X5_MCA_EN:               /* Enable pass all multicast addresses*/
+      case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
        if (suser()) {
            omr = inl(DE4X5_OMR);
            omr |= OMR_PM;
@@ -4895,9 +5393,8 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        }
        break;
        
-/*
-#define DE4X5_DUMP              0x0f / * Dump the DE4X5 Status * /
-       
+#define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
+/*     
       case DE4X5_DUMP:
        j = 0;
        tmp.addr[j++] = dev->irq;
@@ -4951,7 +5448,7 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
        tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
        tmp.lval[j>>2] = lp->chipset; j+=4; 
        if (lp->chipset == DC21140) {
-           tmp.lval[j>>2] = inl(DE4X5_GEP);  j+=4;
+           tmp.lval[j>>2] = gep_rd(dev);  j+=4;
        } else {
            tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
            tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
@@ -5004,21 +5501,33 @@ de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 #define LP(a) ((struct de4x5_private *)(a))
 static struct device *mdev = NULL;
 static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+MODULE_PARM(io, "i");
+#endif /* LINUX_VERSION_CODE */
 
 int
 init_module(void)
 {
+    int i, num, status = -EIO;
     struct device *p;
 
-    if ((mdev = insert_device(NULL, io, de4x5_probe)) == NULL) 
-      return -ENOMEM;
+    num = count_adapters();
+
+    for (i=0; i<num; i++) {
+       if ((p = insert_device(NULL, io, de4x5_probe)) == NULL) 
+           return -ENOMEM;
+
+       if (!mdev) mdev = p;
 
-    for (p = mdev; p != NULL; p = LP(p->priv)->next_module) {
-       if (register_netdev(p) != 0)
-         return -EIO;
+       if (register_netdev(p) != 0) {
+           kfree(p);
+       } else {
+           status = 0;                 /* At least one adapter will work */
+           lastModule = p;
+       }
     }
 
-    return 0;
+    return status;
 }
 
 void
@@ -5054,6 +5563,59 @@ unlink_modules(struct device *p)
     return next;
 }
 
+static int
+count_adapters(void)
+{
+    int i, j;
+    char name[DE4X5_STRLEN];
+    u_char pb, dev_fn, dev_num;
+    u_short dev_id, vendor;
+    u_int class = DE4X5_CLASS_CODE;
+    u_int device, iobase = 0x1000;
+
+    for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+       if (EISA_signature(name, EISA_ID)) j++;
+    }
+    if (!pcibios_present()) return j;
+
+    for (i=0; 
+        (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+        i++) {
+       dev_num = PCI_SLOT(dev_fn);
+       device = 0;
+       pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
+       pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id);
+       device = dev_id;
+       device <<= 8;
+       if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
+    }
+
+    return j;
+}
+
+/*
+** If at end of eth device list and can't use current entry, malloc
+** one up. If memory could not be allocated, print an error message.
+*/
+__initfunc(static struct device *
+insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)))
+{
+    struct device *new;
+
+    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
+    if (new == NULL) {
+       printk("de4x5.c: Device not initialised, insufficient memory\n");
+       return NULL;
+    } else {
+       memset((char *)new, 0, sizeof(struct device)+8);
+       new->name = (char *)(new + 1);
+       new->base_addr = iobase;       /* assign the io address */
+       new->init = init;              /* initialisation routine */
+    }
+
+    return new;
+}
+
 #endif /* MODULE */
 
 \f
@@ -5064,3 +5626,10 @@ unlink_modules(struct device *p)
  *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
  * End:
  */
+
+
+
+
+
+
+
index 525e0122d47b2620a58a8a9365779b205c9bfe7c..ce095310d0e4b4ea92341ed40aaff6a682c0e5f7 100644 (file)
 #define DC21140     DC21140_DID
 #define DC2114x     DC2114x_DID
 #define DC21142     (DC2114x_DID | 0x0010)
-#define DC21143     (DC2114x_DID | 0x0020)
+#define DC21143     (DC2114x_DID | 0x0030)
 
 #define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
 #define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
 #define TR_128     0x00008000       /* Threshold set to 128 (512) bytes */
 #define TR_160     0x0000c000       /* Threshold set to 160 (1024) bytes */
 
+#define OMR_DEF     (OMR_SDP)
+#define OMR_SIA     (OMR_SDP | OMR_TTM)
+#define OMR_SYM     (OMR_SDP | OMR_SCR | OMR_PCS | OMR_HBD | OMR_PS)
+#define OMR_MII_10  (OMR_SDP | OMR_TTM | OMR_PS)
+#define OMR_MII_100 (OMR_SDP | OMR_SCR | OMR_HBD | OMR_PS)
+
 /*
 ** DC21040 Interrupt Mask Register (DE4X5_IMR)
 */
 ** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
 */
 /* Valid ONLY for DE500 hardware */
-#define GEP_LNP  0x00000080        /* Link Pass               (input) */
-#define GEP_SLNK 0x00000040        /* SYM LINK                (input) */
-#define GEP_SDET 0x00000020        /* Signal Detect           (input) */
-#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output) */
-#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output) */
-#define GEP_PHYL 0x00000004        /* PHY Loopback            (output) */
-#define GEP_FLED 0x00000002        /* Force Activity LED on   (output) */
-#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s           */
-#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1) */
-#define GEP_CTRL 0x00000100        /* GEP control bit                  */
+#define GEP_LNP  0x00000080        /* Link Pass               (input)        */
+#define GEP_SLNK 0x00000040        /* SYM LINK                (input)        */
+#define GEP_SDET 0x00000020        /* Signal Detect           (input)        */
+#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output)       */
+#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output)       */
+#define GEP_PHYL 0x00000004        /* PHY Loopback            (output)       */
+#define GEP_FLED 0x00000002        /* Force Activity LED on   (output)       */
+#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s                 */
+#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1)       */
+#define GEP_CTRL 0x00000100        /* GEP control bit                        */
+
+/*
+** SIA Register Defaults
+*/
+#define CSR13 0x00000001
+#define CSR14 0x0003ff7f           /* Autonegotiation disabled               */
+#define CSR15 0x00000008
 
 /*
 ** SIA Status Register (DE4X5_SISR)
 */
-#define SISR_LPC   0xffff0000      /* Link Partner's Code Word */
-#define SISR_LPN   0x00008000      /* Link Partner Negotiable */
-#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State */
-#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041) */
-#define SISR_TRF   0x00000800      /* Transmit Remote Fault */
-#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142) */
+#define SISR_LPC   0xffff0000      /* Link Partner's Code Word               */
+#define SISR_LPN   0x00008000      /* Link Partner Negotiable                */
+#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State     */
+#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041)     */
+#define SISR_TRF   0x00000800      /* Transmit Remote Fault                  */
+#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142)     */
 #define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
-#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity */
-#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity */
-#define SISR_ARA   0x00000100      /* AUI Receive Port Activity */
-#define SISR_SRA   0x00000100      /* Selected Port Receive Activity */
-#define SISR_DAO   0x00000080      /* PLL All One */
-#define SISR_DAZ   0x00000040      /* PLL All Zero */
-#define SISR_DSP   0x00000020      /* PLL Self-Test Pass */
-#define SISR_DSD   0x00000010      /* PLL Self-Test Done */
-#define SISR_APS   0x00000008      /* Auto Polarity State */
-#define SISR_LKF   0x00000004      /* Link Fail Status */
-#define SISR_NCR   0x00000002      /* Network Connection Error */
-#define SISR_PAUI  0x00000001      /* AUI_TP Indication */
-#define SISR_MRA   0x00000001      /* MII Receive Port Activity */
-
-#define ANS_NDIS   0x00000000      /* Nway disable */
-#define ANS_TDIS   0x00001000      /* Transmit Disable */
-#define ANS_ADET   0x00002000      /* Ability Detect */
-#define ANS_ACK    0x00003000      /* Acknowledge */
-#define ANS_CACK   0x00004000      /* Complete Acknowledge */
-#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good */
-#define ANS_LCHK   0x00006000      /* Link Check */
+#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity         */
+#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity     */
+#define SISR_ARA   0x00000100      /* AUI Receive Port Activity              */
+#define SISR_SRA   0x00000100      /* Selected Port Receive Activity         */
+#define SISR_DAO   0x00000080      /* PLL All One                            */
+#define SISR_DAZ   0x00000040      /* PLL All Zero                           */
+#define SISR_DSP   0x00000020      /* PLL Self-Test Pass                     */
+#define SISR_DSD   0x00000010      /* PLL Self-Test Done                     */
+#define SISR_APS   0x00000008      /* Auto Polarity State                    */
+#define SISR_LKF   0x00000004      /* Link Fail Status                       */
+#define SISR_LS10  0x00000004      /* 10Mb/s Link Fail Status                */
+#define SISR_NCR   0x00000002      /* Network Connection Error               */
+#define SISR_LS100 0x00000002      /* 100Mb/s Link Fail Status               */
+#define SISR_PAUI  0x00000001      /* AUI_TP Indication                      */
+#define SISR_MRA   0x00000001      /* MII Receive Port Activity              */
+
+#define ANS_NDIS   0x00000000      /* Nway disable                           */
+#define ANS_TDIS   0x00001000      /* Transmit Disable                       */
+#define ANS_ADET   0x00002000      /* Ability Detect                         */
+#define ANS_ACK    0x00003000      /* Acknowledge                            */
+#define ANS_CACK   0x00004000      /* Complete Acknowledge                   */
+#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good                */
+#define ANS_LCHK   0x00006000      /* Link Check                             */
+
+#define SISR_RST   0x00000301      /* CSR12 reset                            */
+#define SISR_ANR   0x00001301      /* Autonegotiation restart                */
 
 /*
 ** SIA Connectivity Register (DE4X5_SICR)
 #define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
 #define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
 #define DEBUG_PCICFG    0x0100
+#define DEBUG_ALL       0x01ff
 
 /*
 ** Miscellaneous
 #define CLOSED               1     /* Ready for opening */
 #define OPEN                 2     /* Running */
 
+/*
+** Various wait times
+*/
+#define PDET_LINK_WAIT    1200    /* msecs to wait for link detect bits     */
+#define ANS_FINISH_WAIT   1000    /* msecs to wait for link detect bits     */
+
 /*
 ** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
 ** the vendors seem split 50-50 on how to calculate the OUI register values
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
+    outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
   } else {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
   } else if (lp->useSROM && !lp->useMII) {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | lp->infoblock_csr6 | OMR_HBD, DE4X5_OMR);\
+    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
   } else {\
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
     omr |= (lp->fdx ? OMR_FDX : 0);\
@@ -991,3 +1016,5 @@ struct de4x5_ioctl {
 #define DE4X5_GET_OMR           0x0c /* Get the OMR Register contents */
 #define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
 #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
index c9ea5a34d02693fcebd8622315b685d003503a83..79bf0a14ce415facb5c7764a99f1dcebde189901 100644 (file)
@@ -162,6 +162,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( MOTOROLA,       MOTOROLA_MPC105,"MPC105 Eagle"),
        DEVICE( MOTOROLA,       MOTOROLA_MPC106,"MPC106 Grackle"),
        DEVICE( MOTOROLA,       MOTOROLA_RAVEN, "Raven"),
+       DEVICE( PROMISE,        PROMISE_IDE_UDMA,"IDE Ultra DMA/33"),
        DEVICE( PROMISE,        PROMISE_5300,   "DC5030"),
        DEVICE( N9,             N9_I128,        "Imagine 128"),
        DEVICE( N9,             N9_I128_2,      "Imagine 128v2"),
index ab52e4ed1f174570c1d3b75d89995c0f6f08ec9d..3d3ee56956325f5292a4ec00859869dc73e27555 100644 (file)
@@ -92,7 +92,6 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
   if [ "$CONFIG_SCSI_PPA" != "n" ]; then
     int  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
-    int  '  EPP timeout'             CONFIG_SCSI_PPA_EPP_TIME 128
   fi
 fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
index 93e1b2b5f332e481d28f1dec80a18424d5abdbc1..53ad122031fc850df02cc5184198ce7dabe753c9 100644 (file)
  * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
  * under the terms of the GNU Public License.
  * 
- */
-
-/*      This driver was developed without the benefit of any technical
- * specifications for the interface.  Instead, a modified version of
- * DOSemu was used to monitor the protocol used by the DOS driver
- * for this adapter.  I have no idea how my programming model relates
- * to IOMEGA's design.
- * 
- * IOMEGA's driver does not generate linked commands.  I've never
- * observed a SCSI message byte in the protocol transactions, so
- * I am assuming that as long as linked commands are not used
- * we won't see any.  
- * 
- * For more information, see the file drivers/scsi/README.ppa.
- * 
- */
-
-/* 
- * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
- * to support EPP and scatter-gather.                        [0.26-athena]
- *
- * additional hacks by David Campbell (campbell@tirian.che.curtin.edu.au)
- * in response to this driver "mis-behaving" on his machine.
- *      Fixed EPP to handle "software" changing of EPP port data direction.
- *      Chased down EPP timeouts
- *      Made this driver "kernel version friendly"           [0.28-athena]
- *
- * Really hacked it out of existance (David Campbell)
- *      EPP timeouts no longer occur (yet better handling)
- *      Probes known parallel ports
- *      Autodetects EPP / ECP / PS2 / NIBBLE
- *      Support for multiple devices (does anyone need this??)
- *                                                           [0.29-Curtin]
- * [ Stuff removed ]
- *
- *      Modified PEDANTIC for less PEDANTIC drivers as people
- *      were complaining about speed (I received a report indicating
- *      that PEDANTIC is necessary for WinBond chipsets.
- *      Updated config_ppa and Makefile
- *                                                           [0.36b-Curtin]
- *
- * First round of cleanups
- *      Remove prior 1.3.34 kernel support
- *      SMC support changed
- *              ECP+EPP detection always invoked.
- *              If compat mode => PS/2
- *              else ecp_sync() called (ECP+EPP uses FIFO).
- *      Added routine to detect interrupt channel for ECP (not used)
- *      Changed version numbering
- *              1       Major number
- *              00      Minor revision number
- *              ALPHA   Expected stability (alpha, beta, stable)
- *                                              [Curtin-1-00-ALPHA]
- * Second round of cleanups
- *      Clean up timer queues
- *      Fixed problem with non-detection of PS/2 ports
- *      SMC ECP+EPP confirmed to work, remove option from config_ppa
- *                                              [Curtin-1-01-ALPHA]
- *
- * Parport hits with a vengance!!
- *      Several internal revisions have been made with huge amounts of
- *      fixes including:
- *              ioport_2_hostno removed (unique_id is quicker)
- *              SMC compat option is history
- *              Driver name / info hardwired
- *              Played with inlines and saved 4k on module
- *      Parport support
- *              Using PnP Parport allows use of printer attached to
- *              ZIP drive.
- *              Numerous fixups for device registration and to allow
- *              proper aborts.
- *      Version jumps a few numbers here - considered BETA
- *      Shipping Parport with monolithic driver :)
- *                                              [Curtin-1-05-BETA]
- *
- * Fixed code to ensure SCSI abort will release the SCSI command
- *      if the driver is STILL trying to claim the parport (PNP ver)
- *      Now I have to fix the lp driver then there will NEVER be a
- *      problem.
- *      Got around to doing the ppa_queuecommand() clean up
- *      Fixed bug relating to SMC EPP+ECP and monolithic driver
- *                                              [Curtin-1-06-BETA]
- *
- * Where did the ppa_setup() code disappear to ??
- *      Back in now...
- *      Distribution of ppa now independent of parport (less work for me).
- *      Also cleaned up the port detection to allow for variations on
- *      IO aliasing (in an attempt to fix a few problems with some
- *      machines...)
- *                                              [Curtin-1-07-BETA]
- *
- * Rewrote detection code for monolithic driver and ported changes to
- *      parport driver. Result is more stable detection of hardware and
- *      better immunity to port aliasing (old XT cards).
- *      Parport 0.16 (or better) is required for parport operation and
- *      ECP+EPP modes, otherwise the latest parport edition is recommended.
- *
- *      When using EPP and writing to disk CPU usage > 40%, while reading <10%.
- *      This is due to ZIP drive IO scheduling, the drive does a verify after
- *      write to ensure data integrity (removable media is ALWAYS questionable
- *      since you never know where it has been).
- *      Some fancy programing *MAY* fix the problem but at 30 Mb/min is just
- *      over 10 sectors per jiffy.
- *
- *      Hmm... I think I know a way but it will send the driver into
- *      ALPHA state again.
- *                                              [Curtin-1-08-STABLE]
+ * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
+ *                     campbell@gear.torque.net
+ *                     dcampbel@p01.as17.honeywell.com.au
  */
 
 #include <linux/config.h>
 
 /* The following #define is to avoid a clash with hosts.c */
 #define PPA_CODE 1
-#include  "ppa.h"
-/* batteries not included :-) */
 
-/*
- * modes in which the driver can operate 
- */
-#define   PPA_AUTODETECT        0      /* Autodetect mode                */
-#define   PPA_NIBBLE            1      /* work in standard 4 bit mode    */
-#define   PPA_PS2               2      /* PS/2 byte mode         */
-#define   PPA_EPP_8             3      /* EPP mode, 8 bit                */
-#define   PPA_EPP_16            4      /* EPP mode, 16 bit               */
-#define   PPA_EPP_32            5      /* EPP mode, 32 bit               */
-#define   PPA_UNKNOWN           6      /* Just in case...                */
-
-static char *PPA_MODE_STRING[] =
-{
-       "Autodetect",
-       "SPP",
-       "PS/2",
-       "EPP 8 bit",
-       "EPP 16 bit",
-       "EPP 32 bit",
-       "Unknown"};
+#include <linux/blk.h>
+#include <asm/io.h>
+#include <linux/parport.h>
+#include "sd.h"
+#include "hosts.h"
+int ppa_release(struct Scsi_Host *);
 
 typedef struct {
-       struct pardevice *dev;  /* Parport device entry          */
-       int speed;              /* General PPA delay constant   */
-       int speed_fast;         /* Const for nibble/byte modes  */
-       int epp_speed;          /* Reset time period            */
-       int mode;               /* Transfer mode                */
-       int timeout;            /* Number of timeouts           */
-       int host;               /* Host number (for proc)       */
-       int abort_flag;         /* Abort flag                   */
-       int error_code;         /* Error code                   */
-       int ppa_failed;         /* Failure flag                 */
-       Scsi_Cmnd *cur_cmd;     /* Current queued command       */
-       void (*done) (Scsi_Cmnd *);     /* Done func for queuecommand   */
-       struct tq_struct ppa_tq;        /* Polling interupt stuff       */
-       struct wait_queue *ppa_wait_q;  /* Used for PnP stuff           */
+    struct pardevice *dev;     /* Parport device entry         */
+    int base;                  /* Actual port address          */
+    int mode;                  /* Transfer mode                */
+    int host;                  /* Host number (for proc)       */
+    Scsi_Cmnd *cur_cmd;                /* Current queued command       */
+    struct tq_struct ppa_tq;   /* Polling interupt stuff       */
+    unsigned long jstart;      /* Jiffies at start             */
+    unsigned int failed:1;     /* Failure flag                 */
+    unsigned int p_busy:1;     /* Parport sharing busy flag    */
 } ppa_struct;
 
-static void ppa_interrupt(void *data);
-/* I know that this is a mess but it works!! */
+#define PPA_EMPTY \
+{NULL,         /* dev */       \
+-1,            /* base */      \
+PPA_AUTODETECT,        /* mode */      \
+-1,            /* host */      \
+NULL,          /* cur_cmd */   \
+{0, 0, ppa_interrupt, NULL},   \
+0,             /* jstart */    \
+0,             /* failed */    \
+0              /* p_busy */    \
+}
+
+#include  "ppa.h"
+#include <linux/parport.h>
+
+#ifdef CONFIG_KERNELD
+#include  <linux/kerneld.h>
+#ifndef PARPORT_MODULES
+#define PARPORT_MODULES "parport_pc"
+#endif
+#endif
+
 #define NO_HOSTS 4
 static ppa_struct ppa_hosts[NO_HOSTS] =
-{
-  {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL,
-   {0, 0, ppa_interrupt, NULL}, NULL},
-  {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL,
-   {0, 0, ppa_interrupt, NULL}, NULL},
-  {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL,
-   {0, 0, ppa_interrupt, NULL}, NULL},
-  {0, 6, 1, CONFIG_SCSI_PPA_EPP_TIME, PPA_AUTODETECT, 0, -1, 0, DID_ERROR, 1, NULL, NULL,
-   {0, 0, ppa_interrupt, NULL}, NULL}
-};
-
-/* This is a global option */
-static int ppa_speed = -1;     /* Set to >0 to act as a global value */
-static int ppa_speed_fast = -1;        /* ditto.. */
-static int ppa_sg = SG_ALL;    /* enable/disable scatter-gather. */
-
-/* other options */
-#define   PPA_CAN_QUEUE         1      /* use "queueing" interface */
-#define   PPA_BURST_SIZE        512    /* block size for bulk transfers */
-#define   PPA_SELECT_TMO        5000   /* how long to wait for target ? */
-#define   PPA_SPIN_TMO          500000 /* ppa_wait loop limiter */
-
-#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
-
-/* args to ppa_connect */
-#define CONNECT_EPP_MAYBE 1
-#define CONNECT_NORMAL  0
-
-#define PPA_BASE(x)    ppa_hosts[(x)].dev->port->base
-
-/* Port IO - Sorry Grant but I prefer the following symbols */
-#define r_dtr(x)        inb(PPA_BASE(x))
-#define r_str(x)        inb(PPA_BASE(x)+1)
-#define r_ctr(x)        inb(PPA_BASE(x)+2)
-#define r_epp(x)        inb(PPA_BASE(x)+4)
-#define r_fifo(x)       inb(PPA_BASE(x)+0x400)
-#define r_ecr(x)        inb(PPA_BASE(x)+0x402)
-
-#define w_dtr(x,y)      outb(y, PPA_BASE(x))
-#define w_str(x,y)      outb(y, PPA_BASE(x)+1)
-#define w_ctr(x,y)      outb(y, PPA_BASE(x)+2);\
-                       udelay( ppa_hosts[(x)].speed)
-#define w_epp(x,y)      outb(y, PPA_BASE(x)+4)
-#define w_fifo(x,y)     outb(y, PPA_BASE(x)+0x400)
-#define w_ecr(x,y)      outb(y, PPA_BASE(x)+0x402)
-
-static void ppa_wakeup(void *ref)
-{
-       ppa_struct *ppa_dev = (ppa_struct *) ref;
+{PPA_EMPTY, PPA_EMPTY, PPA_EMPTY, PPA_EMPTY};
 
-       if (!ppa_dev->ppa_wait_q)
-               return; /* Wake up whom ? */
+#define PPA_BASE(x)    ppa_hosts[(x)].base
 
-       /* Claim the Parport */
-       if (parport_claim(ppa_dev->dev))
-               return; /* Shouldn't happen */
+void ppa_wakeup(void *ref)
+{
+    ppa_struct *ppa_dev = (ppa_struct *) ref;
 
-       wake_up(&ppa_dev->ppa_wait_q);
+    if (!ppa_dev->p_busy)
        return;
+
+    if (parport_claim(ppa_dev->dev)) {
+       printk("ppa: bug in ppa_wakeup\n");
+       return;
+    }
+
+    ppa_dev->p_busy = 0;
+    ppa_dev->base = ppa_dev->dev->port->base;
+    if (ppa_dev->cur_cmd)
+       ppa_dev->cur_cmd->SCp.phase++;
+    return;
 }
 
 int ppa_release(struct Scsi_Host *host)
 {
-       int host_no = host->unique_id;
+    int host_no = host->unique_id;
 
-       printk("Releasing ppa%i\n", host_no);
-       parport_unregister_device(ppa_hosts[host_no].dev);
-       return 0;
+    printk("Releasing ppa%i\n", host_no);
+    parport_unregister_device(ppa_hosts[host_no].dev);
+    return 0;
 }
 
 static int ppa_pb_claim(int host_no)
 {
-       if (parport_claim(ppa_hosts[host_no].dev)) {
-               sleep_on(&ppa_hosts[host_no].ppa_wait_q);
-               ppa_hosts[host_no].ppa_wait_q = NULL;
-
-               /* Check to see if we were aborted or reset */
-               if (ppa_hosts[host_no].dev->port->cad !=
-                   ppa_hosts[host_no].dev) {
-                       printk("Abort detected on ppa%i\n", host_no);
-                       return 1;
-               }
-       }
-       return 0;
-}
+    if (parport_claim(ppa_hosts[host_no].dev)) {
+       ppa_hosts[host_no].p_busy = 1;
+       return 1;
+    }
 
-static void ppa_pb_release(int host_no)
-{
-       parport_release(ppa_hosts[host_no].dev);
+    PPA_BASE(host_no) = ppa_hosts[host_no].dev->port->base;
+    if (ppa_hosts[host_no].cur_cmd)
+       ppa_hosts[host_no].cur_cmd->SCp.phase++;
+    return 0;
 }
 
+#define ppa_pb_release(x) parport_release(ppa_hosts[(x)].dev)
+
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = PPA;
+#include  "scsi_module.c"
+#endif
+
+/*
+ * Start of Chipset kludges
+ */
 
-/* Placed here so everyone knows what ecp_sync does.. */
-static void ecp_sync(int host_no)
+int ppa_detect(Scsi_Host_Template * host)
 {
-       int i, r;
+    struct Scsi_Host *hreg;
+    int ports;
+    int i, nhosts, try_again;
+    struct parport *pb = parport_enumerate();
+
+    printk("ppa: Version %s\n", PPA_VERSION);
+    nhosts = 0;
+    try_again = 0;
+
+#ifdef CONFIG_KERNELD
+    if (!pb) {
+       request_module(PARPORT_MODULES);
+       pb = parport_enumerate();
+    }
+#endif
 
-       r = r_ecr(host_no);
-       if ((r & 0xe0) != 0x80)
-               return;
+    if (!pb) {
+       printk("ppa: parport reports no devices.\n");
+       return 0;
+    }
+  retry_entry:
+    for (i = 0; pb; i++, pb = pb->next) {
+       int modes, ppb;
 
-       for (i = 0; i < 100; i++) {
-               r = r_ecr(host_no);
-               if (r & 0x01)
-                       return;
-               udelay(5);
-       }
+       ppa_hosts[i].dev =
+           parport_register_device(pb, "ppa", NULL, ppa_wakeup,
+                        NULL, PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]);
 
-       printk("ppa: ECP sync failed as data still present in FIFO.\n");
-}
+       /* Claim the bus so it remembers what we do to the control
+        * registers. [ CTR and ECP ]
+        */
+       if (ppa_pb_claim(i))
+           while (ppa_hosts[i].p_busy)
+               schedule(); /* Whe can safe schedule() here */
+       ppb = PPA_BASE(i);
+       w_ctr(ppb, 0x0c);
+       modes = ppa_hosts[i].dev->port->modes;
+
+       /* Mode detection works up the chain of speed
+        * This avoids a nasty if-then-else-if-... tree
+        */
+       ppa_hosts[i].mode = PPA_NIBBLE;
 
-static inline void ppa_d_pulse(int host_no, char b)
-{
-       w_dtr(host_no, b);
-       w_ctr(host_no, 0xc);
-       w_ctr(host_no, 0xe);
-       w_ctr(host_no, 0xc);
-       w_ctr(host_no, 0x4);
-       w_ctr(host_no, 0xc);
-}
+       if (modes & PARPORT_MODE_PCPS2)
+           ppa_hosts[i].mode = PPA_PS2;
 
-static void ppa_disconnect(int host_no)
-{
-       ppa_d_pulse(host_no, 0);
-       ppa_d_pulse(host_no, 0x3c);
-       ppa_d_pulse(host_no, 0x20);
-       ppa_d_pulse(host_no, 0xf);
+       if (modes & PARPORT_MODE_PCECPPS2) {
+           w_ecr(ppb, 0x20);
+           ppa_hosts[i].mode = PPA_PS2;
+       }
+       if (modes & PARPORT_MODE_PCECPEPP)
+           w_ecr(ppb, 0x80);
 
-       ppa_pb_release(host_no);
-}
+       /* Done configuration */
+       ppa_pb_release(i);
 
-static inline void ppa_c_pulse(int host_no, char b)
-{
-       w_dtr(host_no, b);
-       w_ctr(host_no, 0x4);
-       w_ctr(host_no, 0x6);
-       w_ctr(host_no, 0x4);
-       w_ctr(host_no, 0xc);
+       if (ppa_init(i)) {
+           parport_unregister_device(ppa_hosts[i].dev);
+           continue;
+       }
+       /* now the glue ... */
+       switch (ppa_hosts[i].mode) {
+       case PPA_NIBBLE:
+           ports = 3;
+           break;
+       case PPA_PS2:
+           ports = 3;
+           break;
+       case PPA_EPP_8:
+       case PPA_EPP_16:
+       case PPA_EPP_32:
+           ports = 8;
+           break;
+       default:                /* Never gets here */
+           continue;
+       }
+
+       host->can_queue = PPA_CAN_QUEUE;
+       host->sg_tablesize = ppa_sg;
+       hreg = scsi_register(host, 0);
+       hreg->io_port = pb->base;
+       hreg->n_io_port = ports;
+       hreg->dma_channel = -1;
+       hreg->unique_id = i;
+       ppa_hosts[i].host = hreg->host_no;
+       nhosts++;
+    }
+    if (nhosts == 0) {
+       if (try_again == 1)
+           return 0;
+       try_again = 1;
+       goto retry_entry;
+    } else
+       return 1;               /* return number of hosts detected */
 }
 
-static int ppa_connect(int host_no, int flag)
+/* This is to give the ppa driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/ppa/0 file.
+ * Very simple method really... (To simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+
+static inline int ppa_strncmp(const char *a, const char *b, int len)
 {
-       int retv = ppa_pb_claim(host_no);
-
-       ppa_c_pulse(host_no, 0);
-       ppa_c_pulse(host_no, 0x3c);
-       ppa_c_pulse(host_no, 0x20);
-       if ((flag == CONNECT_EPP_MAYBE) &&
-           IN_EPP_MODE(ppa_hosts[host_no].mode))
-               ppa_c_pulse(host_no, 0xcf);
-       else
-               ppa_c_pulse(host_no, 0x8f);
+    int loop;
+    for (loop = 0; loop < len; loop++)
+       if (a[loop] != b[loop])
+           return 1;
 
-       return retv;
+    return 0;
 }
 
-static void ppa_do_reset(int host_no)
+static inline int ppa_proc_write(int hostno, char *buffer, int length)
 {
-       /*
-        * SCSI reset taken from ppa_init and checked with
-        * Iomega document that Grant has (via email :(
-        */
-       ppa_pb_claim(host_no);
-       ppa_disconnect(host_no);
-
-       ppa_connect(host_no, CONNECT_NORMAL);
-
-       w_ctr(host_no, 0x6);
-       w_ctr(host_no, 0x4);
-       w_dtr(host_no, 0x40);
-       w_ctr(host_no, 0x8);
-       udelay(50);
-       w_ctr(host_no, 0xc);
-
-       ppa_disconnect(host_no);
+    unsigned long x;
+
+    if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) {
+       x = simple_strtoul(buffer + 5, NULL, 0);
+       ppa_hosts[hostno].mode = x;
+       return length;
+    }
+    printk("ppa /proc: invalid variable\n");
+    return (-EINVAL);
 }
 
-static char ppa_select(int host_no, int initiator, int target)
+int ppa_proc_info(char *buffer, char **start, off_t offset,
+                 int length, int hostno, int inout)
 {
-       char r;
-       int k;
+    int i;
+    int len = 0;
 
-       r = r_str(host_no);     /* TODO */
+    for (i = 0; i < 4; i++)
+       if (ppa_hosts[i].host == hostno)
+           break;
 
-       w_dtr(host_no, (1 << target));
-       w_ctr(host_no, 0xe);
-       w_ctr(host_no, 0xc);
-       w_dtr(host_no, (1 << initiator));
-       w_ctr(host_no, 0x8);
+    if (inout)
+       return ppa_proc_write(i, buffer, length);
 
-       k = 0;
-       while (!(r = (r_str(host_no) & 0xf0)) && (k++ < PPA_SELECT_TMO))
-               barrier();
+    len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
+    len += sprintf(buffer + len, "Parport : %s\n", ppa_hosts[i].dev->port->name);
+    len += sprintf(buffer + len, "Mode    : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
 
-       if (k >= PPA_SELECT_TMO)
-               return 0;
+    /* Request for beyond end of buffer */
+    if (offset > length)
+       return 0;
 
-       return r;
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+       len = length;
+    return len;
 }
+/* end of ppa.c */
+static int device_check(int host_no);
 
-static void ppa_fail(int host_no, int error_code)
+#if PPA_DEBUG > 0
+#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
+          y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+static inline void ppa_fail_func(int host_no, int error_code)
+#else
+static inline void ppa_fail(int host_no, int error_code)
+#endif
 {
-       ppa_hosts[host_no].error_code = error_code;
-       ppa_hosts[host_no].ppa_failed = 1;
-       ppa_disconnect(host_no);
+    /* If we fail a device then we trash status / message bytes */
+    if (ppa_hosts[host_no].cur_cmd) {
+       ppa_hosts[host_no].cur_cmd->result = error_code << 16;
+       ppa_hosts[host_no].failed = 1;
+    }
 }
 
 /*
@@ -378,483 +300,539 @@ static void ppa_fail(int host_no, int error_code)
  * doesn't appear to be designed to support interrupts.  We spin on
  * the 0x80 ready bit. 
  */
-static char ppa_wait(int host_no)
+static unsigned char ppa_wait(int host_no)
 {
-       int k;
-       char r;
-
-       k = 0;
-       while (!((r = r_str(host_no)) & 0x80)
-              && (k++ < PPA_SPIN_TMO) && !ppa_hosts[host_no].abort_flag)
-               barrier();
-
-       /* check if we were interrupted */
-       if (ppa_hosts[host_no].abort_flag) {
-               if (ppa_hosts[host_no].abort_flag == 1)
-                       ppa_fail(host_no, DID_ABORT);
-               else {
-                       ppa_do_reset(host_no);
-                       ppa_fail(host_no, DID_RESET);
-               }
-               return 0;
-       }
-       /* check if timed out */
-       if (k >= PPA_SPIN_TMO) {
-               ppa_fail(host_no, DID_TIME_OUT);
-               return 0;       /* command timed out */
-       }
-       /* 
-        * return some status information.
-        * Semantics: 0xc0 = ZIP wants more data
-        *            0xd0 = ZIP wants to send more data
-        *            0xf0 = end of transfer, ZIP is sending status
-        */
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char r;
+
+    k = PPA_SPIN_TMO;
+    do {
+       r = r_str(ppb);
+       k--;
+       udelay(1);
+    }
+    while (!(r & 0x80) && (k));
+
+    /*
+     * return some status information.
+     * Semantics: 0xc0 = ZIP wants more data
+     *            0xd0 = ZIP wants to send more data
+     *            0xe0 = ZIP is expecting SCSI command data
+     *            0xf0 = end of transfer, ZIP is sending status
+     */
+    if (k)
        return (r & 0xf0);
-}
 
+    /* Counter expired - Time out occured */
+    ppa_fail(host_no, DID_TIME_OUT);
+    printk("ppa timeout in ppa_wait\n");
+    return 0;                  /* command timed out */
+}
 
-/* 
- * This is based on a trace of what the Iomega DOS 'guest' driver does.
- * I've tried several different kinds of parallel ports with guest and
- * coded this to react in the same ways that it does.
- * 
- * The return value from this function is just a hint about where the
- * handshaking failed.
- * 
+/*
+ * output a string, in whatever mode is available, according to the
+ * PPA protocol. 
  */
-static int ppa_init(int host_no)
+static inline void epp_reset(unsigned short ppb)
 {
-       if (ppa_pb_claim(host_no))
-               return 1;
-       ppa_disconnect(host_no);
+    int i;
 
-       ppa_connect(host_no, CONNECT_NORMAL);
+    i = r_str(ppb);
+    w_str(ppb, i);
+    w_str(ppb, i & 0xfe);
+}
 
-       w_ctr(host_no, 0x6);
-       if ((r_str(host_no) & 0xf0) != 0xf0) {
-               ppa_pb_release(host_no);
-               return 2;
-       }
-       w_ctr(host_no, 0x4);
-       if ((r_str(host_no) & 0xf0) != 0x80) {
-               ppa_pb_release(host_no);
-               return 3;
-       }
-       /* This is a SCSI reset signal */
-       w_dtr(host_no, 0x40);
-       w_ctr(host_no, 0x8);
-       udelay(50);
-       w_ctr(host_no, 0xc);
+static inline void ecp_sync(unsigned short ppb)
+{
+    int i;
 
-       ppa_disconnect(host_no);
+    if ((r_ecr(ppb) & 0xe0) != 0x80)
+       return;
 
-       return 0;
+    for (i = 0; i < 100; i++) {
+       if (r_ecr(ppb) & 0x01)
+           return;
+       udelay(5);
+    }
+    printk("ppa: ECP sync failed as data still present in FIFO.\n");
 }
 
-/* 
- * check the epp status. After a EPP transfer, it should be true that
- * 1) the TIMEOUT bit (SPP_STR.0) is clear
- * 2) the READY bit (SPP_STR.7) is set
+/*
+ * Here is the asm code for the SPP/PS2 protocols for the i386.
+ * This has been optimised for speed on 386/486 machines. There will
+ * be very little improvement on the current 586+ machines as it is the
+ * IO statements which will limit throughput.
  */
-static int ppa_check_epp_status(int host_no)
+#ifdef __i386__
+#define BYTE_OUT(reg) \
+       "       movb " #reg ",%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       addl $2,%%edx\n" \
+       "       movb $0x0e,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       movb $0x0c,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       subl $2,%%edx\n"
+
+static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int len)
 {
-       char r;
-       r = r_str(host_no);
-
-       if (r & 1) {
-               /* EPP timeout, according to the PC87332 manual */
-               /* Semantics of clearing EPP timeout bit.
-                * PC87332 - reading SPP_STR does it...
-                * SMC     - write 1 to EPP timeout bit
-                * Others  - (???) write 0 to EPP timeout bit
-                */
-               w_str(host_no, r);
-               w_str(host_no, r & 0xfe);
-               ppa_hosts[host_no].timeout++;
-               printk("PPA: EPP timeout on port 0x%04x\n",
-                      PPA_BASE(host_no));
-               ppa_fail(host_no, DID_BUS_BUSY);
-               return 0;
-       }
-       if (!(r & 0x80)) {
-               ppa_fail(host_no, DID_ERROR);
-               return 0;
-       }
-       return 1;
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_bo\n" \
+       "       .align 4\n" \
+       ".loop_bulk_bo:\n" \
+       "       movl (%%esi),%%ebx\n" \
+       BYTE_OUT(%%bl) \
+       BYTE_OUT(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       BYTE_OUT(%%bl) \
+       BYTE_OUT(%%bh) \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_bo\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_bo:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_bo\n" \
+       "       .align 4\n" \
+       ".loop_loose_bo:\n" \
+       BYTE_OUT((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_bo\n" \
+       ".no_more_loose_bo:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
 }
 
-static inline int ppa_force_epp_byte(int host_no, char x)
+#define BYTE_IN(reg) \
+       "       inb (%%dx),%%al\n" \
+       "       movb %%al," #reg "\n" \
+       "       addl $2,%%edx\n" \
+       "       movb $0x27,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       movb $0x25,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       subl $2,%%edx\n"
+
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
 {
-/* This routine forces a byte down the EPP data port whether the
- * device is ready or not...
- */
-       char r;
-
-       w_epp(host_no, x);
-
-       r = r_str(host_no);
-       if (!(r & 1))
-               return 1;
-
-       if (ppa_hosts[host_no].epp_speed > 0) {
-               /* EPP timeout, according to the PC87332 manual */
-               /* Semantics of clearing EPP timeout bit.
-                * PC87332 - reading SPP_STR does it...
-                * SMC     - write 1 to EPP timeout bit
-                * Others  - (???) write 0 to EPP timeout bit
-                */
-               w_str(host_no, r);
-               w_str(host_no, r & 0xfe);
-
-               /* Take a deep breath, count to 10 and then... */
-               udelay(ppa_hosts[host_no].epp_speed);
-
-               /* Second time around */
-               w_epp(host_no, x);
-
-               r = r_str(host_no);
-       }
-       if (r & 1) {
-               w_str(host_no, r);
-               w_str(host_no, r & 0xfe);
-               ppa_hosts[host_no].timeout++;
-               printk("PPA: warning: EPP timeout\n");
-               ppa_fail(host_no, DID_BUS_BUSY);
-               return 0;
-       } else
-               return 1;
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_bi\n" \
+       "       .align 4\n" \
+       ".loop_bulk_bi:\n" \
+       BYTE_IN(%%bl) \
+       BYTE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       BYTE_IN(%%bl) \
+       BYTE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       "       movl %%ebx,(%%esi)\n" \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_bi\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_bi:" \
+  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_bi\n" \
+       "       .align 4\n" \
+       ".loop_loose_bi:\n" \
+       BYTE_IN((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_bi\n" \
+       ".no_more_loose_bi:\n" \
+  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
 }
 
-static inline int ppa_send_command_epp(Scsi_Cmnd * cmd)
+#define NIBBLE_IN(reg) \
+       "       incl %%edx\n" \
+       "       movb $0x04,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       decl %%edx\n" \
+       "       inb (%%dx),%%al\n" \
+       "       andb $0xf0,%%al\n" \
+       "       movb %%al," #reg "\n" \
+       "       incl %%edx\n" \
+       "       movb $0x06,%%al\n" \
+       "       outb %%al,(%%dx)\n" \
+       "       decl %%edx\n" \
+       "       inb (%%dx),%%al\n" \
+       "       shrb $4,%%al\n" \
+       "       orb %%al," #reg "\n"
+
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
 {
-       int host_no = cmd->host->unique_id;
-       int k;
+    /*
+     * %eax scratch
+     * %ebx Data to transfer
+     * %ecx Counter (Don't touch!!)
+     * %edx Port
+     * %esi Source buffer (mem pointer)
+     *
+     * In case you are wondering what the last line of the asm does...
+     * <output allocation> : <input allocation> : <trashed registers>
+     */
+    asm("shr $2,%%ecx\n" \
+       "       jz .no_more_bulk_ni\n" \
+       "       .align 4\n" \
+       ".loop_bulk_ni:\n" \
+       NIBBLE_IN(%%bl) \
+       NIBBLE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       NIBBLE_IN(%%bl) \
+       NIBBLE_IN(%%bh) \
+       "       rorl $16,%%ebx\n" \
+       "       movl %%ebx,(%%esi)\n" \
+       "       addl $4,%%esi\n" \
+       "       loop .loop_bulk_ni\n" \
+       "       .align 4\n" \
+       ".no_more_bulk_ni:" \
+  : "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+
+    asm("andl $3,%%ecx\n" \
+       "       jz .no_more_loose_ni\n" \
+       "       .align 4\n" \
+       ".loop_loose_ni:\n" \
+       NIBBLE_IN((%%esi)) \
+       "       incl %%esi\n" \
+       "       loop .loop_loose_ni\n" \
+       ".no_more_loose_ni:\n" \
+  : /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+    return 1;                  /* All went well - we hope! */
+}
+#else                          /* Old style C routines */
 
-       w_ctr(host_no, 0x4);
-       for (k = 0; k < cmd->cmd_len; k++) {    /* send the command */
-               if (!ppa_force_epp_byte(host_no, cmd->cmnd[k]))
-                       return 0;
-       }
-       w_ctr(host_no, 0xc);
-       ecp_sync(host_no);
-       return 1;
+static inline int ppa_byte_out(unsigned short base, const char *buffer, int len)
+{
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+       outb(*buffer++, base);
+       outb(0xe, ctr_p);
+       outb(0xc, ctr_p);
+    }
+    return 1;                  /* All went well - we hope! */
 }
 
-static inline int ppa_send_command_normal(Scsi_Cmnd * cmd)
+static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
 {
-       int host_no = cmd->host->unique_id;
-       int k;
+    unsigned short ctr_p = base + 2;
+    int i;
+
+    for (i = len; i; i--) {
+       *buffer++ = inb(base);
+       outb(0x27, ctr_p);
+       outb(0x25, ctr_p);
+    }
+    return 1;                  /* All went well - we hope! */
+}
 
-       w_ctr(host_no, 0xc);
+static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
+{
+    unsigned short ctr_p = str_p + 1;
+    unsigned char h, l;
+    int i;
+
+    for (i = len; i; i--) {
+       outb(0x4, ctr_p);
+       h = inb(str_p);
+       outb(0x6, ctr_p);
+       l = inb(str_p);
+       *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
+    }
+    return 1;                  /* All went well - we hope! */
+}
+#endif
 
-       for (k = 0; k < cmd->cmd_len; k++) {    /* send the command */
-               if (!ppa_wait(host_no))
-                       return 0;
-               w_dtr(host_no, cmd->cmnd[k]);
-               w_ctr(host_no, 0xe);
-               w_ctr(host_no, 0xc);
-       }
-       return 1;
+static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--) {
+       outb(*buffer++, epp_p);
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2
+       if (inb(str_p) & 0x01)
+           return 0;
+#endif
+    }
+    return 1;
 }
 
-static int ppa_start(Scsi_Cmnd * cmd)
+static int ppa_out(int host_no, char *buffer, int len)
 {
-       int host_no = cmd->host->unique_id;
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
 
-       /* 
-        * by default, the command failed,
-        * unless explicitly completed in ppa_completion().
-        */
-       ppa_hosts[host_no].error_code = DID_ERROR;
-       ppa_hosts[host_no].abort_flag = 0;
-       ppa_hosts[host_no].ppa_failed = 0;
-
-       if (cmd->target == PPA_INITIATOR) {
-               ppa_hosts[host_no].error_code = DID_BAD_TARGET;
-               ppa_hosts[host_no].ppa_failed = 1;
-               return 0;
-       }
-       if (ppa_connect(host_no, CONNECT_EPP_MAYBE))
-               return 0;
+    r = ppa_wait(host_no);
 
-       if (!ppa_select(host_no, PPA_INITIATOR, cmd->target)) {
-               ppa_fail(host_no, DID_NO_CONNECT);
-               return 0;
-       }
-       if (IN_EPP_MODE(ppa_hosts[host_no].mode))
-               return ppa_send_command_epp(cmd);
+    if ((r & 0x50) != 0x40) {
+       ppa_fail(host_no, DID_ERROR);
+       return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+    case PPA_PS2:
+       /* 8 bit output, with a loop */
+       r = ppa_byte_out(ppb, buffer, len);
+       break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+       epp_reset(ppb);
+       w_ctr(ppb, 0x4);
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1
+       r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);
+#else
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0
+       if (!(((long) buffer | len) & 0x03))
+           outsl(ppb + 4, buffer, len >> 2);
        else
-               return ppa_send_command_normal(cmd);
+#endif
+           outsb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0xc);
+       r = !(r_str(ppb) & 0x01);
+#endif
+       w_ctr(ppb, 0xc);
+       ecp_sync(ppb);
+       break;
+
+    default:
+       printk("PPA: bug in ppa_out()\n");
+       r = 0;
+    }
+    return r;
 }
 
-/*
- * output a string, in whatever mode is available, according to the
- * PPA protocol. 
- */
-static inline int ppa_outs(int host_no, char *buffer, int len)
+static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len)
 {
-       int k;
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 0
-       int r;
+    int i;
+    for (i = len; i; i--) {
+       *buffer++ = inb(epp_p);
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2
+       if (inb(str_p) & 0x01)
+           return 0;
 #endif
+    }
+    return 1;
+}
 
-       switch (ppa_hosts[host_no].mode) {
-       case PPA_NIBBLE:
-       case PPA_PS2:
-               /* 8 bit output, with a loop */
-               for (k = len; k; k--) {
-                       w_dtr(host_no, *buffer++);
-                       w_ctr(host_no, 0xe);
-                       w_ctr(host_no, 0xc);
-               }
-               return 1;       /* assume transfer went OK */
+static int ppa_in(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = PPA_BASE(host_no);
 
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 0
-       case PPA_EPP_32:
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC < 2
-               w_ctr(host_no, 0x4);
-               for (k = len; k; k -= 4) {
-                       w_epp(host_no, *buffer++);
-                       w_epp(host_no, *buffer++);
-                       w_epp(host_no, *buffer++);
-                       w_epp(host_no, *buffer++);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return 1;
-#endif
-       case PPA_EPP_16:
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC < 3
-               w_ctr(host_no, 0x4);
-               for (k = len; k; k -= 2) {
-                       w_epp(host_no, *buffer++);
-                       w_epp(host_no, *buffer++);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return 1;
-#endif
-       case PPA_EPP_8:
-               w_ctr(host_no, 0x4);
-               for (k = len; k; k--) {
-                       w_epp(host_no, *buffer++);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return 1;
+    r = ppa_wait(host_no);
+
+    if ((r & 0x50) != 0x50) {
+       ppa_fail(host_no, DID_ERROR);
+       return 0;
+    }
+    switch (ppa_hosts[host_no].mode) {
+    case PPA_NIBBLE:
+       /* 4 bit input, with a loop */
+       r = ppa_nibble_in(ppb + 1, buffer, len);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case PPA_PS2:
+       /* 8 bit input, with a loop */
+       w_ctr(ppb, 0x25);
+       r = ppa_byte_in(ppb, buffer, len);
+       w_ctr(ppb, 0x4);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case PPA_EPP_32:
+    case PPA_EPP_16:
+    case PPA_EPP_8:
+       epp_reset(ppb);
+       w_ctr(ppb, 0x24);
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1
+       r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);
 #else
-       case PPA_EPP_32:
-       case PPA_EPP_16:
-       case PPA_EPP_8:
-               w_ctr(host_no, 0x4);
-               switch (ppa_hosts[host_no].mode) {
-               case PPA_EPP_8:
-                       outsb(PPA_BASE(host_no) + 0x04,
-                             buffer, len);
-                       break;
-               case PPA_EPP_16:
-                       outsw(PPA_BASE(host_no) + 0x04,
-                             buffer, len / 2);
-                       break;
-               case PPA_EPP_32:
-                       outsl(PPA_BASE(host_no) + 0x04,
-                             buffer, len / 4);
-                       break;
-               }
-               k = ppa_check_epp_status(host_no);
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return k;
+#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0
+       if (!(((long) buffer | len) & 0x03))
+           insl(ppb + 4, buffer, len >> 2);
+       else
+#endif
+           insb(ppb + 4, buffer, len);
+       w_ctr(ppb, 0x2c);
+       r = !(r_str(ppb) & 0x01);
 #endif
+       w_ctr(ppb, 0x2c);
+       ecp_sync(ppb);
+       break;
+
+    default:
+       printk("PPA: bug in ppa_ins()\n");
+       r = 0;
+       break;
+    }
+    return r;
+}
 
-       default:
-               printk("PPA: bug in ppa_outs()\n");
-       }
-       return 0;
+/* end of ppa_io.h */
+static inline void ppa_d_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
 }
 
-static inline int ppa_outb(int host_no, char d)
+static void ppa_disconnect(int host_no)
 {
-       int k;
+    unsigned short ppb = PPA_BASE(host_no);
 
-       switch (ppa_hosts[host_no].mode) {
-       case PPA_NIBBLE:
-       case PPA_PS2:
-               w_dtr(host_no, d);
-               w_ctr(host_no, 0xe);
-               w_ctr(host_no, 0xc);
-               return 1;       /* assume transfer went OK */
+    ppa_d_pulse(ppb, 0);
+    ppa_d_pulse(ppb, 0x3c);
+    ppa_d_pulse(ppb, 0x20);
+    ppa_d_pulse(ppb, 0xf);
+}
 
-       case PPA_EPP_8:
-       case PPA_EPP_16:
-       case PPA_EPP_32:
-               w_ctr(host_no, 0x4);
-               w_epp(host_no, d);
-               k = ppa_check_epp_status(host_no);
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return k;
-
-       default:
-               printk("PPA: bug in ppa_outb()\n");
-       }
+static inline void ppa_c_pulse(unsigned short ppb, unsigned char b)
+{
+    w_dtr(ppb, b);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0x6);
+    w_ctr(ppb, 0x4);
+    w_ctr(ppb, 0xc);
+}
+
+static inline void ppa_connect(int host_no, int flag)
+{
+    unsigned short ppb = PPA_BASE(host_no);
+
+    ppa_c_pulse(ppb, 0);
+    ppa_c_pulse(ppb, 0x3c);
+    ppa_c_pulse(ppb, 0x20);
+    if ((flag == CONNECT_EPP_MAYBE) &&
+       IN_EPP_MODE(ppa_hosts[host_no].mode))
+       ppa_c_pulse(ppb, 0xcf);
+    else
+       ppa_c_pulse(ppb, 0x8f);
+}
+
+static int ppa_select(int host_no, int target)
+{
+    int k;
+    unsigned short ppb = PPA_BASE(host_no);
+
+    /*
+     * Bit 6 (0x40) is the device selected bit.
+     * First we must wait till the current device goes off line...
+     */
+    k = PPA_SELECT_TMO;
+    do {
+       k--;
+    } while ((r_str(ppb) & 0x40) && (k));
+    if (!k)
        return 0;
+
+    w_dtr(ppb, (1 << target));
+    w_ctr(ppb, 0xe);
+    w_ctr(ppb, 0xc);
+    w_dtr(ppb, 0x80);          /* This is NOT the initator */
+    w_ctr(ppb, 0x8);
+
+    k = PPA_SELECT_TMO;
+    do {
+       k--;
+    }
+    while (!(r_str(ppb) & 0x40) && (k));
+    if (!k)
+       return 0;
+
+    return 1;
 }
 
-static inline int ppa_ins(int host_no, char *buffer, int len)
+/* 
+ * This is based on a trace of what the Iomega DOS 'guest' driver does.
+ * I've tried several different kinds of parallel ports with guest and
+ * coded this to react in the same ways that it does.
+ * 
+ * The return value from this function is just a hint about where the
+ * handshaking failed.
+ * 
+ */
+static int ppa_init(int host_no)
 {
-       int k, h, l;
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 0
-       int r;
+    int retv;
+    unsigned short ppb = PPA_BASE(host_no);
+
+#if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE)
+    if (ppa_pb_claim(host_no))
+       while (ppa_hosts[host_no].p_busy)
+           schedule(); /* Whe can safe schedule() here */
 #endif
 
-       switch (ppa_hosts[host_no].mode) {
-       case PPA_NIBBLE:
-               /* 4 bit input, with a loop */
-               for (k = len; k; k--) {
-                       w_ctr(host_no, 0x4);
-                       h = r_str(host_no);
-                       w_ctr(host_no, 0x6);
-                       l = r_str(host_no);
-                       *buffer++ = ((l >> 4) & 0x0f) + (h & 0xf0);
-               }
-               w_ctr(host_no, 0xc);
-               return 1;       /* assume transfer went OK */
+    ppa_disconnect(host_no);
+    ppa_connect(host_no, CONNECT_NORMAL);
 
-       case PPA_PS2:
-               /* 8 bit input, with a loop */
-               for (k = len; k; k--) {
-                       w_ctr(host_no, 0x25);
-                       *buffer++ = r_dtr(host_no);
-                       w_ctr(host_no, 0x27);
-               }
-               w_ctr(host_no, 0x5);
-               w_ctr(host_no, 0x4);
-               w_ctr(host_no, 0xc);
-               return 1;       /* assume transfer went OK */
+    retv = 2;                  /* Failed */
 
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 0
-       case PPA_EPP_32:
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC < 2
-               w_ctr(host_no, 0x24);
-               for (k = len; k; k -= 4) {
-                       *buffer++ = r_epp(host_no);
-                       *buffer++ = r_epp(host_no);
-                       *buffer++ = r_epp(host_no);
-                       *buffer++ = r_epp(host_no);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0x2c);
-               ecp_sync(host_no);
-               return 1;
-#endif
-       case PPA_EPP_16:
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC < 3
-               w_ctr(host_no, 0x24);
-               for (k = len; k; k -= 2) {
-                       *buffer++ = r_epp(host_no);
-                       *buffer++ = r_epp(host_no);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0x2c);
-               ecp_sync(host_no);
-               return 1;
-#endif
-       case PPA_EPP_8:
-               w_ctr(host_no, 0x24);
-               for (k = len; k; k--) {
-                       *buffer++ = r_epp(host_no);
-                       r = ppa_check_epp_status(host_no);
-                       if (!r)
-                               return r;
-               }
-               w_ctr(host_no, 0x2c);
-               ecp_sync(host_no);
-               return 1;
-               break;
-#else
-       case PPA_EPP_8:
-       case PPA_EPP_16:
-       case PPA_EPP_32:
-               w_ctr(host_no, 0x24);
-               switch (ppa_hosts[host_no].mode) {
-               case PPA_EPP_8:
-                       insb(PPA_BASE(host_no) + 0x04,
-                            buffer, len);
-                       break;
-               case PPA_EPP_16:
-                       insw(PPA_BASE(host_no) + 0x04,
-                            buffer, len / 2);
-                       break;
-               case PPA_EPP_32:
-                       insl(PPA_BASE(host_no) + 0x04,
-                            buffer, len / 4);
-                       break;
-               }
-               k = ppa_check_epp_status(host_no);
-               w_ctr(host_no, 0x2c);
-               ecp_sync(host_no);
-               return k;
-#endif
+    w_ctr(ppb, 0xe);
+    if ((r_str(ppb) & 0x08) == 0x08)
+       retv--;
 
-       default:
-               printk("PPA: bug in ppa_ins()\n");
-       }
-       return 0;
+    w_ctr(ppb, 0xc);
+    if ((r_str(ppb) & 0x08) == 0x00)
+       retv--;
+
+    /* This is a SCSI BUS reset signal */
+    if (!retv) {
+       w_dtr(ppb, 0x40);
+       w_ctr(ppb, 0x08);
+       udelay(30);
+       w_ctr(ppb, 0x0c);
+       udelay(1000);           /* Allow devices to settle down */
+    }
+    ppa_disconnect(host_no);
+    udelay(1000);              /* Another delay to allow devices to settle */
+
+    if (!retv)
+       retv = device_check(host_no);
+
+    ppa_pb_release(host_no);
+    return retv;
 }
 
-static int ppa_inb(int host_no, char *buffer)
+static inline int ppa_send_command(Scsi_Cmnd * cmd)
 {
-       int h, l, k;
+    int host_no = cmd->host->unique_id;
+    int k;
 
-       switch (ppa_hosts[host_no].mode) {
-       case PPA_NIBBLE:
-               /* 4 bit input */
-               w_ctr(host_no, 0x4);
-               h = r_str(host_no);
-               w_ctr(host_no, 0x6);
-               l = r_str(host_no);
-               *buffer = ((l >> 4) & 0x0f) + (h & 0xf0);
-               w_ctr(host_no, 0xc);
-               return 1;       /* assume transfer went OK */
+    w_ctr(PPA_BASE(host_no), 0x0c);
 
-       case PPA_PS2:
-               /* 8 bit input */
-               w_ctr(host_no, 0x25);
-               *buffer++ = r_dtr(host_no);
-               w_ctr(host_no, 0x27);
-               w_ctr(host_no, 0x5);
-               w_ctr(host_no, 0x4);
-               w_ctr(host_no, 0xc);
-               return 1;       /* assume transfer went OK */
-
-       case PPA_EPP_8:
-       case PPA_EPP_16:
-       case PPA_EPP_32:
-               w_ctr(host_no, 0x24);
-               *buffer = r_epp(host_no);
-               k = ppa_check_epp_status(host_no);
-               w_ctr(host_no, 0xc);
-               ecp_sync(host_no);
-               return k;
-
-       default:
-               printk("PPA: bug in ppa_inb()\n");
-       }
-       return 0;
+    for (k = 0; k < cmd->cmd_len; k++)
+       if (!ppa_out(host_no, &cmd->cmnd[k], 1))
+           return 0;
+    return 1;
 }
 
 /*
@@ -867,115 +845,107 @@ static int ppa_inb(int host_no, char *buffer)
  */
 static int ppa_completion(Scsi_Cmnd * cmd)
 {
-       int host_no = cmd->host->unique_id;
-
-       char r, l, h, v;
-       int dir, cnt, blen, fast, bulk, status;
-       char *buffer;
-       struct scatterlist *sl;
-       int current_segment, nsegment;
-
-       v = cmd->cmnd[0];
-       bulk = ((v == READ_6) ||
-               (v == READ_10) ||
-               (v == WRITE_6) ||
-               (v == WRITE_10));
-
-       /* code for scatter/gather: */
-       if (cmd->use_sg) {
-               /* if many buffers are available, start filling the first */
-               sl = (struct scatterlist *) cmd->request_buffer;
-               blen = sl->length;
-               buffer = sl->address;
-       } else {
-               /* else fill the only available buffer */
-               sl = NULL;
-               buffer = cmd->request_buffer;
-               blen = cmd->request_bufflen;
-       }
-       current_segment = 0;
-       nsegment = cmd->use_sg;
-
-       cnt = 0;
-
-       /* detect transfer direction */
-       dir = 0;
-       if (!(r = ppa_wait(host_no)))
-               return 0;
-       if (r == (char) 0xc0)
-               dir = 1;        /* d0 = read c0 = write f0 = status */
-
-       while (r != (char) 0xf0) {
-               if (((r & 0xc0) != 0xc0) || (cnt >= blen)) {
-                       ppa_fail(host_no, DID_ERROR);
-                       return 0;
-               }
-               /* determine if we should use burst I/O */
-               fast = (bulk && ((blen - cnt) >= PPA_BURST_SIZE) &&
-                       ((((long)buffer + cnt)) & 0x3) == 0);
-
-               if (fast) {
-                       if (dir)
-                               status = ppa_outs(host_no, &buffer[cnt], PPA_BURST_SIZE);
-                       else
-                               status = ppa_ins(host_no, &buffer[cnt], PPA_BURST_SIZE);
-                       cnt += PPA_BURST_SIZE;
-               } else {
-                       if (dir)
-                               status = ppa_outb(host_no, buffer[cnt]);
-                       else
-                               status = ppa_inb(host_no, &buffer[cnt]);
-                       cnt++;
-               }
+    /* Return codes:
+     * -1     Error
+     *  0     Told to schedule
+     *  1     Finished data transfer
+     */
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned long start_jiffies = jiffies;
+
+    unsigned char r, v;
+    int fast, bulk, status;
+
+    v = cmd->cmnd[0];
+    bulk = ((v == READ_6) ||
+           (v == READ_10) ||
+           (v == WRITE_6) ||
+           (v == WRITE_10));
+
+    /*
+     * We only get here if the drive is ready to comunicate,
+     * hence no need for a full ppa_wait.
+     */
+    r = (r_str(ppb) & 0xf0);
+
+    while (r != (unsigned char) 0xf0) {
+       /*
+        * If we have been running for more than a full timer tick
+        * then take a rest.
+        */
+       if (jiffies > start_jiffies + 1)
+           return 0;
 
-               if (!status || !(r = ppa_wait(host_no)))
-                       return 0;
-
-               if (sl && cnt == blen) {
-                       /* if scatter/gather, advance to the next segment */
-                       if (++current_segment < nsegment) {
-                               ++sl;
-                               blen = sl->length;
-                               buffer = sl->address;
-                               cnt = 0;
-                       }
-                       /*
-                        * the else case will be captured by the (cnt >= blen)
-                        * test above.
-                        */
-               }
+       if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+           ppa_fail(host_no, DID_ERROR);
+           return -1;          /* ERROR_RETURN */
        }
+       /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+           ? PPA_BURST_SIZE : 1;
 
-       /* read status and message bytes */
-       if (!ppa_inb(host_no, &l))      /* read status byte */
-               return 0;
-       if (!(ppa_wait(host_no)))
-               return 0;
-       if (!ppa_inb(host_no, &h))      /* read message byte */
-               return 0;
+       if (r == (unsigned char) 0xc0)
+           status = ppa_out(host_no, cmd->SCp.ptr, fast);
+       else
+           status = ppa_in(host_no, cmd->SCp.ptr, fast);
 
-       ppa_disconnect(host_no);
+       cmd->SCp.ptr += fast;
+       cmd->SCp.this_residual -= fast;
 
-       ppa_hosts[host_no].error_code = DID_OK;
-       return (h << 8) | (l & STATUS_MASK);
+       if (!status) {
+           ppa_fail(host_no, DID_BUS_BUSY);
+           return -1;          /* ERROR_RETURN */
+       }
+       if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+           /* if scatter/gather, advance to the next segment */
+           if (cmd->SCp.buffers_residual--) {
+               cmd->SCp.buffer++;
+               cmd->SCp.this_residual = cmd->SCp.buffer->length;
+               cmd->SCp.ptr = cmd->SCp.buffer->address;
+           }
+       }
+       /* Now check to see if the drive is ready to comunicate */
+       r = (r_str(ppb) & 0xf0);
+       /* If not, drop back down to the scheduler and wait a timer tick */
+       if (!(r & 0x80))
+           return 0;
+    }
+    return 1;                  /* FINISH_RETURN */
 }
 
 /* deprecated synchronous interface */
-
 int ppa_command(Scsi_Cmnd * cmd)
 {
-       int host_no = cmd->host->unique_id;
-       int s;
-
-       sti();
-       s = 0;
-       if (ppa_start(cmd))
-               if (ppa_wait(host_no))
-                       s = ppa_completion(cmd);
-       return s + (ppa_hosts[host_no].error_code << 16);
+    static int first_pass = 1;
+    int host_no = cmd->host->unique_id;
+
+    if (first_pass) {
+       printk("ppa: using non-queuing interface\n");
+       first_pass = 0;
+    }
+    if (ppa_hosts[host_no].cur_cmd) {
+       printk("PPA: bug in ppa_command\n");
+       return 0;
+    }
+    ppa_hosts[host_no].failed = 0;
+    ppa_hosts[host_no].jstart = jiffies;
+    ppa_hosts[host_no].cur_cmd = cmd;
+    cmd->result = DID_ERROR << 16;     /* default return code */
+    cmd->SCp.phase = 0;
+
+    ppa_pb_claim(host_no);
+
+    while (ppa_engine(&ppa_hosts[host_no], cmd))
+       schedule();
+
+    if (cmd->SCp.phase)                /* Only disconnect if we have connected */
+       ppa_disconnect(cmd->host->unique_id);
+
+    ppa_pb_release(host_no);
+    ppa_hosts[host_no].cur_cmd = 0;
+    return cmd->result;
 }
 
-/* pseudo-interrupt queueing interface */
 /*
  * Since the PPA itself doesn't generate interrupts, we use
  * the scheduler's task queue to generate a stream of call-backs and
@@ -983,82 +953,198 @@ int ppa_command(Scsi_Cmnd * cmd)
  */
 static void ppa_interrupt(void *data)
 {
-       ppa_struct *tmp = (ppa_struct *) data;
-       Scsi_Cmnd *cmd = tmp->cur_cmd;
-       void (*done) (Scsi_Cmnd *) = tmp->done;
-       int host_no = cmd->host->unique_id;
-
-       if (!cmd) {
-               printk("PPA: bug in ppa_interrupt\n");
-               return;
-       }
-       /* First check for any errors that may of occured
-        * Here we check for internal errors
-        */
-       if (tmp->ppa_failed) {
-               printk("PPA: ppa_failed bug: ppa_error_code = %d\n",
-                      tmp->error_code);
-               cmd->result = DID_ERROR << 16;
-               tmp->cur_cmd = 0;
-               done(cmd);
-               return;
+    ppa_struct *tmp = (ppa_struct *) data;
+    Scsi_Cmnd *cmd = tmp->cur_cmd;
+
+    if (!cmd) {
+       printk("PPA: bug in ppa_interrupt\n");
+       return;
+    }
+    if (ppa_engine(tmp, cmd)) {
+       tmp->ppa_tq.data = (void *) tmp;
+       tmp->ppa_tq.sync = 0;
+       queue_task(&tmp->ppa_tq, &tq_timer);
+       return;
+    }
+    /* Command must of completed hence it is safe to let go... */
+#if PPA_DEBUG > 0
+    switch ((cmd->result >> 16) & 0xff) {
+    case DID_OK:
+       break;
+    case DID_NO_CONNECT:
+       printk("ppa: no device at SCSI ID %i\n", cmd->target);
+       break;
+    case DID_BUS_BUSY:
+       printk("ppa: BUS BUSY - EPP timeout detected\n");
+       break;
+    case DID_TIME_OUT:
+       printk("ppa: unknown timeout\n");
+       break;
+    case DID_ABORT:
+       printk("ppa: told to abort\n");
+       break;
+    case DID_PARITY:
+       printk("ppa: parity error (???)\n");
+       break;
+    case DID_ERROR:
+       printk("ppa: internal driver error\n");
+       break;
+    case DID_RESET:
+       printk("ppa: told to reset device\n");
+       break;
+    case DID_BAD_INTR:
+       printk("ppa: bad interrupt (???)\n");
+       break;
+    default:
+       printk("ppa: bad return code (%02x)\n", (cmd->result >> 16) & 0xff);
+    }
+#endif
+
+    ppa_disconnect(cmd->host->unique_id);
+    ppa_pb_release(cmd->host->unique_id);
+    tmp->cur_cmd = 0;
+    cmd->scsi_done(cmd);
+    return;
+}
+
+static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = PPA_BASE(host_no);
+    unsigned char l = 0, h = 0;
+    int retv;
+
+    /* First check for any errors that may of occured
+     * Here we check for internal errors
+     */
+    if (tmp->failed)
+       return 0;
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Phase 0 - Waiting for parport */
+       if ((jiffies - tmp->jstart) > HZ) {
+           /*
+            * We waited more than a second
+            * for parport to call us
+            */
+           ppa_fail(host_no, DID_BUS_BUSY);
+           return 0;
        }
-       /* Occasionally the mid level driver will abort a SCSI
-        * command because we are taking to long, if this occurs
-        * we should abort the command.
-        */
-       if (tmp->abort_flag) {
-               ppa_disconnect(host_no);
-               if (tmp->abort_flag == 1)
-                       cmd->result = DID_ABORT << 16;
-               else {
-                       ppa_do_reset(host_no);
-                       cmd->result = DID_RESET << 16;
+       return 1; /* wait that ppa_wakeup claims parport */
+    case 1:                    /* Phase 1 - Connected */
+       {                       /* Perform a sanity check for cable unplugged */
+           int retv = 2;       /* Failed */
+
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+
+           w_ctr(ppb, 0xe);
+           if ((r_str(ppb) & 0x08) == 0x08)
+               retv--;
+
+           w_ctr(ppb, 0xc);
+           if ((r_str(ppb) & 0x08) == 0x00)
+               retv--;
+
+           if (retv)
+               if ((jiffies - tmp->jstart) > (1 * HZ)) {
+                   printk("ppa: Parallel port cable is unplugged!!\n");
+                   ppa_fail(host_no, DID_BUS_BUSY);
+                   return 0;
+               } else {
+                   ppa_disconnect(host_no);
+                   return 1;   /* Try again in a jiffy */
                }
-               tmp->cur_cmd = 0;
-               done(cmd);
-               return;
+           cmd->SCp.phase++;
        }
-       /* Check to see if the device is now free, if not
-        * then throw this function onto the scheduler queue
-        * to be called back in a jiffy.
-        * (i386: 1 jiffy = 0.01 seconds)
-        */
-       if (!(r_str(host_no) & 0x80)) {
-               tmp->ppa_tq.data = (void *) tmp;
-               queue_task(&tmp->ppa_tq, &tq_scheduler);
-               return;
+
+    case 2:                    /* Phase 2 - We are now talking to the scsi bus */
+       if (!ppa_select(host_no, cmd->target)) {
+           ppa_fail(host_no, DID_NO_CONNECT);
+           return 0;
        }
-       /* Device is now free and no errors have occured so
-        * it is safe to do the data phase
-        */
-       cmd->result = ppa_completion(cmd) + (tmp->error_code << 16);
-       tmp->cur_cmd = 0;
-       done(cmd);
-       return;
-}
+       cmd->SCp.phase++;
 
-int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-       int host_no = cmd->host->unique_id;
+    case 3:                    /* Phase 3 - Ready to accept a command */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       if (!ppa_send_command(cmd))
+           return 0;
+       cmd->SCp.phase++;
 
-       if (ppa_hosts[host_no].cur_cmd) {
-               printk("PPA: bug in ppa_queuecommand\n");
-               return 0;
+    case 4:                    /* Phase 4 - Setup scatter/gather buffers */
+       if (cmd->use_sg) {
+           /* if many buffers are available, start filling the first */
+           cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+           cmd->SCp.this_residual = cmd->SCp.buffer->length;
+           cmd->SCp.ptr = cmd->SCp.buffer->address;
+       } else {
+           /* else fill the only available buffer */
+           cmd->SCp.buffer = NULL;
+           cmd->SCp.this_residual = cmd->request_bufflen;
+           cmd->SCp.ptr = cmd->request_buffer;
+       }
+       cmd->SCp.buffers_residual = cmd->use_sg;
+       cmd->SCp.phase++;
+
+    case 5:                    /* Phase 5 - Data transfer stage */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       retv = ppa_completion(cmd);
+       if (retv == -1)
+           return 0;
+       if (retv == 0)
+           return 1;
+       cmd->SCp.phase++;
+
+    case 6:                    /* Phase 6 - Read status/message */
+       cmd->result = DID_OK << 16;
+       /* Check for data overrun */
+       if (ppa_wait(host_no) != (unsigned char) 0xf0) {
+           ppa_fail(host_no, DID_ERROR);
+           return 0;
        }
-       sti();
-       ppa_hosts[host_no].cur_cmd = cmd;
-       ppa_hosts[host_no].done = done;
-
-       if (!ppa_start(cmd)) {
-               cmd->result = ppa_hosts[host_no].error_code << 16;
-               ppa_hosts[host_no].cur_cmd = 0;
-               done(cmd);
-               return 0;
+       if (ppa_in(host_no, &l, 1)) {   /* read status byte */
+           /* Check for optional message byte */
+           if (ppa_wait(host_no) == (unsigned char) 0xf0)
+               ppa_in(host_no, &h, 1);
+           cmd->result = (DID_OK << 16) + (h << 8) + (l & STATUS_MASK);
        }
-       ppa_interrupt(ppa_hosts + host_no);
+       return 0;               /* Finished */
+       break;
 
+    default:
+       printk("ppa: Invalid scsi phase\n");
+    }
+    return 0;
+}
+
+int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+    int host_no = cmd->host->unique_id;
+
+    if (ppa_hosts[host_no].cur_cmd) {
+       printk("PPA: bug in ppa_queuecommand\n");
        return 0;
+    }
+    ppa_hosts[host_no].failed = 0;
+    ppa_hosts[host_no].jstart = jiffies;
+    ppa_hosts[host_no].cur_cmd = cmd;
+    cmd->scsi_done = done;
+    cmd->result = DID_ERROR << 16;     /* default return code */
+    cmd->SCp.phase = 0;                /* bus free */
+
+    ppa_pb_claim(host_no);
+
+    ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no;
+    ppa_hosts[host_no].ppa_tq.sync = 0;
+    queue_task(&ppa_hosts[host_no].ppa_tq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+
+    return 0;
 }
 
 /*
@@ -1069,263 +1155,166 @@ int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
  */
 int ppa_biosparam(Disk * disk, kdev_t dev, int ip[])
 {
-       ip[0] = 0x40;
-       ip[1] = 0x20;
+    ip[0] = 0x40;
+    ip[1] = 0x20;
+    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    if (ip[2] > 1024) {
+       ip[0] = 0xff;
+       ip[1] = 0x3f;
        ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
-       if (ip[2] > 1024) {
-               ip[0] = 0xff;
-               ip[1] = 0x3f;
-               ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
-               if (ip[2] > 1023)
-                       ip[2] = 1023;
-       }
-       return 0;
+       if (ip[2] > 1023)
+           ip[2] = 1023;
+    }
+    return 0;
 }
 
 int ppa_abort(Scsi_Cmnd * cmd)
 {
-       int host_no = cmd->host->unique_id;
-
-       ppa_hosts[host_no].abort_flag = 1;
-       ppa_hosts[host_no].error_code = DID_ABORT;
-       if (ppa_hosts[host_no].ppa_wait_q)
-               wake_up(&ppa_hosts[host_no].ppa_wait_q);
-
-       return SCSI_ABORT_SNOOZE;
+    /*
+     * There is no method for aborting commands since Iomega
+     * have tied the SCSI_MESSAGE line high in the interface
+     */
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Do not have access to parport */
+    case 1:                    /* Have not connected to interface */
+       cmd->result = DID_ABORT;
+       cmd->done(cmd);
+       return SCSI_ABORT_SUCCESS;
+       break;
+    default:                   /* SCSI command sent, can not abort */
+       return SCSI_ABORT_BUSY;
+       break;
+    }
 }
 
 int ppa_reset(Scsi_Cmnd * cmd, unsigned int x)
 {
-       int host_no = cmd->host->unique_id;
-
-       ppa_hosts[host_no].abort_flag = 2;
-       ppa_hosts[host_no].error_code = DID_RESET;
-       if (ppa_hosts[host_no].ppa_wait_q)
-               wake_up(&ppa_hosts[host_no].ppa_wait_q);
-
-       return SCSI_RESET_PUNT;
+    int host_no = cmd->host->unique_id;
+    int ppb = PPA_BASE(host_no);
+
+    /*
+     * PHASE1:
+     * Bring the interface crashing down on whatever is running
+     * hopefully this will kill the request.
+     * Bring back up the interface, reset the drive (and anything
+     * attached for that manner)
+     */
+    if (cmd)
+       if (cmd->SCp.phase)
+           ppa_disconnect(cmd->host->unique_id);
+
+    ppa_connect(host_no, CONNECT_NORMAL);
+    w_dtr(ppb, 0x40);
+    w_ctr(ppb, 0x8);
+    udelay(30);
+    w_ctr(ppb, 0xc);
+    udelay(1000);              /* delay for devices to settle down */
+    ppa_disconnect(host_no);
+    udelay(1000);              /* Additional delay to allow devices to settle down */
+
+    /*
+     * PHASE2:
+     * Sanity check for the sake of mid-level driver
+     */
+    if (!cmd) {
+       printk("ppa bus reset called for invalid command.\n");
+       return SCSI_RESET_NOT_RUNNING;
+    }
+    /*
+     * PHASE3:
+     * Flag the current command as having died due to reset
+     */
+    ppa_connect(host_no, CONNECT_NORMAL);
+    ppa_fail(host_no, DID_RESET);
+
+    /* Since the command was already on the timer queue ppa_interrupt
+     * will be called shortly.
+     */
+    return SCSI_RESET_PENDING;
 }
 
-
-
-/***************************************************************************
- *                   Parallel port probing routines                        *
- ***************************************************************************/
-
-
-#ifdef MODULE
-Scsi_Host_Template driver_template = PPA;
-#include  "scsi_module.c"
-#endif
-
-/*
- * Start of Chipset kludges
- */
-
-int ppa_detect(Scsi_Host_Template * host)
-{
-       struct Scsi_Host *hreg;
-       int rs;
-       int ports;
-       int i, nhosts;
-       struct parport *pb = parport_enumerate();
-
-       printk("PPA driver version: %s\n", PPA_VERSION);
-       nhosts = 0;
-
-       for (i = 0; pb; i++, pb=pb->next) {
-               int modes = pb->modes;
-
-               /* We only understand PC-style ports */
-               if (modes & PARPORT_MODE_PCSPP) {
-
-                       /* transfer global values here */
-                       if (ppa_speed >= 0)
-                               ppa_hosts[i].speed = ppa_speed;
-                       if (ppa_speed_fast >= 0)
-                               ppa_hosts[i].speed_fast = ppa_speed_fast;
-                       
-                       ppa_hosts[i].dev = parport_register_device(pb, "ppa", 
-                                   NULL, ppa_wakeup, NULL,
-                                   PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]);
-                       
-                       /* Claim the bus so it remembers what we do to the
-                        * control registers. [ CTR and ECP ]
-                        */
-                       ppa_pb_claim(i);
-                       w_ctr(i, 0x0c);
-
-                       ppa_hosts[i].mode = PPA_NIBBLE;
-                       if (modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP)) {
-                               ppa_hosts[i].mode = PPA_EPP_32;
-                               printk("PPA: Parport [ PCEPP ]\n");
-                       } else if (modes & PARPORT_MODE_PCECP) {
-                               w_ecr(i, 0x20);
-                               ppa_hosts[i].mode = PPA_PS2;
-                               printk("PPA: Parport [ PCECP in PS2 submode ]\n");
-                       } else if (modes & PARPORT_MODE_PCPS2) {
-                               ppa_hosts[i].mode = PPA_PS2;
-                               printk("PPA: Parport [ PCPS2 ]\n");
-                       }
-                       /* Done configuration */
-                       ppa_pb_release(i);
-
-                       rs = ppa_init(i);
-                       if (rs) {
-                               parport_unregister_device(ppa_hosts[i].dev);
-                               continue;
-                       }
-                       /* now the glue ... */
-                       switch (ppa_hosts[i].mode) {
-                       case PPA_NIBBLE:
-                       case PPA_PS2:
-                               ports = 3;
-                               break;
-                       case PPA_EPP_8:
-                       case PPA_EPP_16:
-                       case PPA_EPP_32:
-                               ports = 8;
-                               break;
-                       default:        /* Never gets here */
-                               continue;
-                       }
-                       
-                       host->can_queue = PPA_CAN_QUEUE;
-                       host->sg_tablesize = ppa_sg;
-                       hreg = scsi_register(host, 0);
-                       hreg->io_port = pb->base;
-                       hreg->n_io_port = ports;
-                       hreg->dma_channel = -1;
-                       hreg->unique_id = i;
-                       ppa_hosts[i].host = hreg->host_no;
-                       nhosts++;
-               }
-       }
-       if (nhosts == 0)
-               return 0;
-       else
-               return 1;       /* return number of hosts detected */
-}
-
-/* This is to give the ppa driver a way to modify the timings (and other
- * parameters) by writing to the /proc/scsi/ppa/0 file.
- * Very simple method really... (To simple, no error checking :( )
- * Reason: Kernel hackers HATE having to unload and reload modules for
- * testing...
- * Also gives a method to use a script to obtain optimum timings (TODO)
- */
-
-static int ppa_strncmp(const char *a, const char *b, int len)
+static int device_check(int host_no)
 {
-       int loop;
-       for (loop = 0; loop < len; loop++)
-               if (a[loop] != b[loop])
-                       return 1;
-
-       return 0;
-}
-
-static int ppa_proc_write(int hostno, char *buffer, int length)
-{
-       unsigned long x;
-       const char *inv_num = "ppa /proc entry passed invalid number\n";
-
-       if ((length > 15) && (ppa_strncmp(buffer, "ppa_speed_fast=", 15) == 0)) {
-               x = simple_strtoul(buffer + 15, NULL, 0);
-               if (x <= ppa_hosts[hostno].speed)
-                       ppa_hosts[hostno].speed_fast = x;
-               else
-                       printk(inv_num);
-               return length;
-       }
-       if ((length > 10) && (ppa_strncmp(buffer, "ppa_speed=", 10) == 0)) {
-               x = simple_strtoul(buffer + 10, NULL, 0);
-               if (x >= ppa_hosts[hostno].speed_fast)
-                       ppa_hosts[hostno].speed = x;
-               else
-                       printk(inv_num);
-               return length;
+    /* This routine looks for a device and then attempts to use EPP
+       to send a command. If all goes as planned then EPP is available. */
+
+    static char cmd[6] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    int loop, old_mode, status, k, ppb = PPA_BASE(host_no);
+    unsigned char l;
+
+    old_mode = ppa_hosts[host_no].mode;
+    for (loop = 0; loop < 8; loop++) {
+       /* Attempt to use EPP for Test Unit Ready */
+       if ((ppb & 0x0007) == 0x0000)
+           ppa_hosts[host_no].mode = PPA_EPP_32;
+
+      second_pass:
+       ppa_connect(host_no, CONNECT_EPP_MAYBE);
+       /* Select SCSI device */
+       if (!ppa_select(host_no, loop)) {
+           ppa_disconnect(host_no);
+           continue;
        }
-       if ((length > 10) && (ppa_strncmp(buffer, "epp_speed=", 10) == 0)) {
-               x = simple_strtoul(buffer + 10, NULL, 0);
-               ppa_hosts[hostno].epp_speed = x;
-               return length;
+       printk("ppa: Found device at ID %i, Attempting to use %s\n", loop,
+              PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+
+       /* Send SCSI command */
+       status = 1;
+       w_ctr(ppb, 0x0c);
+       for (l = 0; (l < 6) && (status); l++)
+           status = ppa_out(host_no, cmd, 1);
+
+       if (!status) {
+           ppa_disconnect(host_no);
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+           w_dtr(ppb, 0x40);
+           w_ctr(ppb, 0x08);
+           udelay(30);
+           w_ctr(ppb, 0x0c);
+           udelay(1000);
+           ppa_disconnect(host_no);
+           udelay(1000);
+           if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+               ppa_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("ppa: Unable to establish communication, aborting driver load.\n");
+           return 1;
        }
-       if ((length > 12) && (ppa_strncmp(buffer, "epp_timeout=", 12) == 0)) {
-               x = simple_strtoul(buffer + 12, NULL, 0);
-               ppa_hosts[hostno].timeout = x;
-               return length;
+       w_ctr(ppb, 0x0c);
+       k = 1000000;            /* 1 Second */
+       do {
+           l = r_str(ppb);
+           k--;
+           udelay(1);
+       } while (!(l & 0x80) && (k));
+
+       l &= 0xf0;
+
+       if (l != 0xf0) {
+           ppa_disconnect(host_no);
+           ppa_connect(host_no, CONNECT_EPP_MAYBE);
+           w_dtr(ppb, 0x40);
+           w_ctr(ppb, 0x08);
+           udelay(30);
+           w_ctr(ppb, 0x0c);
+           udelay(1000);
+           ppa_disconnect(host_no);
+           udelay(1000);
+           if (ppa_hosts[host_no].mode == PPA_EPP_32) {
+               ppa_hosts[host_no].mode = old_mode;
+               goto second_pass;
+           }
+           printk("ppa: Unable to establish communication, aborting driver load.\n");
+           return 1;
        }
-       if ((length > 5) && (ppa_strncmp(buffer, "mode=", 5) == 0)) {
-               x = simple_strtoul(buffer + 5, NULL, 0);
-               ppa_hosts[hostno].mode = x;
-               return length;
-       }
-       printk("ppa /proc: invalid variable\n");
-       return (-EINVAL);
-}
-
-int ppa_proc_info(char *buffer, char **start, off_t offset,
-                 int length, int hostno, int inout)
-{
-       int i;
-       int size, len = 0;
-       off_t begin = 0;
-       off_t pos = 0;
-
-       for (i = 0; i < 4; i++)
-               if (ppa_hosts[i].host == hostno)
-                       break;
-
-       if (inout)
-               return ppa_proc_write(i, buffer, length);
-
-       size = sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
-       len += size;
-       pos = begin + len;
-       size = sprintf(buffer + len, "Parport  : %s\n",
-                      ppa_hosts[i].dev->port->name);
-       len += size;
-       pos = begin + len;
-
-       size = sprintf(buffer + len, "Mode    : %s\n",
-                      PPA_MODE_STRING[ppa_hosts[i].mode]);
-       len += size;
-       pos = begin + len;
-
-       size = sprintf(buffer + len, "\nTiming Parameters\n");
-       len += size;
-       pos = begin + len;
-
-       size = sprintf(buffer + len, "ppa_speed       %i\n",
-                      ppa_hosts[i].speed);
-       len += size;
-       pos = begin + len;
-
-       size = sprintf(buffer + len, "ppa_speed_fast  %i\n",
-                      ppa_hosts[i].speed_fast);
-       len += size;
-       pos = begin + len;
-
-       if (IN_EPP_MODE(ppa_hosts[i].mode)) {
-               size = sprintf(buffer + len, "epp_speed       %i\n",
-                              ppa_hosts[i].epp_speed);
-               len += size;
-               pos = begin + len;
-
-               size = sprintf(buffer + len, "\nInternal Counters\n");
-               len += size;
-               pos = begin + len;
-
-               size = sprintf(buffer + len, "epp_timeout     %i\n",
-                              ppa_hosts[i].timeout);
-               len += size;
-               pos = begin + len;
-       }
-       *start = buffer + (offset + begin);
-       len -= (offset - begin);
-       if (len > length)
-               len = length;
-       return len;
+       ppa_disconnect(host_no);
+       printk("ppa: Communication established with ID %i using %s\n", loop,
+              PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+       return 0;
+    }
+    printk("ppa: No devices found, aborting driver load.\n");
+    return 1;
 }
-/* end of ppa.c */
index 84fa2dec8e987cb09601fd76faad8f61ee7622ae..5aeb67e5b3e2152b643607f0533a1e2f523fa119 100644 (file)
@@ -2,30 +2,62 @@
  * the Iomega ZIP drive
  * 
  * (c) 1996     Grant R. Guenther  grant@torque.net
+ *             David Campbell     campbell@torque.net
+ *
+ *     All comments to David.
  */
 
 #ifndef _PPA_H
 #define _PPA_H
 
-#define   PPA_VERSION   "Curtin 1-08-BETA"
-
-/* This driver reqires a 1.3.37 kernel or higher!! */
+#define   PPA_VERSION   "1.39"
 
 /* Use the following to enable certain chipset support
  * Default is PEDANTIC = 3
  */
-
-#include <linux/config.h>
-
 #ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC
 #define CONFIG_SCSI_PPA_HAVE_PEDANTIC  3
 #endif
-#ifndef CONFIG_SCSI_PPA_EPP_TIME
-#define CONFIG_SCSI_PPA_EPP_TIME       64
-#endif
 
+/* 
+ * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
+ * to support EPP and scatter-gather.                        [0.26-athena]
+ *
+ * additional hacks by David Campbell
+ * in response to this driver "mis-behaving" on his machine.
+ *      Fixed EPP to handle "software" changing of EPP port data direction.
+ *      Chased down EPP timeouts
+ *      Made this driver "kernel version friendly"           [0.28-athena]
+ *
+ * [ Stuff removed ]
+ *
+ * Compiled against 2.1.53.
+ *     Rebuilt ppa_abort() function, should handle unplugged cable.
+ *                                                     [1.35s]
+ *
+ * PPA now auto probes for EPP on base address which are aligned on
+ * 8 byte boundaries (0x278 & 0x378) using the attached devices.
+ * This hopefully avoids the nasty problem of trying to detect EPP.
+ *     Tested on 2.1.53                                [1.36]
+ *
+ * The id_probe utility no longer performs read/write tests.
+ * Additional code included for checking the Intel ECP bug
+ * (Bit 0 of STR stuck low which fools the EPP detection routine)
+ *                                                     [1.37]
+ *
+ * Oops! Got the bit sign mixed up for the Intel bug check.
+ * Found that an additional delay is required during SCSI resets
+ * to allow devices to settle down.
+ *                                                     [1.38]
+ *
+ * Fixed all problems in the parport sharing scheme. Now ppa can be safe
+ * used with lp or other parport devices on the same parallel port.
+ *             1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *                                                     [1.39]
+ */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
+#ifdef PPA_CODE
 #include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
 #include  <linux/proc_fs.h>
 #include  <linux/stat.h>
 #include  <linux/blk.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
 
 #include  <asm/io.h>
 #include  "sd.h"
 #include  "hosts.h"
-#include  <linux/parport.h>
 /* batteries not included :-) */
 
-#define        PPA_INITIATOR   7
+/*
+ * modes in which the driver can operate 
+ */
+#define   PPA_AUTODETECT        0      /* Autodetect mode                */
+#define   PPA_NIBBLE            1      /* work in standard 4 bit mode    */
+#define   PPA_PS2               2      /* PS/2 byte mode         */
+#define   PPA_EPP_8             3      /* EPP mode, 8 bit                */
+#define   PPA_EPP_16            4      /* EPP mode, 16 bit               */
+#define   PPA_EPP_32            5      /* EPP mode, 32 bit               */
+#define   PPA_UNKNOWN           6      /* Just in case...                */
+
+static char *PPA_MODE_STRING[] =
+{
+    "Autodetect",
+    "SPP",
+    "PS/2",
+    "EPP 8 bit",
+    "EPP 16 bit",
+    "EPP 32 bit",
+    "Unknown"};
+
+/* This is a global option */
+int ppa_sg = SG_ALL;           /* enable/disable scatter-gather. */
+
+/* other options */
+#define PPA_CAN_QUEUE   0      /* use "queueing" interface */
+#define PPA_BURST_SIZE 512     /* data burst size */
+#define PPA_SELECT_TMO  5000   /* how long to wait for target ? */
+#define PPA_SPIN_TMO    50000  /* ppa_wait loop limiter */
+#define PPA_DEBUG      0       /* debuging option */
+#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
+
+/* args to ppa_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb((x)+0x402)
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_ctr(x,y)      outb(y, (x)+2)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x)+0x400)
+#define w_ecr(x,y)      outb(y, (x)+0x402)
+
+static int ppa_engine(ppa_struct *, Scsi_Cmnd *);
+static int ppa_in(int, char *, int);
+static int ppa_init(int);
+static void ppa_interrupt(void *);
+static int ppa_out(int, char *, int);
+
+struct proc_dir_entry proc_scsi_ppa =
+{PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
+#else
+extern struct proc_dir_entry proc_scsi_ppa;
+#define ppa_release 0
+#endif
 
 int ppa_detect(Scsi_Host_Template *);
 const char *ppa_info(struct Scsi_Host *);
@@ -51,25 +145,13 @@ int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int ppa_abort(Scsi_Cmnd *);
 int ppa_reset(Scsi_Cmnd *, unsigned int);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
-int ppa_biosparam(Disk *, kdev_t, int*);
-int ppa_release(struct Scsi_Host *);
-
-#ifndef        MODULE
-#ifdef PPA_CODE
-#define SKIP_PROC_DIR
-#endif
-#endif
-
-#ifndef SKIP_PROC_DIR
-struct proc_dir_entry proc_scsi_ppa =
-{PROC_SCSI_PPA, 3, "ppa", S_IFDIR | S_IRUGO | S_IXUGO, 2};
-#endif /* !PPA_CODE => hosts.c */
+int ppa_biosparam(Disk *, kdev_t, int *);
 
 #define PPA {  /* next */              0, \
                /* usage_count */       0, \
                /* proc_dir */          &proc_scsi_ppa, \
                /* proc_info */         ppa_proc_info, \
-               /* name */              "Iomega ZIP/JAZ Traveller", \
+               /* name */              "Iomega parport ZIP drive", \
                /* detect */            ppa_detect, \
                /* release */           ppa_release, \
                /* info */              0, \
@@ -80,7 +162,7 @@ struct proc_dir_entry proc_scsi_ppa =
                /* slave_attach */      0, \
                /* bios_param */        ppa_biosparam, \
                /* can_queue */         0, \
-               /* this_id */           PPA_INITIATOR, \
+               /* this_id */           -1, \
                /* sg_tablesize */      SG_ALL, \
                /* cmd_per_lun */       1, \
                /* present */           0, \
index 644c42fe178c5562d14bcf427758172ed293a09f..89bc64e6b2daf58f8668817d92aaf06eaf7fdb11 100644 (file)
@@ -191,4 +191,5 @@ typedef struct              // master setup structure
        SETUP_DEVICE    setupDevice[8];
        }       SETUP, *PSETUP;
 
-#endif
\ No newline at end of file
+#endif
+
index e9c411e48b6a5f975b4fd842923c61d34bd510f5..d532c13e4224330458faa5ca655bbc1c0ad039ba 100644 (file)
  *      x is some number, It will let you specify a default
  *      transfer rate if handshaking isn't working correctly.
  *
+ * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
+ *                    and DATA reigsters which complies more closely
+ *                    with the SCSI2 standard. This hopefully eliminates
+ *                    the need to swap the order these registers are
+ *                    'messed' with. It makes the following two options
+ *                    obsolete. To reenable the old sceme define this.
+ *
  * The following to options are patches from the SCSI.HOWTO
  *
  * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
@@ -794,6 +801,10 @@ static int internal_command (unsigned char target, unsigned char lun,
   unsigned char message = 0;
   register unsigned char status_read;
 
+#ifndef OLDCNTDATASCEME
+  volatile unsigned char tmp_data;
+  volatile unsigned char tmp_control;
+#endif
   unsigned transfersize = 0, underflow = 0;
 
   incommand = 0;
@@ -1029,6 +1040,7 @@ static int internal_command (unsigned char target, unsigned char lun,
  *    try this with a SCSI protocol or logic analyzer to see what is
  *    going on.
  */
+#ifdef OLDCNTDATASCEME
 #ifdef SWAPCNTDATA
        cli();
       WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
@@ -1044,6 +1056,16 @@ static int internal_command (unsigned char target, unsigned char lun,
                      (reselect ? CMD_ATTN : 0));
       sti ();
 #endif
+#else
+       tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE 
+? 0x80 : 0x40));
+       tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL |
+                (reselect ? CMD_ATTN : 0) | CMD_BSY;
+       WRITE_CONTROL(tmp_data);
+       WRITE_DATA(tmp_control);
+       tmp_control ^= CMD_BSY;
+       WRITE_CONTROL(tmp_control);
+#endif /* OLDCNTDATASCEME */
       while (!((status_read = STATUS) & STAT_BSY) && (jiffies < clock)
              && !st0x_aborted)
 #if 0 && (DEBUG & PHASE_SELECTION)
index 3abf8520f220ffa236c9b577a09c274c3b33d4a7..b705222808523cfe6b00bc4ca5544d2c5e05665c 100644 (file)
@@ -11,7 +11,7 @@
   Copyright 1992 - 1997 Kai Makisara
                 email Kai.Makisara@metla.fi
 
-  Last modified: Tue May 27 22:29:00 1997 by makisara@home
+  Last modified: Wed Nov  5 23:39:52 1997 by makisara@home
   Some small formal changes - aeb, 950809
 */
 
@@ -230,18 +230,9 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
     }
     else
       (STp->buffer)->last_result = SCpnt->result;
-#if 0
-    if ((STp->buffer)->writing) {
-      /* Process errors before releasing request */
-      (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
-      SCpnt->request.rq_status = RQ_INACTIVE;
-    }
-    else
-      SCpnt->request.rq_status = RQ_SCSI_DONE;
-#else
+
     SCpnt->request.rq_status = RQ_SCSI_DONE;
     (STp->buffer)->last_SCpnt = SCpnt;
-#endif
 
 #if DEBUG
     STp->write_pending = 0;
@@ -645,8 +636,10 @@ scsi_tape_open(struct inode * inode, struct file * filp)
     }
 
     if ((STp->buffer)->last_result_fatal != 0) {
-      if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-         (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) {
+      if ((STp->device)->scsi_level >= SCSI_2 &&
+         (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+         (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
+         SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */
        STp->ready = ST_NO_TAPE;
       } else
        STp->ready = ST_NOT_READY;
@@ -872,8 +865,6 @@ scsi_tape_close(struct inode * inode, struct file * filp)
        if (!SCpnt)
          goto out;
 
-       SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-
        if ((STp->buffer)->last_result_fatal != 0 &&
            ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
             (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
@@ -882,11 +873,13 @@ scsi_tape_close(struct inode * inode, struct file * filp)
               SCpnt->sense_buffer[5] |
               SCpnt->sense_buffer[6]) == 0))) {
            /* Filter out successful write at EOM */
+           SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
            printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
            if (result == 0)
                result = (-EIO);
        }
        else {
+         SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
          if (STps->drv_file >= 0)
              STps->drv_file++ ;
          STps->drv_block = 0;
@@ -977,8 +970,12 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
     }
 
     STp = &(scsi_tapes[dev]);
-    if (STp->ready != ST_READY)
-      return (-EIO);
+    if (STp->ready != ST_READY) {
+      if (STp->ready == ST_NO_TAPE)
+       return (-ENOMEDIUM);
+      else
+        return (-EIO);
+    }
     STm = &(STp->modes[STp->current_mode]);
     if (!STm->defined)
       return (-ENXIO);
@@ -1349,7 +1346,7 @@ read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
                    }
                    else {
                        SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
-                       SCpnt = NULL;
+                       SCpnt = *aSCpnt = NULL;
                        if (transfer == blks) {  /* We did not get anything, error */
                            printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
                            if (STps->drv_block >= 0)
@@ -1465,8 +1462,12 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
     }
 
     STp = &(scsi_tapes[dev]);
-    if (STp->ready != ST_READY)
-      return (-EIO);
+    if (STp->ready != ST_READY) {
+      if (STp->ready == ST_NO_TAPE)
+       return (-ENOMEDIUM);
+      else
+        return (-EIO);
+    }
     STm = &(STp->modes[STp->current_mode]);
     if (!STm->defined)
       return (-ENXIO);
@@ -1544,7 +1545,7 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
       if ((STp->buffer)->buffer_bytes > 0) {
 #if DEBUG
        if (debugging && STps->eof != ST_NOEOF)
-         printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %ld.\n", dev,
+         printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
                 STps->eof, (STp->buffer)->buffer_bytes, count - total);
 #endif
        transfer = (STp->buffer)->buffer_bytes < count - total ?
@@ -1886,8 +1887,12 @@ st_int_ioctl(struct inode * inode,
    int dev = TAPE_NR(inode->i_rdev);
 
    STp = &(scsi_tapes[dev]);
-   if (STp->ready != ST_READY && cmd_in != MTLOAD)
-     return (-EIO);
+   if (STp->ready != ST_READY && cmd_in != MTLOAD) {
+     if (STp->ready == ST_NO_TAPE)
+       return (-ENOMEDIUM);
+     else
+       return (-EIO);
+   }
    timeout = STp->long_timeout;
    STps = &(STp->ps[STp->partition]);
    fileno = STps->drv_file;
@@ -2523,6 +2528,7 @@ set_location(struct inode * inode, unsigned int block, int partition,
     if (!SCpnt)
       return (-EBUSY);
 
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
     STps->drv_block = STps->drv_file = (-1);
     STps->eof = ST_NOEOF;
     if ((STp->buffer)->last_result_fatal != 0) {
@@ -2548,7 +2554,6 @@ set_location(struct inode * inode, unsigned int block, int partition,
        STps->drv_block = STps->drv_file = 0;
       result = 0;
     }
-    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
     return result;
 }
index c25c80cc7af2ac415c63adf654fe8f299ed3b583..c3e71f293b30a894a6c86e91761543f72cdd1655 100644 (file)
@@ -64,7 +64,6 @@ typedef struct {
   unsigned capacity;
   struct wait_queue * waiting;
   Scsi_Device* device;
-  Scsi_Cmnd SCpnt;
   struct semaphore sem;
   ST_buffer * buffer;
 
index 310bf01bf1f4036199e328100c2e0e87e75ec108..098ba3de7c014a5f87c526140963688bb551f178 100644 (file)
-#
-# Sound driver configuration
-#
-#--------
-# There is another confic script which is compatible with rest of
-# the kernel. It can be activated by running 'make mkscript' in this
-# directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
-#--------
-#
-$MAKE -C drivers/sound config || exit 1
+bool 'ProAudioSpectrum 16 support' CONFIG_PAS
+bool '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB
+bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
+bool 'Gravis Ultrasound support' CONFIG_GUS
+bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
+bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
+bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
+bool 'GUS MAX support' CONFIG_GUSMAX
+bool 'Microsoft Sound System support' CONFIG_MSS
+bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
+bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
+bool 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16
+bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
+bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
+bool 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1
+bool 'SoftOSS software wave table engine' CONFIG_SOFTOSS
+bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
+
+if [ "$CONFIG_AEDSP16" = "y" ]; then
+hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'Enter -1 to the following question if you have something else such as SB16/32.'
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
+fi
+
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with Maui.'
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
+fi
+
+
+if [ "$CONFIG_PSS" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with PSS cards.'
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS I/O base 220 or 240' PSS_BASE 220
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
+fi
 
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
+fi
+
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with OPL3-SA1.'
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 audio DMA 0, 1 or 3' TRIX_DMA 0
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'OPL3-SA1 SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'OPL3-SA1 SB DMA 1 or 3' TRIX_SB_DMA 1
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' OPL3SA1_BASE 530
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' OPL3SA1_IRQ 11
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+int 'OPL3-SA1 audio DMA 0, 1 or 3' OPL3SA1_DMA 0
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' OPL3SA1_DMA2 3
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' OPL3SA1_MPU_BASE 330
+fi
+
+if [ "$CONFIG_OPL3SA1" = "y" ]; then
+int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' OPL3SA1_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_SOFTOSS" = "y" ]; then
+int 'Sampling rate for SoftOSS 8000 to 48000' SOFTOSS_RATE 22050
+fi
+
+if [ "$CONFIG_SOFTOSS" = "y" ]; then
+int 'Max # of concurrent voices for SoftOSS 4 to 32' SOFTOSS_VOICES 32
+fi
+#
+$MAKE -C drivers/sound kernelconfig || exit 1
 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
 
 if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
index 84de143cfc17f99d97ac5efacb2a0b07fde16f92..d260c0b4e290734154209f07f948cbf05dd2a6ba 100644 (file)
@@ -27,6 +27,7 @@
 /*----------------------------------------------------------------
  * system configuration
  *----------------------------------------------------------------*/
+#define AWE_NEW_KERNEL_INTERFACE
 
 /* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD),
  * define the following line.
index 8a9bdf902de7fc2f87b9d053c563128a032fb015..048b589bfbe5927dddee9fa46908640fb7dfe000 100644 (file)
@@ -57,72 +57,6 @@ static int sync_block (struct inode * inode, u32 * block, int wait)
        return 0;
 }
 
-#ifndef __LITTLE_ENDIAN
-static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
-{
-       struct buffer_head * bh;
-       
-       if (!le32_to_cpu(*block))
-               return 0;
-       bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
-       if (!bh)
-               return 0;
-       if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-               brelse (bh);
-               return -1;
-       }
-       if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
-               brelse (bh);
-               return 0;
-       }
-       ll_rw_block (WRITE, 1, &bh);
-       bh->b_count--;
-       return 0;
-}
-#else
-#define sync_block_swab32 sync_block
-#endif
-
-
-static int sync_iblock (struct inode * inode, u32 * iblock, 
-                       struct buffer_head ** bh, int wait) 
-{
-       int rc, tmp;
-       
-       *bh = NULL;
-       tmp = *iblock;
-       if (!tmp)
-               return 0;
-       rc = sync_block (inode, iblock, wait);
-       if (rc)
-               return rc;
-       *bh = bread (inode->i_dev, tmp, blocksize);
-       if (!*bh)
-               return -1;
-       return 0;
-}
-
-#ifndef __LITTLE_ENDIAN
-static int sync_iblock_swab32 (struct inode * inode, u32 * iblock, 
-                              struct buffer_head ** bh, int wait) 
-{
-       int rc, tmp;
-       
-       *bh = NULL;
-       tmp = le32_to_cpu(*iblock);
-       if (!tmp)
-               return 0;
-       rc = sync_block_swab32 (inode, iblock, wait);
-       if (rc)
-               return rc;
-       *bh = bread (inode->i_dev, tmp, blocksize);
-       if (!*bh)
-               return -1;
-       return 0;
-}
-#else
-#define sync_iblock_swab32 sync_iblock
-#endif
 
 static int sync_direct (struct inode * inode, int wait)
 {
@@ -137,122 +71,15 @@ static int sync_direct (struct inode * inode, int wait)
        return err;
 }
 
-static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
-{
-       int i;
-       struct buffer_head * ind_bh;
-       int rc, err = 0;
-
-       rc = sync_iblock (inode, iblock, &ind_bh, wait);
-       if (rc || !ind_bh)
-               return rc;
-       
-       for (i = 0; i < addr_per_block; i++) {
-               rc = sync_block_swab32 (inode, 
-                                       ((u32 *) ind_bh->b_data) + i,
-                                       wait);
-               if (rc)
-                       err = rc;
-       }
-       brelse (ind_bh);
-       return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
-{
-       int i;
-       struct buffer_head * ind_bh;
-       int rc, err = 0;
-
-       rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
-       if (rc || !ind_bh)
-               return rc;
-       
-       for (i = 0; i < addr_per_block; i++) {
-               rc = sync_block_swab32 (inode, 
-                                       ((u32 *) ind_bh->b_data) + i,
-                                       wait);
-               if (rc)
-                       err = rc;
-       }
-       brelse (ind_bh);
-       return err;
-}
-#else
-#define sync_indirect_swab32 sync_indirect
-#endif
-
-static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
-{
-       int i;
-       struct buffer_head * dind_bh;
-       int rc, err = 0;
-
-       rc = sync_iblock (inode, diblock, &dind_bh, wait);
-       if (rc || !dind_bh)
-               return rc;
-       
-       for (i = 0; i < addr_per_block; i++) {
-               rc = sync_indirect_swab32 (inode,
-                                          ((u32 *) dind_bh->b_data) + i,
-                                          wait);
-               if (rc)
-                       err = rc;
-       }
-       brelse (dind_bh);
-       return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
-{
-       int i;
-       struct buffer_head * dind_bh;
-       int rc, err = 0;
-
-       rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
-       if (rc || !dind_bh)
-               return rc;
-       
-       for (i = 0; i < addr_per_block; i++) {
-               rc = sync_indirect_swab32 (inode,
-                                          ((u32 *) dind_bh->b_data) + i,
-                                          wait);
-               if (rc)
-                       err = rc;
-       }
-       brelse (dind_bh);
-       return err;
-}
-#else
-#define sync_dindirect_swab32 sync_dindirect
-#endif
-
-static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
-{
-       int i;
-       struct buffer_head * tind_bh;
-       int rc, err = 0;
-
-       rc = sync_iblock (inode, tiblock, &tind_bh, wait);
-       if (rc || !tind_bh)
-               return rc;
-       
-       for (i = 0; i < addr_per_block; i++) {
-               rc = sync_dindirect_swab32 (inode,
-                                           ((u32 *) tind_bh->b_data) + i,
-                                           wait);
-               if (rc)
-                       err = rc;
-       }
-       brelse (tind_bh);
-       return err;
-}
-
 /*
  *     File may be NULL when we are called. Perhaps we shouldn't
  *     even pass file to fsync ?
+ *
+ *     This currently falls back to synching the whole device when
+ *     the file is larger than can fit directly in the inode. This
+ *     is because dirty-buffer handling is indexed by the device
+ *     of the buffer, which makes it much faster to sync the whole
+ *     device than to sync just one large file.
  */
 
 int ext2_sync_file(struct file * file, struct dentry *dentry)
@@ -269,18 +96,14 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
                 */
                goto skip;
 
+       if (inode->i_size > EXT2_NDIR_BLOCKS*blocksize) {
+               err = fsync_dev(inode->i_dev);
+               goto skip;
+       }
+
        for (wait=0; wait<=1; wait++)
        {
                err |= sync_direct (inode, wait);
-               err |= sync_indirect (inode,
-                                     inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
-                                     wait);
-               err |= sync_dindirect (inode,
-                                      inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, 
-                                      wait);
-               err |= sync_tindirect (inode, 
-                                      inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, 
-                                      wait);
        }
 skip:
        err |= ext2_sync_inode (inode);
index c88c56760ab1459e137392f47f35ab93e1666e1f..5321e011a6b3f2429a8607c4c7e449781beedac5 100644 (file)
@@ -56,7 +56,7 @@ static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
        if (!pnt)
                return 0;
 
-       i = strlen(pnt)+1;
+       i = strlen(pnt);
        if (i > buflen)
                i = buflen; 
        if (copy_to_user(buffer, pnt, i))
index 6bb9993f013f4c85da279b559ae8e00f59435952..005431485a1bca36fbabbc8b0934cc3b5c3ce382 100644 (file)
@@ -118,22 +118,23 @@ static struct dentry_operations ncp_dentry_operations =
        ncp_delete_dentry       /* d_delete(struct dentry *) */
 };
 
+
+/*
+ * XXX: It would be better to use the tolower from linux/ctype.h,
+ * but _ctype is needed and it is not exported.
+ */
+#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
+
+
 static int 
 ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
 {
-  char al[NCP_MAXPATHLEN];
   unsigned long hash;
   int i;
 
-  memcpy(al,this->name,this->len);
-  al[this->len] = 0;
-
-  if (!ncp_preserve_case(dentry->d_inode))
-      str_lower(al);
-
   hash = init_name_hash();
   for (i=0; i<this->len ; i++)
-    hash = partial_name_hash(al[i],hash);
+    hash = partial_name_hash(tolower(this->name[i]),hash);
   this->hash = end_name_hash(hash);
   
   return 0;
@@ -142,21 +143,18 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
 static int
 ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
 {
-       char al[NCP_MAXPATHLEN],bl[NCP_MAXPATHLEN];
+       int i;
 
        if (a->len != b->len) return 1;
 
-       if (ncp_preserve_case(dentry->d_inode))
+       if (ncp_case_sensitive(dentry->d_inode))
            return strncmp(a->name, b->name, a->len);
 
-       memcpy (al,a->name,a->len);
-       memcpy (bl,b->name,b->len);
-       al[a->len] = bl[b->len] = 0;
+       for (i=0; i<a->len; i++)
+         if (tolower(a->name[i]) != tolower(b->name[i]))
+           return 1;
 
-       str_lower(al);
-       str_lower(bl);
-       
-       return strcmp(al,bl);
+       return 0;
 }
 
 /*
@@ -223,10 +221,16 @@ ino_t ncp_invent_inos(unsigned long n)
 static ino_t
 find_inode_number(struct dentry *dir, struct qstr *name)
 {
+        unsigned long hash;
+        int i;
        struct dentry * dentry;
        ino_t ino = 0;
-
-       name->hash = full_name_hash(name->name, name->len);
+        
+        hash = init_name_hash();
+        for (i=0; i<name->len ; i++)
+                hash = partial_name_hash(tolower(name->name[i]),hash);
+        name->hash = end_name_hash(hash);
+        
        dentry = d_lookup(dir, name);
        if (dentry)
        {
@@ -278,8 +282,11 @@ ncp_lookup_validate(struct dentry * dentry)
        struct ncpfs_inode_info finfo;
        __u8 __name[dentry->d_name.len + 1];
 
-       printk("ncp_lookup_validate called\n");
-      
+        if (!dentry->d_inode) {
+                DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n");
+                return 0;
+        }
+        
        if (!dir || !S_ISDIR(dir->i_mode)) {
                printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n");
                goto finished;
index 2a140ea55dda445738183de1bebe6921d22a9613..56275034d05500bb59eee534a2eaf755911546b1 100644 (file)
@@ -40,7 +40,7 @@ static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
        unsigned long tmp;
        int bufsize;
        int pos;
-       mm_segment_t fs;
+       unsigned long fs;
 
        page = __get_free_page(GFP_KERNEL);
        if (!page)
index c6c8d6f58ae7c9d2fee98c6d978f910771da0557..08055ac5e5b04468dfff5917758d09938fc35ca7 100644 (file)
@@ -82,7 +82,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
        struct file *file;
        struct inode *inode;
        struct socket *sock;
-       mm_segment_t fs;
+       unsigned long fs;
        int result;
        char *start = server->packet;
        poll_table wait_table;
index 166f664d9866a01a66fe30fef799a231ca6b5952..acc76710b4bd4bd317fc5351a1848ea4e9948262 100644 (file)
 
 #define NFS_MAX_AGE 10*HZ      /* max age for dentry validation */
 
-#ifndef shrink_dcache_parent
-#define shrink_dcache_parent(dentry) shrink_dcache_sb((dentry)->d_sb)
-#endif
-
 /* needed by smbfs as well ... move to dcache? */
 extern void nfs_renew_times(struct dentry *);
 
@@ -59,7 +55,7 @@ struct nfs_dirent {
 
 static int nfs_safe_remove(struct dentry *);
 
-static int nfs_dir_open(struct inode * inode, struct file * file);
+static int nfs_dir_open(struct inode *, struct file *);
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
 static int nfs_lookup(struct inode *, struct dentry *);
@@ -435,6 +431,21 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                if (age > NFS_MAX_AGE)
                        d_drop(dentry);
        }
+
+#ifdef NFS_PARANOIA
+       /*
+        * Sanity check: if the dentry has been unhashed and the
+        * inode still has users, we could have problems ...
+        */
+       if (list_empty(&dentry->d_hash) && dentry->d_inode) {
+               struct inode *inode = dentry->d_inode;
+               if (inode->i_count > 1) {
+printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+               }
+       }
+#endif
 }
 
 static struct dentry_operations nfs_dentry_operations = {
@@ -785,7 +796,7 @@ static int nfs_safe_remove(struct dentry *dentry)
 {
        struct inode *dir = dentry->d_parent->d_inode;
        struct inode *inode = dentry->d_inode;
-       int error;
+       int error, rehash = 0;
                
        error = -EBUSY;
        if (inode) {
@@ -813,8 +824,22 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
 #endif
                goto out;
        }
+       /*
+        * Unhash the dentry while we remove the file ...
+        */
+       if (!list_empty(&dentry->d_hash)) {
+               d_drop(dentry);
+               rehash = 1;
+       }
        error = nfs_proc_remove(NFS_SERVER(dir),
                                        NFS_FH(dir), dentry->d_name.name);
+       /*
+        * ... then restore the hashed state.  This ensures that the
+        * dentry can't become busy after having its file deleted.
+        */
+       if (rehash) {
+               d_add(dentry, inode);
+       }
 #ifdef NFS_PARANOIA
 if (dentry->d_count > 1)
 printk("nfs_safe_remove: %s/%s busy after delete?? d_count=%d\n",
@@ -827,6 +852,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
                nfs_invalidate_dircache(dir);
                if (inode && inode->i_nlink)
                        inode->i_nlink --;
+               d_delete(dentry);
        }
 out:
        return error;
@@ -858,7 +884,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
                error = nfs_safe_remove(dentry);
                if (!error) {
                        nfs_renew_times(dentry);
-                       d_delete(dentry);
                }
        }
 out:
@@ -966,8 +991,9 @@ out:
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct inode *inode = old_dentry->d_inode;
-       int update = 1, error;
+       struct inode *old_inode = old_dentry->d_inode;
+       struct inode *new_inode = new_dentry->d_inode;
+       int error, rehash = 0, update = 1;
 
 #ifdef NFS_DEBUG_VERBOSE
 printk("nfs_rename: old %s/%s, count=%d, new %s/%s, count=%d\n",
@@ -988,6 +1014,24 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
        if (old_dentry->d_name.len > NFS_MAXNAMLEN ||
            new_dentry->d_name.len > NFS_MAXNAMLEN)
                goto out;
+
+       /*
+        * First check whether the target is busy ... we can't
+        * safely do _any_ rename if the target is in use.
+        */
+       if (new_dentry->d_count > 1) {
+               if (new_inode && S_ISDIR(new_inode->i_mode))
+                       shrink_dcache_parent(new_dentry);
+       }
+       error = -EBUSY;
+       if (new_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: target %s/%s busy, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
+               goto out;
+       }
+
        /*
         * Check for within-directory rename ... no complications.
         */
@@ -996,15 +1040,14 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
        /*
         * Cross-directory move ... check whether it's a file.
         */
-       error = -EBUSY;
-       if (S_ISREG(inode->i_mode)) {
-               if (NFS_WRITEBACK(inode)) {
+       if (S_ISREG(old_inode->i_mode)) {
+               if (NFS_WRITEBACK(old_inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: %s/%s has pending writes\n",
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
 #endif
-                       nfs_flush_dirty_pages(inode, 0, 0, 0);
-                       if (NFS_WRITEBACK(inode)) {
+                       nfs_flush_dirty_pages(old_inode, 0, 0, 0);
+                       if (NFS_WRITEBACK(old_inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: %s/%s has pending writes after flush\n",
 old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
@@ -1030,7 +1073,6 @@ old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
 #endif
                goto out;
        }
-
        if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
@@ -1040,13 +1082,28 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
        }
 
        d_drop(old_dentry);
-       d_drop(new_dentry);
        update = 0;
 
 do_rename:
+       /*
+        * We must prevent any new references to the target while
+        * the rename is in progress, so we unhash the dentry.
+        */
+       if (!list_empty(&new_dentry->d_hash)) {
+               d_drop(new_dentry);
+               rehash = 1;
+       }
        error = nfs_proc_rename(NFS_SERVER(old_dir),
                                NFS_FH(old_dir), old_dentry->d_name.name,
                                NFS_FH(new_dir), new_dentry->d_name.name);
+       if (rehash) {
+               d_add(new_dentry, new_inode);
+       }
+#ifdef NFS_PARANOIA
+if (new_dentry->d_count > 1)
+printk("nfs_rename: %s/%s busy after rename, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
        if (!error) {
                nfs_invalidate_dircache(new_dir);
                nfs_invalidate_dircache(old_dir);
index d30165ba4e5dbeeb6979323d16e189436de4b696..c070d130b4041a1ea6774d9662120e04fb4467df 100644 (file)
@@ -629,13 +629,12 @@ out_changed:
         * Big trouble! The inode has become a different object.
         */
 #ifdef NFS_PARANOIA
-printk("nfs_refresh_inode: mode changed, %07o to %07o\n",
-inode->i_mode, fattr->mode);
+printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+inode->i_ino, inode->i_mode, fattr->mode);
 #endif
        fattr->mode = inode->i_mode; /* save mode */
        make_bad_inode(inode);
        inode->i_mode = fattr->mode; /* restore mode */
-       inode->i_nlink = 0;
        /*
         * No need to worry about unhashing the dentry, as the
         * lookup validation will know that the inode is bad.
index 76456af5fc6cbabd58e3f8b8aa4e0e9c918dc6b1..b7f2e1507201b8978889113dafa17b0387fc5234 100644 (file)
@@ -142,7 +142,7 @@ __initfunc(static void check_popad(void))
          : "edx" (inp)
          : "eax", "ecx", "edx", "edi" );
        /* If this fails, it means that any user program may lock CPU hard. Too bad. */
-       if (res != 12345678) printk( "Bad.\n" );
+       if (res != 12345678) printk( "Buggy.\n" );
                        else printk( "Ok.\n" );
 #endif
 }
@@ -172,23 +172,19 @@ __initfunc(static void check_amd_k6(void))
  */
 
 extern int pentium_f00f_bug;
+extern void trap_init_f00f_bug(void);
+
 
 __initfunc(static void check_pentium_f00f(void))
 {
        /*
         * Pentium and Pentium MMX
         */
-       printk("checking for F00F bug ...");
-       if(x86==5 && !memcmp(x86_vendor_id, "GenuineIntel", 12))
-       {
-               extern void trap_init_f00f_bug(void);
-
-               printk(KERN_INFO "\nIntel Pentium/[MMX] F0 0F bug detected - turning on workaround.\n");
+       pentium_f00f_bug = 0;
+       if (x86==5 && !memcmp(x86_vendor_id, "GenuineIntel", 12)) {
+               printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
                pentium_f00f_bug = 1;
                trap_init_f00f_bug();
-       } else {
-               printk(KERN_INFO " no F0 0F bug in this CPU, great!\n");
-               pentium_f00f_bug = 0;
        }
 }
 
index 94e01ec2a55ff5a9cd0d0d78a444bbf1bf637819..9dcc21b44e67595a8771303d58ef2a1452a1ff6e 100644 (file)
@@ -255,13 +255,13 @@ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
        :"ax","dx")
 
 #define set_intr_gate(n,addr) \
-       _set_gate(&idt[n],14,0,addr)
+       _set_gate(idt+(n),14,0,addr)
 
 #define set_trap_gate(n,addr) \
-       _set_gate(&idt[n],15,0,addr)
+       _set_gate(idt+(n),15,0,addr)
 
 #define set_system_gate(n,addr) \
-       _set_gate(&idt[n],15,3,addr)
+       _set_gate(idt+(n),15,3,addr)
 
 #define set_call_gate(a,addr) \
        _set_gate(a,12,3,addr)
index 3829b1c36ec475fd0519f5c0340e5b352d6a8184..e4e99b31d4fb8b3ca7c72d322054184133802f91 100644 (file)
@@ -1,11 +1,20 @@
 #ifndef _LINUX_HEAD_H
 #define _LINUX_HEAD_H
 
-typedef struct desc_struct {
+struct desc_struct {
        unsigned long a,b;
-} desc_table[256];
+};
 
-extern desc_table idt,gdt;
+extern struct desc_struct idt_table[],gdt_table[];
+extern struct desc_struct *idt, *gdt;
+
+struct Xgt_desc_struct {
+       unsigned short size;
+       unsigned long address __attribute__((packed));
+};
+
+#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
+#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
 
 #define GDT_NUL 0
 #define GDT_CODE 1
index a0770c23f1c9543a5c228d944b77630b11018820..36528a606f56386ba8fb8bba7ee20802b82efc56 100644 (file)
@@ -9,10 +9,10 @@
 #define ATARIMOUSE_MINOR 5
 #define SUN_MOUSE_MINOR 6
 #define PC110PAD_MINOR 9
-#define RADIO_MINOR 129
 #define RTC_MINOR 135
 #define SUN_OPENPROM_MINOR 139
 #define NVRAM_MINOR 144
+#define RADIO_MINOR 152
 #define MISC_DYNAMIC_MINOR 255
 
 extern int misc_init(void);
index 039ad1559ad6a866ab752172d383504edb547411..7b09f94a9a311f44aacf357386bb50fac757f236 100644 (file)
@@ -202,13 +202,14 @@ static inline int ncp_namespace(struct inode *inode)
 
 static inline int ncp_preserve_case(struct inode *i)
 {
-       /* If we can get case-sensitive server lookups working, then
-        *
-        *  return (ncp_namespace(i) == NW_NS_OS2);
-        */
-       return 0;
+               return (ncp_namespace(i) == NW_NS_OS2);
 }
 
+static inline int ncp_case_sensitive(struct inode *i)
+{
+       return 0;
+} 
+
 #endif                         /* __KERNEL__ */
 
 #endif                         /* _LINUX_NCP_FS_H */
index b702a64a8969297863c7e1b8d82ac33ce790e87b..a78aa8a69ce8301be2b6840c2711a391a5cf9bf5 100644 (file)
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN   0x4801
 
 #define PCI_VENDOR_ID_PROMISE          0x105a
+#define PCI_DEVICE_ID_PROMISE_IDE_UDMA 0x4d33
 #define PCI_DEVICE_ID_PROMISE_5300     0x5300
 
 #define PCI_VENDOR_ID_N9               0x105d
index 536b5d3075d0d389a1375b3124ccabc7108cd085..bf9aa5d64247dfc2250f6b05176fb74ec99f654a 100644 (file)
@@ -198,6 +198,7 @@ EXPORT_SYMBOL(dput);
 EXPORT_SYMBOL(get_cached_page);
 EXPORT_SYMBOL(put_cached_page);
 EXPORT_SYMBOL(shrink_dcache_sb);
+EXPORT_SYMBOL(shrink_dcache_parent);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
index f5a06935a6d891a1ee3814125f0b0fc431c7d87b..b57dc9e3d87a9757c43697010ce3a38a2eb081a5 100644 (file)
@@ -26,9 +26,6 @@ comment ' '
 tristate 'The IPX protocol' CONFIG_IPX
 if [ "$CONFIG_IPX" != "n" ]; then
   bool 'Full internal IPX network' CONFIG_IPX_INTERN
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'IPX Type 20 Routing' CONFIG_IPX_PPROP_ROUTING
-  fi
 fi
 tristate 'Appletalk DDP' CONFIG_ATALK
 tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25
index 8ed6fd46affb9b2695ef0c5b0daf3b81f5893253..13d9528e60aef3710f51e616214a28af9941ccf0 100644 (file)
@@ -750,7 +750,6 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                }
        }
 
-#ifdef CONFIG_IPX_PPROP_ROUTING
        if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 && skb->pkt_type == PACKET_HOST ) 
        {
                int i;
@@ -802,7 +801,6 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                }
 
        }
-#endif
 
        if (!ipx->ipx_dest.net)
                ipx->ipx_dest.net = intrfc->if_netnum;