]> git.neil.brown.name Git - history.git/commitdiff
Import 0.99.14k 0.99.14k
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:17 +0000 (15:09 -0500)
38 files changed:
Makefile
config.in
drivers/block/hd.c
drivers/char/console.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/net/3c501.c
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/at1700.c
drivers/net/atp.c [new file with mode: 0644]
drivers/net/atp.h [new file with mode: 0644]
drivers/net/eexpress.c
drivers/net/hp.c
drivers/net/iow.h
drivers/net/lance.c
drivers/net/ne.c
drivers/net/skeleton.c
drivers/scsi/aha152x.c
drivers/scsi/fdomain.c
drivers/sound/sb16_dsp.c
fs/minix/inode.c
include/asm/io.h
include/linux/fs.h
include/linux/mcd.h
include/linux/minix_fs.h
include/linux/minix_fs_sb.h
kernel/exit.c
kernel/ksyms.sh
kernel/sched.c
kernel/traps.c
net/inet/icmp.c
net/inet/ip.c
net/inet/route.c
net/inet/tcp.c
net/inet/udp.c
net/socket.c
net/unix/proc.c

index 5761b0840551eecac4e7bf07e46ab8c88c785ecc..044c67560ac5c2b987df58c5aa909d9bc2d2472e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
 PATCHLEVEL = 14
-ALPHA = j
+ALPHA = k
 
 all:   Version zImage
 
@@ -189,8 +189,7 @@ zdisk: zImage
 zlilo: $(CONFIGURE) zImage
        if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi
        cat zImage > /vmlinuz
-       /etc/lilo/install
-
+       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
        $(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \
@@ -221,6 +220,7 @@ net: dummy
        $(MAKE) linuxsubdirs SUBDIRS=net
 
 clean:
+       rm -f kernel/ksyms.lst
        rm -f core `find . -name '*.[oas]' -print`
        rm -f core `find . -name 'core' -print`
        rm -f zImage zSystem.map tools/zSystem tools/system
index aed82ea43efad8774faa2655dd099c200c09b0c7..75a3812f6996120328d57a07f19f40db9bf2b325 100644 (file)
--- a/config.in
+++ b/config.in
@@ -82,7 +82,7 @@ bool 'AT1700 support' CONFIG_AT1700 n
 #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
 #bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n
 bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
-#bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
+bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
 fi
 *
 bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
index b4dd66af4e40c09bd6b85094581486c8d072aa1f..4391cc33441f15222e42b5c2d10a4032e994b608 100644 (file)
@@ -85,12 +85,6 @@ static struct hd_struct hd[MAX_HD<<6]={{0,0},};
 static int hd_sizes[MAX_HD<<6] = {0, };
 static int hd_blocksizes[MAX_HD<<6] = {0, };
 
-#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
-
-#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
-
 #if (HD_DELAY > 0)
 unsigned long read_timer(void)
 {
@@ -339,7 +333,7 @@ static void read_intr(void)
        do_hd_request();
        return;
 ok_to_read:
-       port_read(HD_DATA,CURRENT->buffer,256);
+       insw(HD_DATA,CURRENT->buffer,256);
        CURRENT->errors = 0;
        CURRENT->buffer += 512;
        CURRENT->sector++;
@@ -398,7 +392,7 @@ ok_to_write:
                end_request(1);
        if (i > 0) {
                SET_INTR(&write_intr);
-               port_write(HD_DATA,CURRENT->buffer,256);
+               outsw(HD_DATA,CURRENT->buffer,256);
                sti();
        } else {
 #if (HD_DELAY > 0)
@@ -508,7 +502,7 @@ repeat:
                        bad_rw_intr();
                        goto repeat;
                }
-               port_write(HD_DATA,CURRENT->buffer,256);
+               outsw(HD_DATA,CURRENT->buffer,256);
                sti();
                return;
        }
index a19a7a57fea4a249b967cb459f44af55cf15b28a..0823dc72dd4038c0299d34ab853d63b0ca952e2e 100644 (file)
@@ -233,8 +233,8 @@ static unsigned char * translations[] = {
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        " !\"#$%&'()*+,-./0123456789:;<=>?"
        "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
-       "\004\261\007\007\007\007\370\361\040\007\331\277\332\300\305\007"
-       "\007\304\007\007\303\264\301\302\263\007\007\007\007\007\234\0"
+       "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
+       "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
        "\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
index cb7a649903df5a22345360dc2fbd23ab58bf1440..c25c17b02bab73a514bbd351b38ea54841c11186 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/serial.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
+#include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
@@ -1580,7 +1581,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
         * If this is a callout device, then just make sure the normal
         * device isn't being used.
         */
-       if (MAJOR(filp->f_rdev) == 5) {
+       if (MAJOR(filp->f_rdev) == TTYAUX_MAJOR) {
                if (info->flags & ASYNC_NORMAL_ACTIVE)
                        return -EBUSY;
                if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
@@ -1694,7 +1695,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
        tty->start = rs_start;
        tty->hangup = rs_hangup;
        if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-               if (MAJOR(filp->f_rdev) == 4) 
+               if (MAJOR(filp->f_rdev) == TTY_MAJOR)
                        *tty->termios = info->normal_termios;
                else 
                        *tty->termios = info->callout_termios;
index 1a2ac8b1d2c8e2250e525860cf515d6d4aaf59ff..44f094b8e785b81ad6ff5cb8fe95f967e6019ed1 100644 (file)
@@ -55,6 +55,8 @@
 
 #include "vt_kern.h"
 
+#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
+
 #define MAX_TTYS 256
 
 struct tty_struct *tty_table[MAX_TTYS];
@@ -239,13 +241,13 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
 
        if (!tty)
                return;
-       dev = 0x0400 + tty->line;
+       dev = MKDEV(TTY_MAJOR,tty->line);
        for (filp = first_file, i=0; i<nr_files; i++, filp = filp->f_next) {
-       if (!filp->f_count)
+               if (!filp->f_count)
                        continue;
                if (filp->f_rdev != dev)
                        continue;
-               if (filp->f_inode && filp->f_inode->i_rdev == 0x0400)
+               if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV)
                        continue;
                if (filp->f_op != &tty_fops)
                        continue;
@@ -1031,7 +1033,7 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
        tty = TTY_TABLE(dev);
        if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
                return -EIO;
-       if ((inode->i_rdev != 0x0400) && /* don't stop on /dev/console */
+       if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
            (tty->pgrp > 0) &&
            (current->tty == dev) &&
            (tty->pgrp != current->pgrp))
@@ -1056,7 +1058,7 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
        struct tty_struct * tty;
 
        dev = file->f_rdev;
-       is_console = (inode->i_rdev == 0x0400);
+       is_console = (inode->i_rdev == CONSOLE_DEV);
        if (MAJOR(dev) != TTY_MAJOR) {
                printk("tty_write: pseudo-major != TTY_MAJOR\n");
                return -EINVAL;
@@ -1396,7 +1398,7 @@ static int tty_open(struct inode * inode, struct file * filp)
                tty->session = current->session;
                tty->pgrp = current->pgrp;
        }
-       filp->f_rdev = 0x0400 | minor; /* Set it to something normal */
+       filp->f_rdev = MKDEV(TTY_MAJOR,minor); /* Set it to something normal */
        return 0;
 }
 
index 44c54309f7068cac8a028151d0239428bcae6624..9b9d4dbfc6ffe798329363f46c3b50fd1b13aa4a 100644 (file)
@@ -38,7 +38,6 @@ static char *version =
 #include <errno.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
@@ -321,7 +320,7 @@ el_start_xmit(struct sk_buff *skb, struct device *dev)
        inb(TX_STATUS);
        outb(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
        outw(gp_start, GP_LOW);
-       port_write_b(DATAPORT,buf,skb->len);
+       outsb(DATAPORT,buf,skb->len);
        outw(gp_start, GP_LOW);
        outb(AX_XMIT, AX_CMD);          /* Trigger xmit.  */
        dev->trans_start = jiffies;
@@ -464,7 +463,7 @@ el_receive(struct device *dev)
        skb->len = pkt_len;
        skb->dev = dev;
 
-       port_read_b(DATAPORT, (void *)(skb+1), pkt_len);
+       insb(DATAPORT, (void *)(skb+1), pkt_len);
 
 #ifdef HAVE_NETIF_RX
            netif_rx(skb);
index 64c45320a6a3952cdc0e07aa9d8e970b1e54b083..f55131ff75342802056ef19a38fc401336f4f0aa 100644 (file)
@@ -50,7 +50,6 @@ static char *version =
 #include <memory.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
index f0898d266c3ebcfae7b7fef7cca9700b0bfcf4e8..d517cd4f08c437cae9e8c8263ec621acb67f4500 100644 (file)
@@ -33,16 +33,6 @@ static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n";
 #include "skbuff.h"
 #include "arp.h"
 
-#ifndef port_read
-#include "iow.h"
-#endif
-
-/* These should be in <asm/io.h>. */
-#define port_read_l(port,buf,nr) \
-__asm__("cld;rep;insl": :"d" (port),"D" (buf),"c" (nr):"cx","di")
-#define port_write_l(port,buf,nr) \
-__asm__("cld;rep;outsl": :"d" (port),"S" (buf),"c" (nr):"cx","si")
-
 #ifndef HAVE_ALLOC_SKB
 #define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
 #endif
@@ -415,7 +405,7 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
                outw(skb->len, ioaddr + TX_FIFO);
                outw(0x00, ioaddr + TX_FIFO);
                /* ... and the packet rounded to a doubleword. */
-               port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
+               outsl(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
        
                dev->trans_start = jiffies;
                if (inw(ioaddr + TX_FREE) > 1536) {
@@ -588,7 +578,7 @@ el3_rx(struct device *dev)
                                skb->dev = dev;
 
                                /* 'skb+1' points to the start of sk_buff data area. */
-                               port_read_l(ioaddr+RX_FIFO, (void *)(skb+1),
+                               insl(ioaddr+RX_FIFO, (void *)(skb+1),
                                                        (pkt_len + 3) >> 2);
 
 #ifdef HAVE_NETIF_RX
index fe619c85a1d6805500a0bc65c94b109ffe6f2ccd..d31cd66e38683dc81a8b5b78a4c1aec2b28c0362 100644 (file)
@@ -38,7 +38,6 @@ static char *version =
 #include <memory.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
@@ -426,7 +425,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
                outb(0x00, ioaddr + TX_INTR);
                
                outw(length, ioaddr + DATAPORT);
-               port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+               outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
 
                lp->tx_queue++;
                lp->tx_queue_len += length + 2;
@@ -553,7 +552,7 @@ net_rx(struct device *dev)
                        skb->dev = dev;
 
                        /* 'skb+1' points to the start of sk_buff data area. */
-                       port_read(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1);
+                       insw(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1);
 
                        if (net_debug > 5) {
                                int i;
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
new file mode 100644 (file)
index 0000000..f753c79
--- /dev/null
@@ -0,0 +1,789 @@
+/* atp.c: Attached (pocket) ethernet adaptor driver for linux. */
+/*
+       Written 1993 by Donald Becker.
+       Copyright 1993 United States Government as represented by the Director,
+       National Security Agency.  This software may only be used and distributed
+       according to the terms of the GNU Public License as modified by SRC,
+       incorported herein by reference.
+
+       The author may be reached as becker@super.org or
+       C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+*/
+
+static char *version =
+       "atp.c:v0.02 12/22/93 Donald Becker (becker@super.org)\n";
+
+/*
+       This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket
+       ethernet adaptor.  This is a common low-cost OEM pocket ethernet
+       adaptor, sold under many names.
+
+  Sources:
+       This driver was written from the packet driver assembly code provided by
+       Vincent Bono of AT-Lan-Tec.      Ever try to figure out how a complicated
+       device works just from the assembly code?  It ain't pretty.  The following
+       description is written based on guesses and writing lots of special-purpose
+       code to test my theorized operation.
+
+                                       Theory of Operation
+       
+       The RTL8002 adaptor seems to be built around a custom spin of the SEEQ
+       controller core.  It probably has a 16K or 64K internal packet buffer, of
+       which the first 4K is devoted to transmit and the rest to receive.
+       The controller maintains the queue of received packet and the packet buffer
+       access pointer internally, with only 'reset to beginning' and 'skip to next
+       packet' commands visible.  The transmit packet queue holds two (or more?)
+       packets: both 'retransmit this packet' (due to collision) and 'transmit next
+       packet' commands must be started by hand.
+
+       The station address is stored in a standard bit-serial EEPROM which must be
+       read (ughh) by the device driver.  (Provisions have been made for
+       substituting a 74S288 PROM, but I haven't gotten reports of any models
+       using it.)  Unlike built-in devices, a pocket adaptor can temporarily lose
+       power without indication to the device driver.  The major effect is that
+       the station address, receive filter (promiscuous, etc.) and transceiver
+       must be reset.
+
+       The controller itself has 16 registers, some of which use only the lower
+       bits.  The registers are read and written 4 bits at a time.  The four bit
+       register address is presented on the data lines along with a few additional
+       timing and control bits.  The data is then read from status port or written
+       to the data port.
+
+       Since the bulk data transfer of the actual packets through the slow
+       parallel port dominates the driver's running time, four distinct data
+       (non-register) transfer modes are provided by the adaptor, two in each
+       direction.  In the first mode timing for the nibble transfers is
+       provided through the data port.  In the second mode the same timing is
+       provided through the control port.  In either case the data is read from
+       the status port and written to the data port, just as it is accessing
+       registers.
+
+       In addition to the basic data transfer methods, several more are modes are
+       created by adding some delay by doing multiple reads of the data to allow
+       it to stabilize.  This delay seems to be needed on most machines.
+
+       The data transfer mode is stored in the 'dev->if_port' field.  Its default
+       value is '4'.  It may be overriden at boot-time using the third parameter
+       to the "ether=..." initialization.
+
+       The header file <atp.h> provides inline functions that encapsulate the
+       register and data access methods.  These functions are hand-tuned to
+       generate reasonable object code.  This header file also documents my
+       interpretations of the device registers.
+*/
+
+#include <linux/config.h>              /* Used only to override default values. */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+
+#include "dev.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#include "atp.h"
+
+/* Compatibility definitions for earlier kernel versions. */
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c, in ioport.h for later versions. */
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+/* The map from IRQ number (as passed to the interrupt handler) to
+   'struct device'. */
+extern struct device *irq2dev_map[16];
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(addr, size) kfree_s(addr,size);
+#endif
+
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size)             0
+#define snarf_region(ioaddr, size);            do ; while (0)
+#endif
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 4
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* The number of low I/O ports used by the ethercard. */
+#define ETHERCARD_TOTAL_SIZE   3
+
+/* Index to functions, as function prototypes. */
+
+extern int atp_probe(struct device *dev);
+
+static int atp_probe1(struct device *dev, short ioaddr);
+static void init_dev(struct device *dev);
+static void get_node_ID(struct device *dev);
+static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
+static int net_open(struct device *dev);
+static void hardware_init(struct device *dev);
+static void write_packet(short ioaddr, int length, unsigned char *packet, int mode);
+static void trigger_send(short ioaddr, int length);
+static int     net_send_packet(struct sk_buff *skb, struct device *dev);
+static void net_interrupt(int reg_ptr);
+static void net_rx(struct device *dev);
+static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
+static int net_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+\f
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, alloate space for the device and return success
+   (detachable devices only).
+   */
+int
+atp_init(struct device *dev)
+{
+       int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
+       int base_addr = dev->base_addr;
+
+       if (base_addr > 0x1ff)          /* Check a single specified location. */
+               return atp_probe1(dev, base_addr);
+       else if (base_addr == 1)        /* Don't probe at all. */
+               return ENXIO;
+
+       for (port = ports; *port; port++) {
+               int ioaddr = *port;
+               outb(0x57, ioaddr + PAR_DATA);
+               if (inb(ioaddr + PAR_DATA) != 0x57)
+                       continue;
+               if (atp_probe1(dev, ioaddr) == 0)
+                       return 0;
+       }
+
+       return ENODEV;
+}
+
+static int atp_probe1(struct device *dev, short ioaddr)
+{
+       int saved_ctrl_reg, status;
+
+       outb(0xff, ioaddr + PAR_DATA);
+       /* Save the original value of the Control register, in case we guessed
+          wrong. */
+       saved_ctrl_reg = inb(ioaddr + PAR_CONTROL);
+       /* IRQEN=0, SLCTB=high INITB=high, AUTOFDB=high, STBB=high. */
+       outb(0x04, ioaddr + PAR_CONTROL);
+       write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+       eeprom_delay(2048);
+       status = read_nibble(ioaddr, CMR1);
+
+       if ((status & 0x78) != 0x08) {
+               /* The pocket adaptor probe failed, restore the control register. */
+               outb(saved_ctrl_reg, ioaddr + PAR_CONTROL);
+               return 1;
+       }
+       status = read_nibble(ioaddr, CMR2_h);
+       if ((status & 0x78) != 0x10) {
+               outb(saved_ctrl_reg, ioaddr + PAR_CONTROL);
+               return 1;
+       }
+       /* Find the IRQ used by triggering an interrupt. */
+       write_reg_byte(ioaddr, CMR2, 0x01);                     /* No accept mode, IRQ out. */
+       write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);  /* Enable Tx and Rx. */
+
+       /* Omit autoIRQ routine for now. Use "table lookup" instead.  Uhgggh. */
+       if (ioaddr == 0x378)
+               dev->irq = 7;
+       else
+               dev->irq = 5;
+       write_reg_high(ioaddr, CMR1, CMR1h_TxRxOFF); /* Diable Tx and Rx units. */
+       write_reg(ioaddr, CMR2, CMR2_NULL);
+
+       dev->base_addr = ioaddr;
+
+       /* Read the station address PROM.  */
+       get_node_ID(dev);
+
+       printk("%s: Pocket adaptor found at %#3x, IRQ %d, SAPROM "
+                  "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
+                  dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+                  dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+       /* Leave the hardware in a reset state. */
+    write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+
+       if (net_debug)
+               printk(version);
+
+       /* Initialize the device structure. */
+       init_dev(dev);
+       dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+       memset(dev->priv, 0, sizeof(struct net_local));
+
+
+       {
+               struct net_local *lp = (struct net_local *)dev->priv;
+               lp->addr_mode = CMR2h_Normal;
+       }
+
+       /* For the ATP adaptor the "if_port" is really the data transfer mode. */
+       dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4;
+       if (dev->mem_end & 0xf)
+               net_debug = dev->mem_end & 7;
+
+       dev->open               = net_open;
+       dev->stop               = net_close;
+       dev->hard_start_xmit = net_send_packet;
+       dev->get_stats  = net_get_stats;
+#ifdef HAVE_MULTICAST
+       dev->set_multicast_list = &set_multicast_list;
+#endif
+
+       return 0;
+}
+
+/* Fill in the fields of the device structure with ethernet-generic values.
+   This should be in a common file instead of per-driver.  */
+static void init_dev(struct device *dev)
+{
+       int i;
+
+       for (i = 0; i < DEV_NUMBUFFS; i++)
+               dev->buffs[i] = NULL;
+
+       dev->hard_header        = eth_header;
+       dev->add_arp            = eth_add_arp;
+       dev->queue_xmit         = dev_queue_xmit;
+       dev->rebuild_header = eth_rebuild_header;
+       dev->type_trans         = eth_type_trans;
+
+       dev->type                       = ARPHRD_ETHER;
+       dev->hard_header_len = ETH_HLEN;
+       dev->mtu                        = 1500; /* eth_mtu */
+       dev->addr_len           = ETH_ALEN;
+       for (i = 0; i < ETH_ALEN; i++) {
+               dev->broadcast[i]=0xff;
+       }
+
+       /* New-style flags. */
+       dev->flags                      = IFF_BROADCAST;
+       dev->family                     = AF_INET;
+       dev->pa_addr            = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+       dev->pa_alen            = sizeof(unsigned long);
+}
+
+/* Read the station address PROM, usually a word-wide EEPROM. */
+static void get_node_ID(struct device *dev)
+{
+       short ioaddr = dev->base_addr;
+       int sa_offset = 0;
+       int i;
+       
+       write_reg(ioaddr, CMR2, CMR2_EEPROM);     /* Point to the EEPROM control registers. */
+       
+       /* Some adaptors have the station address at offset 15 instead of offset
+          zero.  Check for it, and fix it if needed. */
+       if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff)
+               sa_offset = 15;
+       
+       for (i = 0; i < 3; i++)
+               ((unsigned short *)dev->dev_addr)[i] =
+                       ntohs(eeprom_op(ioaddr, EE_READ(sa_offset + i)));
+       
+       write_reg(ioaddr, CMR2, CMR2_NULL);
+}
+
+/*
+  An EEPROM read command starts by shifting out 0x60+address, and then
+  shifting in the serial data. See the NatSemi databook for details.
+ *                ________________
+ * CS : __|
+ *                        ___     ___
+ * CLK: ______|          |___|   |
+ *              __ _______ _______
+ * DI :         __X_______X_______X
+ * DO :         _________X_______X
+ */
+
+static unsigned short eeprom_op(short ioaddr, unsigned int cmd)
+{
+       unsigned eedata_out = 0;
+       int num_bits = EE_CMD_SIZE;
+       
+       while (--num_bits >= 0) {
+               char outval = test_bit(num_bits, &cmd) ? EE_DATA_WRITE : 0;
+               write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_LOW);
+               eeprom_delay(5);
+               write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_HIGH);
+               eedata_out <<= 1;
+               if (read_nibble(ioaddr, PROM_DATA) & EE_DATA_READ)
+                       eedata_out++;
+               eeprom_delay(5);
+       }
+       write_reg_high(ioaddr, PROM_CMD, EE_CLK_LOW & ~EE_CS);
+       return eedata_out;
+}
+
+\f
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine sets everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+
+   This is an attachable device: if there is no dev->priv entry then it wasn't
+   probed for at boot-time, and we need to probe for it again.
+   */
+static int net_open(struct device *dev)
+{
+
+       /* The interrupt line is turned off (tri-stated) when the device isn't in
+          use.  That's especially important for "attached" interfaces where the
+          port or interrupt may be shared. */
+       if (irq2dev_map[dev->irq] != 0
+               || (irq2dev_map[dev->irq] = dev) == 0
+               || request_irq(dev->irq, &net_interrupt)) {
+               return -EAGAIN;
+       }
+
+       hardware_init(dev);
+       dev->start = 1;
+       return 0;
+}
+
+/* This routine resets the hardware.  We initialize everything, assuming that
+   the hardware may have been temporarily detacted. */
+static void hardware_init(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+    int i;
+
+       write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+       
+    for (i = 0; i < 6; i++)
+               write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
+
+       write_reg_high(ioaddr, CMR2, lp->addr_mode);
+
+       if (net_debug > 2) {
+               printk("%s: Reset: current Rx mode %d.\n", dev->name,
+                          (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f);
+       }
+
+    write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+    write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
+
+       /* Enable the interrupt line from the serial port. */
+       outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+
+       /* Unmask the interesting interrupts. */
+    write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+    write_reg_high(ioaddr, IMR, ISRh_RxErr);
+
+       lp->tx_unit_busy = 0;
+    lp->pac_cnt_in_tx_buf = 0;
+       lp->saved_tx_size = 0;
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+}
+
+static void trigger_send(short ioaddr, int length)
+{
+       write_reg_byte(ioaddr, TxCNT0, length & 0xff);
+       write_reg(ioaddr, TxCNT1, length >> 8);
+       write_reg(ioaddr, CMR1, CMR1_Xmit);
+}
+
+static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode)
+{
+    length = (length + 1) & ~1;                /* Round up to word length. */
+    outb(EOC+MAR, ioaddr + PAR_DATA);
+    if ((data_mode & 1) == 0) {
+               /* Write the packet out, starting with the write addr. */
+               outb(WrAddr+MAR, ioaddr + PAR_DATA);
+               do {
+                       write_byte_mode0(ioaddr, *packet++);
+               } while (--length > 0) ;
+    } else {
+               /* Write the packet out in slow mode. */
+               unsigned char outbyte = *packet++;
+
+               outb(Ctrl_LNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+               outb(WrAddr+MAR, ioaddr + PAR_DATA);
+
+               outb((outbyte & 0x0f)|0x40, ioaddr + PAR_DATA);
+               outb(outbyte & 0x0f, ioaddr + PAR_DATA);
+               outbyte >>= 4;
+               outb(outbyte & 0x0f, ioaddr + PAR_DATA);
+               outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+               while (--length > 0)
+                       write_byte_mode1(ioaddr, *packet++);
+    }
+    /* Terminate the Tx frame.  End of write: ECB. */
+    outb(0xff, ioaddr + PAR_DATA);
+    outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+
+       if (dev->tbusy) {
+               /* If we get here, some higher level has decided we are broken.
+                  There should really be a "kick me" function call instead. */
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 5)
+                       return 1;
+               printk("%s: transmit timed out, %s?\n", dev->name,
+                          inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
+                          :  "IRQ conflict");
+               lp->stats.tx_errors++;
+               /* Try to restart the adaptor. */
+               hardware_init(dev);
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+       }
+
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       /* For ethernet, fill in the header.  This should really be done by a
+          higher level, rather than duplicated for each ethernet adaptor. */
+       if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
+               skb->dev = dev;
+               arp_queue (skb);
+               return 0;
+       }
+       skb->arp=1;
+
+       /* Block a timer-based transmit from overlapping.  This could better be
+          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0)
+               printk("%s: Transmitter access conflict.\n", dev->name);
+       else {
+               short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+               unsigned char *buf = (void *)(skb+1);
+               int flags;
+
+               /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
+                  This sequence must not be interrupted by an incoming packet. */
+               save_flags(flags);
+               cli();
+               write_reg(ioaddr, IMR, 0);
+               write_reg_high(ioaddr, IMR, 0);
+               restore_flags(flags);
+
+               write_packet(ioaddr, length, buf, dev->if_port);
+
+               lp->pac_cnt_in_tx_buf++;
+               if (lp->tx_unit_busy == 0) {
+                       trigger_send(ioaddr, length);
+                       lp->saved_tx_size = 0;                          /* Redundent */
+                       lp->re_tx = 0;
+                       lp->tx_unit_busy = 1;
+               } else
+                       lp->saved_tx_size = length;
+
+               dev->trans_start = jiffies;
+               /* Re-enable the LPT interrupts. */
+               write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+               write_reg_high(ioaddr, IMR, ISRh_RxErr);
+       }
+
+       if (skb->free)
+               kfree_skb (skb, FREE_WRITE);
+
+       return 0;
+}
+\f
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+net_interrupt(int reg_ptr)
+{
+       int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct net_local *lp;
+       int ioaddr, status, boguscount = 20;
+       static int num_tx_since_rx = 0;
+
+       if (dev == NULL) {
+               printk ("ATP_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+       dev->interrupt = 1;
+
+       ioaddr = dev->base_addr;
+       lp = (struct net_local *)dev->priv;
+
+       /* Disable additional spurious interrupts. */
+       outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
+
+       /* The adaptor's output is currently the IRQ line, switch it to data. */
+       write_reg(ioaddr, CMR2, CMR2_NULL);
+       write_reg(ioaddr, IMR, 0);
+
+       if (net_debug > 5) printk("%s: In interrupt ", dev->name);
+    while (--boguscount > 0) {
+               status = read_nibble(ioaddr, ISR);
+               if (net_debug > 5) printk("loop status %02x..", status);
+
+               if (status & (ISR_RxOK<<3)) {
+                       write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */
+                       do {
+                               int read_status = read_nibble(ioaddr, CMR1);
+                               if (net_debug > 6)
+                                       printk("handling Rx packet %02x..", read_status);
+                               /* We acknowledged the normal Rx interrupt, so if the interrupt
+                                  is still outstanding we must have a Rx error. */
+                               if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */
+                                       lp->stats.rx_over_errors++;
+                                       /* Set to no-accept mode long enough to remove a packet. */
+                                       write_reg_high(ioaddr, CMR2, CMR2h_OFF);
+                                       net_rx(dev);
+                                       /* Clear the interrupt and return to normal Rx mode. */
+                                       write_reg_high(ioaddr, ISR, ISRh_RxErr);
+                                       write_reg_high(ioaddr, CMR2, lp->addr_mode);
+                               } else if ((read_status & (CMR1_BufEnb << 3)) == 0) {
+                                       net_rx(dev);
+                                       dev->last_rx = jiffies;
+                                       num_tx_since_rx = 0;
+                               } else
+                                       break;
+                       } while (--boguscount > 0);
+               } else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) {
+                       if (net_debug > 6)  printk("handling Tx done..");
+                       /* Clear the Tx interrupt.  We should check for too many failures
+                          and reinitialize the adaptor. */
+                       write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);
+                       if (status & (ISR_TxErr<<3)) {
+                               lp->stats.collisions++;
+                               if (++lp->re_tx > 15) {
+                                       lp->stats.tx_aborted_errors++;
+                                       hardware_init(dev);
+                                       break;
+                               }
+                               /* Attempt to retransmit. */
+                               if (net_debug > 6)  printk("attempting to ReTx");
+                               write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
+                       } else {
+                               /* Finish up the transmit. */
+                               lp->stats.tx_packets++;
+                               lp->pac_cnt_in_tx_buf--;
+                               if ( lp->saved_tx_size) {
+                                       trigger_send(ioaddr, lp->saved_tx_size);
+                                       lp->saved_tx_size = 0;
+                                       lp->re_tx = 0;
+                               } else
+                                       lp->tx_unit_busy = 0;
+                               dev->tbusy = 0;
+                               mark_bh(INET_BH);       /* Inform upper layers. */
+                       }
+                       num_tx_since_rx++;
+               } else if (num_tx_since_rx > 8
+                                  && jiffies > dev->last_rx + 100) {
+                       if (net_debug > 2)
+                               printk("%s: Missed packet? No Rx after %d Tx and %d jiffies"
+                                          " status %02x  CMR1 %02x.\n", dev->name,
+                                          num_tx_since_rx, jiffies - dev->last_rx, status,
+                                          (read_nibble(ioaddr, CMR1) >> 3) & 15);
+                       lp->stats.rx_missed_errors++;
+                       hardware_init(dev);
+                       num_tx_since_rx = 0;
+                       break;
+               } else
+                       break;
+    }
+
+       /* Tell the adaptor that it can go back to using the output line as IRQ. */
+    write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+       /* Enable the physical interrupt line, which is sure to be low until.. */
+       outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+       /* .. we enable the interrupt sources. */
+       write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+       write_reg_high(ioaddr, IMR, ISRh_RxErr);                        /* Hmmm, really needed? */
+
+       if (net_debug > 5) printk("exiting interrupt.\n");
+
+       dev->interrupt = 0;
+
+       return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void net_rx(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+#ifdef notdef
+       ushort header[4];
+#else
+       struct rx_header rx_head;
+#endif
+
+       /* Process the received packet. */
+       outb(EOC+MAR, ioaddr + PAR_DATA);
+       read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port);
+       if (net_debug > 5)
+               printk(" rx_count %04x %04x %04x %04x..", rx_head.pad,
+                          rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr);
+       if ((rx_head.rx_status & 0x77) != 0x01) {
+               lp->stats.rx_errors++;
+               /* Ackkk!  I don't have any documentation on what the error bits mean!
+                  The best I can do is slap the device around a bit. */
+               if (net_debug > 3) printk("%s: Unknown ATP Rx error %04x.\n",
+                                                                 dev->name, rx_head.rx_status);
+               hardware_init(dev);
+               return;
+       } else {
+               /* Malloc up new buffer. */
+               int pkt_len = (rx_head.rx_count & 0x7ff) - 4;           /* The "-4" is omits the FCS (CRC). */
+               int sksize = sizeof(struct sk_buff) + pkt_len;
+               struct sk_buff *skb;
+               
+               skb = alloc_skb(sksize, GFP_ATOMIC);
+               if (skb == NULL) {
+                       printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+                       lp->stats.rx_dropped++;
+                       goto done;
+               }
+               skb->mem_len = sksize;
+               skb->mem_addr = skb;
+               skb->len = pkt_len;
+               skb->dev = dev;
+               
+               /* 'skb+1' points to the start of sk_buff data area. */
+               read_block(ioaddr, pkt_len, (unsigned char *)(skb + 1), dev->if_port);
+
+               if (net_debug > 6) {
+                       unsigned char *data = (unsigned char *)(skb + 1);
+                       printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..",
+                                  data[0], data[1], data[2], data[3], data[4], data[5],
+                                  data[6], data[7], data[8], data[9], data[10], data[11],
+                                  data[12], data[13]);
+               }
+               
+#ifdef HAVE_NETIF_RX
+               netif_rx(skb);
+#else
+               skb->lock = 0;
+               if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+                       kfree_s(skb, sksize);
+                       lp->stats.rx_dropped++;
+                       break;
+               }
+#endif
+               lp->stats.rx_packets++;
+       }
+ done:
+       write_reg(ioaddr, CMR1, CMR1_NextPkt);
+       return;
+}
+
+static void read_block(short ioaddr, int length, unsigned char *p, int data_mode)
+{
+
+       if (data_mode <= 3) { /* Mode 0 or 1 */
+               outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+               outb(length == 8  ?  RdAddr | HNib | MAR  :  RdAddr | MAR,
+                        ioaddr + PAR_DATA);
+               if (data_mode <= 1) { /* Mode 0 or 1 */
+                       do  *p++ = read_byte_mode0(ioaddr);  while (--length > 0);
+               } else  /* Mode 2 or 3 */
+                       do  *p++ = read_byte_mode2(ioaddr);  while (--length > 0);
+       } else if (data_mode <= 5)
+               do      *p++ = read_byte_mode4(ioaddr);  while (--length > 0);
+       else
+               do      *p++ = read_byte_mode6(ioaddr);  while (--length > 0);
+
+    outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
+       outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       int ioaddr = dev->base_addr;
+
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       /* Flush the Tx and disable Rx here. */
+       lp->addr_mode = CMR2h_OFF;
+       write_reg_high(ioaddr, CMR2, CMR2h_OFF);
+
+       /* Free the IRQ line. */
+       outb(0x00, ioaddr + PAR_CONTROL);
+       free_irq(dev->irq);
+       irq2dev_map[dev->irq] = 0;
+
+       /* Leave the hardware in a reset state. */
+    write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+
+       return 0;
+}
+
+/* Get the current statistics. This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+net_get_stats(struct device *dev)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1     Promiscuous mode, receive all packets
+   num_addrs == 0      Normal mode, clear multicast list
+   num_addrs > 0       Multicast mode, receive normal and MC packets, and do
+                       best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+       struct net_local *lp = (struct net_local *)dev->priv;
+       short ioaddr = dev->base_addr;
+       lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal;
+       write_reg_high(ioaddr, CMR2, lp->addr_mode);
+}
+#endif
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/atp.h b/drivers/net/atp.h
new file mode 100644 (file)
index 0000000..6988eae
--- /dev/null
@@ -0,0 +1,264 @@
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+struct net_local {
+#ifdef __KERNEL__
+    struct enet_statistics stats;
+#endif
+    ushort saved_tx_size;
+    unsigned char
+       re_tx,                  /* Number of packet retransmissions. */
+       tx_unit_busy,
+       addr_mode,              /* Current Rx filter e.g. promiscuous, etc. */
+       pac_cnt_in_tx_buf;
+};
+
+struct rx_header {
+    ushort pad;                        /* The first read is always corrupted. */
+    ushort rx_count;
+    ushort rx_status;          /* Unknown bit assignments :-<.  */
+    ushort cur_addr;           /* Apparently the current buffer address(?) */
+};
+
+#define PAR_DATA       0
+#define PAR_STATUS     1
+#define PAR_CONTROL 2
+
+#define Ctrl_LNibRead  0x08    /* LP_PSELECP */
+#define Ctrl_HNibRead  0
+#define Ctrl_LNibWrite 0x08    /* LP_PSELECP */
+#define Ctrl_HNibWrite 0
+#define Ctrl_SelData   0x04    /* LP_PINITP */
+#define Ctrl_IRQEN     0x10    /* LP_PINTEN */
+
+#define EOW    0xE0
+#define EOC    0xE0
+#define WrAddr 0x40    /* Set address of EPLC read, write register. */
+#define RdAddr 0xC0
+#define HNib   0x10
+
+enum page0_regs
+{
+    /* The first six registers hold the ethernet physical station address. */
+    PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5,
+    TxCNT0 = 6, TxCNT1 = 7,            /* The transmit byte count. */
+    TxSTAT = 8, RxSTAT = 9,            /* Tx and Rx status. */
+    ISR = 10, IMR = 11,                        /* Interrupt status and mask. */
+    CMR1 = 12,                         /* Command register 1. */
+    CMR2 = 13,                         /* Command register 2. */
+    MAR = 14,                          /* Memory address register. */
+    CMR2_h = 0x1d, };
+
+enum eepage_regs
+{ PROM_CMD = 6, PROM_DATA = 7 };       /* Note that PROM_CMD is in the "high" bits. */
+
+
+#define ISR_TxOK       0x01
+#define ISR_RxOK       0x04
+#define ISR_TxErr      0x02
+#define ISRh_RxErr     0x11    /* ISR, high nibble */
+
+#define CMR1h_RESET    0x04    /* Reset. */
+#define CMR1h_RxENABLE 0x02    /* Rx unit enable.  */
+#define CMR1h_TxENABLE 0x01    /* Tx unit enable.  */
+#define CMR1h_TxRxOFF  0x00
+#define CMR1_ReXmit    0x08    /* Trigger a retransmit. */
+#define CMR1_Xmit      0x04    /* Trigger a transmit. */
+#define        CMR1_IRQ        0x02    /* Interrupt active. */
+#define        CMR1_BufEnb     0x01    /* Enable the buffer(?). */
+#define        CMR1_NextPkt    0x01    /* Enable the buffer(?). */
+
+#define CMR2_NULL      8
+#define CMR2_IRQOUT    9
+#define CMR2_RAMTEST   10
+#define CMR2_EEPROM    12      /* Set to page 1, for reading the EEPROM. */
+
+#define CMR2h_OFF      0       /* No accept mode. */
+#define CMR2h_Physical 1       /* Accept a physical address match only. */
+#define CMR2h_Normal   2       /* Accept physical and broadcast address. */
+#define CMR2h_PROMISC  3       /* Promiscuous mode. */
+
+/* An inline function used below: it differs from inb() by explicitly return an unsigned
+   char, saving a truncation. */
+extern inline unsigned char inbyte(unsigned short port)
+{
+    unsigned char _v;
+    __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port));
+    return _v;
+}
+
+/* Read register OFFSET.
+   This command should aways be terminated with read_end(). */
+extern inline unsigned char read_nibble(short port, unsigned char offset)
+{
+    unsigned char retval;
+    outb(EOC+offset, port + PAR_DATA);
+    outb(RdAddr+offset, port + PAR_DATA);
+    inbyte(port + PAR_STATUS);         /* Settling time delay */
+    retval = inbyte(port + PAR_STATUS);
+    outb(EOC+offset, port + PAR_DATA);
+
+    return retval;
+}
+
+/* Functions for bulk data read.  The interrupt line is always disabled. */
+/* Get a byte using read mode 0, reading data from the control lines. */
+extern inline unsigned char read_byte_mode0(short ioaddr)
+{
+    unsigned char low_nib;
+
+    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+    inbyte(ioaddr + PAR_STATUS);
+    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
+    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
+    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+}
+
+/* The same as read_byte_mode0(), but does multiple inb()s for stability. */
+extern inline unsigned char read_byte_mode2(short ioaddr)
+{
+    unsigned char low_nib;
+
+    outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);
+    inbyte(ioaddr + PAR_STATUS);
+    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+    outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL);
+    inbyte(ioaddr + PAR_STATUS);       /* Settling time delay -- needed!  */
+    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+}
+
+/* Read a byte through the data register. */
+extern inline unsigned char read_byte_mode4(short ioaddr)
+{
+    unsigned char low_nib;
+
+    outb(RdAddr | MAR, ioaddr + PAR_DATA);
+    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+}
+
+/* Read a byte through the data register, double reading to allow settling. */
+extern inline unsigned char read_byte_mode6(short ioaddr)
+{
+    unsigned char low_nib;
+
+    outb(RdAddr | MAR, ioaddr + PAR_DATA);
+    inbyte(ioaddr + PAR_STATUS);
+    low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f;
+    outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA);
+    inbyte(ioaddr + PAR_STATUS);
+    return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0);
+}
+
+extern inline void
+write_reg(short port, unsigned char reg, unsigned char value)
+{
+    unsigned char outval;
+    outb(EOC | reg, port + PAR_DATA);
+    outval = WrAddr | reg;
+    outb(outval, port + PAR_DATA);
+    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
+
+    outval &= 0xf0;
+    outval |= value;
+    outb(outval, port + PAR_DATA);
+    outval &= 0x1f;
+    outb(outval, port + PAR_DATA);
+    outb(outval, port + PAR_DATA);
+
+    outb(EOC | outval, port + PAR_DATA);
+}
+
+extern inline void
+write_reg_high(short port, unsigned char reg, unsigned char value)
+{
+    unsigned char outval = EOC | HNib | reg;
+
+    outb(outval, port + PAR_DATA);
+    outval &= WrAddr | HNib | 0x0f;
+    outb(outval, port + PAR_DATA);
+    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
+
+    outval = WrAddr | HNib | value;
+    outb(outval, port + PAR_DATA);
+    outval &= HNib | 0x0f;             /* HNib | value */
+    outb(outval, port + PAR_DATA);
+    outb(outval, port + PAR_DATA);
+
+    outb(EOC | HNib | outval, port + PAR_DATA);
+}
+
+/* Write a byte out using nibble mode.  The low nibble is written first. */
+extern inline void
+write_reg_byte(short port, unsigned char reg, unsigned char value)
+{
+    unsigned char outval;
+    outb(EOC | reg, port + PAR_DATA);  /* Reset the address register. */
+    outval = WrAddr | reg;
+    outb(outval, port + PAR_DATA);
+    outb(outval, port + PAR_DATA);     /* Double write for PS/2. */
+
+    outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA);
+    outb(value & 0x0f, port + PAR_DATA);
+    value >>= 4;
+    outb(value, port + PAR_DATA);
+    outb(0x10 | value, port + PAR_DATA);
+    outb(0x10 | value, port + PAR_DATA);
+
+    outb(EOC  | value, port + PAR_DATA);       /* Reset the address register. */
+}
+
+/*
+ * Bulk data writes to the packet buffer.  The interrupt line remains enabled.
+ * The first, faster method uses only the dataport (data modes 0, 2 & 4).
+ * The second (backup) method uses data and control regs (modes 1, 3 & 5).
+ * It should only be needed when there is skew between the individual data
+ * lines.
+ */
+extern inline void write_byte_mode0(short ioaddr, unsigned char value)
+{
+    outb(value & 0x0f, ioaddr + PAR_DATA);
+    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+}
+
+extern inline void write_byte_mode1(short ioaddr, unsigned char value)
+{
+    outb(value & 0x0f, ioaddr + PAR_DATA);
+    outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL);
+    outb((value>>4) | 0x10, ioaddr + PAR_DATA);
+    outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL);
+}
+
+/* Write 16bit VALUE to the packet buffer: the same as above just doubled. */
+extern inline void write_word_mode0(short ioaddr, unsigned short value)
+{
+    outb(value & 0x0f, ioaddr + PAR_DATA);
+    value >>= 4;
+    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+    value >>= 4;
+    outb(value & 0x0f, ioaddr + PAR_DATA);
+    value >>= 4;
+    outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA);
+}
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK   0x04    /* EEPROM shift clock. */
+#define EE_CS          0x02    /* EEPROM chip select. */
+#define EE_CLK_HIGH    0x12
+#define EE_CLK_LOW     0x16
+#define EE_DATA_WRITE  0x01    /* EEPROM chip data in. */
+#define EE_DATA_READ   0x08    /* EEPROM chip data out. */
+
+/* Delay between EEPROM clock transitions. */
+#define eeprom_delay(ticks) \
+do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD(offset)   (((5 << 6) + (offset)) << 17)
+#define EE_READ(offset)        (((6 << 6) + (offset)) << 17)
+#define EE_ERASE(offset)       (((7 << 6) + (offset)) << 17)
+#define EE_CMD_SIZE    27      /* The command+address+data size. */
index 41c2480c6ff84007a8f9d08d5f02558dd360b301..7daab328e81300d3e00833024a3796e88edfe3dd 100644 (file)
@@ -50,7 +50,6 @@ static char *version =
 #include <memory.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
@@ -701,7 +700,7 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
                   by the list of multicast addresses to be accepted. */
                outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR);
                outw(num_addrs * 6, ioaddr);
-               port_write(ioaddr, addrs, num_addrs*3);         /* 3 = addr len in words */
+               outsw(ioaddr, addrs, num_addrs*3);              /* 3 = addr len in words */
                /* We must trigger a whole 586 reset due to a bug. */
        } else {
                /* Not written yet, this requires expanding the init_words config
@@ -770,11 +769,11 @@ init_82586_mem(struct device *dev)
 
        /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */
        outw(0xfff6, ioaddr + WRITE_PTR);
-       port_write(ioaddr, init_words, sizeof(init_words)>>1);
+       outsw(ioaddr, init_words, sizeof(init_words)>>1);
 
        /* Fill in the station address. */
        outw(SA_OFFSET, ioaddr + WRITE_PTR);
-       port_write(ioaddr, dev->dev_addr, 3);
+       outsw(ioaddr, dev->dev_addr, 3);
 
        /* The Tx-block list is written as needed.  We just set up the values. */
 #ifdef initial_text_tx
@@ -882,7 +881,7 @@ hardware_send_packet(struct device *dev, void *buf, short length)
 
        /* Output the packet using the write pointer.
           Hmmm, it feels a little like a 3c501! */
-       port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+       outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
 
        /* Set the old command link pointing to this send packet. */
        outw(lp->tx_cmd_link, ioaddr + WRITE_PTR);
@@ -961,7 +960,7 @@ eexp_rx(struct device *dev)
 
                        outw(data_buffer_addr + 10, ioaddr + READ_PTR);
 
-                       port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
+                       insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
                
 #ifdef HAVE_NETIF_RX
                        netif_rx(skb);
index f6304f19b3d46a61fda931fbd571a2d27f7ebfcf..eda01d12d24aaa24ea60788665899bc515ea5ad1 100644 (file)
@@ -1,19 +1,19 @@
 /* hp.c: A HP LAN ethernet driver for linux. */
 /*
-    Written 1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU Public License,
-    incorporated herein by reference.
+       Written 1993 by Donald Becker.
+       Copyright 1993 United States Government as represented by the
+       Director, National Security Agency.      This software may be used and
+       distributed according to the terms of the GNU Public License,
+       incorporated herein by reference.
 
-    This is a driver for the HP LAN adaptors.
+       This is a driver for the HP LAN adaptors.
 
-    The Author may be reached as becker@super.org or
-    C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+       The Author may be reached as becker@super.org or
+       C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
 static char *version =
-    "hp.c:v0.99.13f 10/16/93 Donald Becker (becker@super.org)\n";
+       "hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -22,182 +22,194 @@ static char *version =
 #include <linux/ioport.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#ifndef port_read
-#include "iow.h"
-#endif
 
 #include "dev.h"
 #include "8390.h"
 
-#define HP_DATAPORT    0x0c    /* "Remote DMA" data port. */
-#define HP_ID          0x07
+#ifndef HAVE_PORTRESERVE
+#define check_region(ioaddr, size)                             0
+#define snarf_region(ioaddr, size);                            do ; while (0)
+#endif
+
+#define HP_IO_EXTENT   32
+
+#define HP_DATAPORT            0x0c    /* "Remote DMA" data port. */
+#define HP_ID                  0x07
 #define HP_CONFIGURE   0x08    /* Configuration register. */
-#define  HP_RUN                0x01    /* 1 == Run, 0 == reset. */
-#define  HP_IRQ                0x0E    /* Mask for software-configured IRQ line. */
-#define  HP_DATAON     0x10    /* Turn on dataport */
-#define NIC_OFFSET     0x10    /* Offset the 8390 registers. */
+#define         HP_RUN                 0x01    /* 1 == Run, 0 == reset. */
+#define         HP_IRQ                 0x0E    /* Mask for software-configured IRQ line. */
+#define         HP_DATAON              0x10    /* Turn on dataport */
+#define NIC_OFFSET             0x10    /* Offset the 8390 registers. */
 
-#define HP_START_PG    0x00    /* First page of TX buffer */
+#define HP_START_PG            0x00    /* First page of TX buffer */
 #define HP_8BSTOP_PG   0x80    /* Last page +1 of RX ring */
-#define HP_16BSTOP_PG  0xFF    /* Last page +1 of RX ring */
+#define HP_16BSTOP_PG  0xFF    /* Same, for 16 bit cards. */
 
 int hp_probe(struct device *dev);
-int hpprobe1(int ioaddr, struct device *dev);
+int hpprobe1(struct device *dev, int ioaddr);
 
 static void hp_reset_8390(struct device *dev);
 static int hp_block_input(struct device *dev, int count,
-                         char *buf, int ring_offset);
+                                                 char *buf, int ring_offset);
 static void hp_block_output(struct device *dev, int count,
-                           const unsigned char *buf, const start_page);
+                                                       const unsigned char *buf, const start_page);
 static void hp_init_card(struct device *dev);
 
 /* The map from IRQ number to HP_CONFIGURE register setting. */
-/* My default is IRQ5      0  1  2  3  4  5  6  7  8  9 10 11 */
+/* My default is IRQ5     0  1  2      3  4  5  6      7  8  9 10 11 */
 static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
 
 \f
-/*  Probe for an HP LAN adaptor.
-    Also initialize the card and fill in STATION_ADDR with the station
-   address. */
+/*     Probe for an HP LAN adaptor.
+       Also initialize the card and fill in STATION_ADDR with the station
+       address. */
 
 int hp_probe(struct device *dev)
 {
-    int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
-    short ioaddr = dev->base_addr;
+       int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
+       short ioaddr = dev->base_addr;
 
-    if (ioaddr > 0x1ff)                /* Check a single specified location. */
-       return ! hpprobe1(ioaddr, dev);
-    else if (ioaddr > 0)               /* Don't probe at all. */
+       if (ioaddr > 0x1ff)                     /* Check a single specified location. */
+               return hpprobe1(dev, ioaddr);
+       else if (ioaddr > 0)                            /* Don't probe at all. */
                return ENXIO;
 
-    for (port = &ports[0]; *port; port++) {
-#ifdef HAVE_PORTRESERVE
-       if (check_region(*port, 32))
-           continue;
-#endif
-       if (inb_p(*port) != 0xff && hpprobe1(*port, dev)) {
-           return 0;
+       for (port = &ports[0]; *port; port++) {
+               if (check_region(*port, HP_IO_EXTENT))
+                       continue;
+               if (hpprobe1(dev, *port) == 0) {
+                       return 0;
+               }
        }
-    }
-    dev->base_addr = ioaddr;
-    return ENODEV;
+       return ENODEV;
 }
 
-int hpprobe1(int ioaddr, struct device *dev)
+int hpprobe1(struct device *dev, int ioaddr)
 {
-  int i;
-  unsigned char *station_addr = dev->dev_addr;
-  int tmp;
-
-  /* Check for the HP physical address, 08 00 09 xx xx xx. */
-  if (inb(ioaddr) != 0x08
-      || inb(ioaddr+1) != 0x00
-      || inb(ioaddr+2) != 0x09)
-      return 0;
-  /* This really isn't good enough, we may pick up HP LANCE boards also! */
-
-  ethdev_init(dev);
-
-  ei_status.tx_start_page = HP_START_PG;
-  ei_status.rx_start_page = HP_START_PG + TX_PAGES;
-  /* Set up the rest of the parameters. */
-  if ((tmp = inb(ioaddr + HP_ID)) & 0x80) {
-      ei_status.name = "HP27247";
-      ei_status.word16 = 1;
-      ei_status.stop_page = HP_16BSTOP_PG; /* Safe (if small) value */
-  } else {
-      ei_status.name = "HP27250";
-      ei_status.word16 = 0;
-      ei_status.stop_page = HP_8BSTOP_PG;
-  }
-
-  printk("%s: %s at %#3x,", dev->name, ei_status.name, ioaddr);
-
-  for(i = 0; i < ETHER_ADDR_LEN; i++)
-      printk(" %2.2x", station_addr[i] = inb(ioaddr + i));
-
-
-  /* Set the base address to point to the NIC, not the "real" base! */
-  dev->base_addr = ioaddr + NIC_OFFSET;
-
-  /* Snarf the interrupt now.  Someday this could be moved to open(). */
-  if (dev->irq < 2) {
-      int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
-      int irq_8list[] = { 7, 5, 3, 4, 9, 0};
-      int *irqp = ei_status.word16 ? irq_16list : irq_8list;
-      do {
-         if (request_irq (dev->irq = *irqp, NULL) != -EBUSY) {
-             autoirq_setup(0);
-             /* Twinkle the interrupt, and check if it's seen. */
-             outb_p(irqmap[dev->irq] | HP_RUN, ioaddr + HP_CONFIGURE);
-             outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
-             if (dev->irq == autoirq_report(0)  /* It's a good IRQ line! */
-                 && request_irq (dev->irq, &ei_interrupt) == 0) {
-                 printk(" selecting IRQ %d.\n", dev->irq);
-                 break;
-             }
-         }
-      } while (*++irqp);
-      if (*irqp == 0) {
-         printk(" no free IRQ lines.\n");
-         return 0;
-      }
-  } else {
-      if (dev->irq == 2)
-         dev->irq = 9;
-      if (irqaction(dev->irq, &ei_sigaction)) {
-         printk (" unable to get IRQ %d.\n", dev->irq);
-         return 0;
-      }
-  }
-
-#ifdef HAVE_PORTRESERVE
-    snarf_region(ioaddr, 32);
-#endif
+       int status, i, board_id, wordmode;
+       char *name;
+       unsigned char *station_addr = dev->dev_addr;
+
+       /* Check for the HP physical address, 08 00 09 xx xx xx. */
+       if (inb(ioaddr) != 0x08
+               || inb(ioaddr+1) != 0x00
+               || inb(ioaddr+2) != 0x09)
+               return ENODEV;
+
+       /* This really isn't good enough, we may pick up HP LANCE boards also! */
+       /* Verify that there is a 8390 at the expected location. */
+       outb(E8390_NODMA + E8390_STOP, ioaddr);
+       SLOW_DOWN_IO;
+       status = inb(ioaddr);
+       if (status != 0x21 && status != 0x23)
+               return ENODEV;
+
+       /* Set up the parameters based on the board ID.
+          If you have additional mappings, please mail them to becker@super.org. */
+       if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
+               name = "HP27247";
+               wordmode = 1;
+       } else {
+               name = "HP27250";
+               wordmode = 0;
+       }
+
+       /* Grab the region so we can find another board if something fails. */
+       snarf_region(ioaddr, HP_IO_EXTENT);
+
+       printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
+
+       for(i = 0; i < ETHER_ADDR_LEN; i++)
+               printk(" %2.2x", station_addr[i] = inb(ioaddr + i));
+
+       /* Snarf the interrupt now.  Someday this could be moved to open(). */
+       if (dev->irq < 2) {
+               int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
+               int irq_8list[] = { 7, 5, 3, 4, 9, 0};
+               int *irqp = wordmode ? irq_16list : irq_8list;
+               do {
+                       int irq = *irqp;
+                       if (request_irq (irq, NULL) != -EBUSY) {
+                               autoirq_setup(0);
+                               /* Twinkle the interrupt, and check if it's seen. */
+                               outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
+                               outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
+                               if (irq == autoirq_report(0)             /* It's a good IRQ line! */
+                                       && request_irq (irq, &ei_interrupt) == 0) {
+                                       printk(" selecting IRQ %d.\n", irq);
+                                       dev->irq = *irqp;
+                                       break;
+                               }
+                       }
+               } while (*++irqp);
+               if (*irqp == 0) {
+                       printk(" no free IRQ lines.\n");
+                       return EBUSY;
+               }
+       } else {
+               if (dev->irq == 2)
+                       dev->irq = 9;
+               if (irqaction(dev->irq, &ei_sigaction)) {
+                       printk (" unable to get IRQ %d.\n", dev->irq);
+                       return EBUSY;
+               }
+       }
+
+       if (ei_debug > 1)
+               printk(version);
 
-  if (ei_debug > 1)
-      printk(version);
+       /* Set the base address to point to the NIC, not the "real" base! */
+       dev->base_addr = ioaddr + NIC_OFFSET;
 
-  ei_status.reset_8390 = &hp_reset_8390;
-  ei_status.block_input = &hp_block_input;
-  ei_status.block_output = &hp_block_output;
-  hp_init_card(dev);
-  return dev->base_addr;
+       ethdev_init(dev);
+
+       ei_status.name = name;
+       ei_status.word16 = wordmode;
+       ei_status.tx_start_page = HP_START_PG;
+       ei_status.rx_start_page = HP_START_PG + TX_PAGES;
+       ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
+
+       ei_status.reset_8390 = &hp_reset_8390;
+       ei_status.block_input = &hp_block_input;
+       ei_status.block_output = &hp_block_output;
+       hp_init_card(dev);
+
+       return 0;
 }
 
 static void
 hp_reset_8390(struct device *dev)
 {
-    int hp_base = dev->base_addr - NIC_OFFSET;
-    int saved_config = inb_p(hp_base + HP_CONFIGURE);
-    int reset_start_time = jiffies;
-
-    if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
-    outb_p(0x00, hp_base + HP_CONFIGURE);
-    ei_status.txing = 0;
-
-    sti();
-    /* We shouldn't use the boguscount for timing, but this hasn't been
-       checked yet, and you could hang your machine if jiffies break... */
-    {
-       int boguscount = 150000;
-       while(jiffies - reset_start_time < 2)
-           if (boguscount-- < 0) {
-               printk("jiffy failure (t=%d)...", jiffies);
-               break;
-           }
-    }
-
-    outb_p(saved_config, hp_base + HP_CONFIGURE);
-    while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-       if (jiffies - reset_start_time > 2) {
-           printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-           return;
+       int hp_base = dev->base_addr - NIC_OFFSET;
+       int saved_config = inb_p(hp_base + HP_CONFIGURE);
+       int reset_start_time = jiffies;
+
+       if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
+       outb_p(0x00, hp_base + HP_CONFIGURE);
+       ei_status.txing = 0;
+
+       sti();
+       /* We shouldn't use the boguscount for timing, but this hasn't been
+          checked yet, and you could hang your machine if jiffies break... */
+       {
+               int boguscount = 150000;
+               while(jiffies - reset_start_time < 2)
+                       if (boguscount-- < 0) {
+                               printk("jiffy failure (t=%d)...", jiffies);
+                               break;
+                       }
        }
-    if (ei_debug > 1) printk("8390 reset done (%d).", jiffies);
+
+       outb_p(saved_config, hp_base + HP_CONFIGURE);
+       while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
+               if (jiffies - reset_start_time > 2) {
+                       printk("%s: hp_reset_8390() did not complete.\n", dev->name);
+                       return;
+               }
+       if (ei_debug > 1) printk("8390 reset done (%d).", jiffies);
 }
 
-/* Block input and output, similar to the Crynwr packet driver.  If you
+/* Block input and output, similar to the Crynwr packet driver.         If you
    porting to a new ethercard look at the packet driver source for hints.
    The HP LAN doesn't use shared memory -- we put the packet
    out through the "remote DMA" dataport. */
@@ -205,111 +217,112 @@ hp_reset_8390(struct device *dev)
 static int
 hp_block_input(struct device *dev, int count, char *buf, int ring_offset)
 {
-    int nic_base = dev->base_addr;
-    int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-    int xfer_count = count;
-
-    outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8, nic_base + EN0_RCNTHI);
-    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base);
-    if (ei_status.word16) {
-      port_read(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
-      if (count & 0x01)
-       buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
-    } else {
-       port_read_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-    }
-    /* This is for the ALPHA version only, remove for later releases. */
-    if (ei_debug > 0) {                /* DMA termination address check... */
-      int high = inb_p(nic_base + EN0_RSARHI);
-      int low = inb_p(nic_base + EN0_RSARLO);
-      int addr = (high << 8) + low;
-      /* Check only the lower 8 bits so we can ignore ring wrap. */
-      if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
-       printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
-              dev->name, ring_offset + xfer_count, addr);
-    }
-    outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-    return ring_offset + count;
+       int nic_base = dev->base_addr;
+       int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
+       int xfer_count = count;
+
+       outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
+       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+       outb_p(count >> 8, nic_base + EN0_RCNTHI);
+       outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+       outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+       outb_p(E8390_RREAD+E8390_START, nic_base);
+       if (ei_status.word16) {
+         insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
+         if (count & 0x01)
+               buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
+       } else {
+               insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
+       }
+       /* This is for the ALPHA version only, remove for later releases. */
+       if (ei_debug > 0) {                     /* DMA termination address check... */
+         int high = inb_p(nic_base + EN0_RSARHI);
+         int low = inb_p(nic_base + EN0_RSARLO);
+         int addr = (high << 8) + low;
+         /* Check only the lower 8 bits so we can ignore ring wrap. */
+         if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
+               printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
+                          dev->name, ring_offset + xfer_count, addr);
+       }
+       outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
+       return ring_offset + count;
 }
 
 static void
 hp_block_output(struct device *dev, int count,
-               const unsigned char *buf, const start_page)
+                               const unsigned char *buf, const start_page)
 {
-    int nic_base = dev->base_addr;
-    int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
-
-    outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (ei_status.word16 && (count & 0x01))
-      count++;
-    /* We should already be in page 0, but to be safe... */
-    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
+       int nic_base = dev->base_addr;
+       int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
+
+       outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
+       /* Round the count up for word writes.  Do we need to do this?
+          What effect will an odd byte count have on the 8390?
+          I should check someday. */
+       if (ei_status.word16 && (count & 0x01))
+         count++;
+       /* We should already be in page 0, but to be safe... */
+       outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
 
 #ifdef ei8390_bug
-    /* Handle the read-before-write bug the same way as the
-       Crynwr packet driver -- the NatSemi method doesn't work. */
-    outb_p(0x42, nic_base + EN0_RCNTLO);
-    outb_p(0,   nic_base + EN0_RCNTHI);
-    outb_p(0xff, nic_base + EN0_RSARLO);
-    outb_p(0x00, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, EN_CMD);
-    /* Make certain that the dummy read has occured. */
-    inb_p(0x61);
-    inb_p(0x61);
+       /* Handle the read-before-write bug the same way as the
+          Crynwr packet driver -- the NatSemi method doesn't work. */
+       outb_p(0x42, nic_base + EN0_RCNTLO);
+       outb_p(0,       nic_base + EN0_RCNTHI);
+       outb_p(0xff, nic_base + EN0_RSARLO);
+       outb_p(0x00, nic_base + EN0_RSARHI);
+       outb_p(E8390_RREAD+E8390_START, EN_CMD);
+       /* Make certain that the dummy read has occured. */
+       inb_p(0x61);
+       inb_p(0x61);
 #endif
 
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
-    outb_p(0x00, nic_base + EN0_RSARLO);
-    outb_p(start_page, nic_base + EN0_RSARHI);
-
-    outb_p(E8390_RWRITE+E8390_START, nic_base);
-    if (ei_status.word16) {
-       /* Use the 'rep' sequence for 16 bit boards. */
-       port_write(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
-    } else {
-       port_write_b(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
-    }
-
-    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
-
-    /* This is for the ALPHA version only, remove for later releases. */
-    if (ei_debug > 0) {                /* DMA termination address check... */
-      int high = inb_p(nic_base + EN0_RSARHI);
-      int low  = inb_p(nic_base + EN0_RSARLO);
-      int addr = (high << 8) + low;
-      if ((start_page << 8) + count != addr)
-       printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
-              dev->name, (start_page << 8) + count, addr);
-    }
-    outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-    return;
+       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+       outb_p(count >> 8,       nic_base + EN0_RCNTHI);
+       outb_p(0x00, nic_base + EN0_RSARLO);
+       outb_p(start_page, nic_base + EN0_RSARHI);
+
+       outb_p(E8390_RWRITE+E8390_START, nic_base);
+       if (ei_status.word16) {
+               /* Use the 'rep' sequence for 16 bit boards. */
+               outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
+       } else {
+               outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
+       }
+
+       /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
+
+       /* This is for the ALPHA version only, remove for later releases. */
+       if (ei_debug > 0) {                     /* DMA termination address check... */
+         int high = inb_p(nic_base + EN0_RSARHI);
+         int low  = inb_p(nic_base + EN0_RSARLO);
+         int addr = (high << 8) + low;
+         if ((start_page << 8) + count != addr)
+               printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
+                          dev->name, (start_page << 8) + count, addr);
+       }
+       outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
+       return;
 }
 
 /* This function resets the ethercard if something screws up. */
 static void
 hp_init_card(struct device *dev)
 {
-    int irq = dev->irq;
-    NS8390_init(dev, 0);
-    outb_p(irqmap[irq&0x0f] | HP_RUN,
-          dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
-    return;
+       int irq = dev->irq;
+       NS8390_init(dev, 0);
+       outb_p(irqmap[irq&0x0f] | HP_RUN,
+                  dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
+       return;
 }
 
 \f
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c hp.c"
+ *     compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
  *  version-control: t
  *  kept-new-versions: 5
+ *  tab-width: 4
  * End:
  */
index e186c456ab098f7d8a812db1625275ed5815edbf..6e15688fb3f6b0b17053f77d213f3d52a50dc820 100644 (file)
@@ -1,126 +1,6 @@
 #ifndef _ASM_IOW_H
 #define _ASM_IOW_H
-/* I added a few.  Please add to the distributed files.        -djb. */
-/* This file is copied 1:1 from /linux/include/asm/io.h, and changed all
-   al to ax, all inb to inw and all outb to outw (to get word in/out)
-   the four inlines here should be added to the original, and
-   then this one rm'd (and the #include "iow.h" in depca.c removed)... 
-   Gruss PB 
-*/
-/*
- * Thanks to James van Artsdalen for a better timing-fix than
- * the two short jumps: using outb's to a nonexistent port seems
- * to guarantee better timings even on fast machines.
- *
- * On the other hand, I'd like to be sure of a non-existent port:
- * I feel a bit unsafe abou using 0x80.
- *
- *             Linus
- */
 
-/* This is the more general version of outw.. */
-extern inline void __outw(unsigned short value, unsigned short port)
-{
-__asm__ __volatile__ ("outw %w0,%w1"
-               : /* no outputs */
-               :"a" (value),"d" (port));
-}
-
-/* this is used for constant port numbers < 256.. */
-extern inline void __outwc(unsigned short value, unsigned short port)
-{
-__asm__ __volatile__ ("outw %w0,%1"
-               : /* no outputs */
-               :"a" (value),"i" (port));
-}
-
-/* general version of inw */
-extern inline unsigned int __inw(unsigned short port)
-{
-       unsigned int _v;
-__asm__ __volatile__ ("inw %w1,%w0"
-               :"=a" (_v):"d" (port),"0" (0));
-       return _v;
-}
-
-/* inw with constant port nr 0-255 */
-extern inline unsigned int __inwc(unsigned short port)
-{
-       unsigned int _v;
-__asm__ __volatile__ ("inw %1,%w0"
-               :"=a" (_v):"i" (port),"0" (0));
-       return _v;
-}
-
-extern inline void __outw_p(unsigned short value, unsigned short port)
-{
-__asm__ __volatile__ ("outw %w0,%w1"
-               : /* no outputs */
-               :"a" (value),"d" (port));
-       SLOW_DOWN_IO;
-}
-
-extern inline void __outwc_p(unsigned short value, unsigned short port)
-{
-__asm__ __volatile__ ("outw %w0,%1"
-               : /* no outputs */
-               :"a" (value),"i" (port));
-       SLOW_DOWN_IO;
-}
-
-extern inline unsigned int __inw_p(unsigned short port)
-{
-       unsigned int _v;
-__asm__ __volatile__ ("inw %w1,%w0"
-               :"=a" (_v):"d" (port),"0" (0));
-       SLOW_DOWN_IO;
-       return _v;
-}
-
-extern inline unsigned int __inwc_p(unsigned short port)
-{
-       unsigned int _v;
-__asm__ __volatile__ ("inw %1,%w0"
-               :"=a" (_v):"i" (port),"0" (0));
-       SLOW_DOWN_IO;
-       return _v;
-}
-
-/*
- * Note that due to the way __builtin_constant_p() works, you
- *  - can't use it inside a inlien function (it will never be true)
- *  - you don't have to worry about side effects within the __builtin..
- */
-#define outw(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
-       __outwc((val),(port)) : \
-       __outw((val),(port)))
-
-#define inw(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
-       __inwc(port) : \
-       __inw(port))
-
-#define outw_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
-       __outwc_p((val),(port)) : \
-       __outw_p((val),(port)))
-
-#define inw_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
-       __inwc_p(port) : \
-       __inw_p(port))
+/* no longer used */
 
 #endif
-
-/* The word-wide I/O operations are more general, but require a halved
-   count.  */
-#define port_read(port,buf,nr) \
-__asm__("cld;rep;insw": :"d" (port),"D" (buf),"c" (nr):"cx","di")
-#define port_write(port,buf,nr) \
-__asm__("cld;rep;outsw": :"d" (port),"S" (buf),"c" (nr):"cx","si")
-
-#define port_read_b(port,buf,nr) \
-__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di")
-#define port_write_b(port,buf,nr) \
-__asm__("cld;rep;outsb": :"d" (port),"S" (buf),"c" (nr):"cx","si")
index b80ecbd5730bff6c8bfb161472f2f12281901ccf..4e9642b79f8ff04aa072f17d60837cb6c68b856e 100644 (file)
@@ -14,7 +14,7 @@
     C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "lance.c:v0.13s 11/15/93 becker@super.org\n";
+static char *version = "lance.c:v0.14g 12/21/93 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -30,7 +30,6 @@ static char *version = "lance.c:v0.13s 11/15/93 becker@super.org\n";
 #include <asm/dma.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
@@ -145,7 +144,7 @@ tx_full and tbusy flags.
    Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
    That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */
 #ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 2
+#define LANCE_LOG_TX_BUFFERS 4
 #define LANCE_LOG_RX_BUFFERS 4
 #endif
 
@@ -224,7 +223,6 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
 {
     int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
 
-    printk("lance_init(%#x, %#x).\n", mem_start, mem_end);
     for (port = &ports[0]; *port; port++) {
        int ioaddr = *port;
 
@@ -336,7 +334,8 @@ static unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
 
            dev->irq = autoirq_report(1);
            if (dev->irq)
-               printk(", probed IRQ %d, fixed at DMA %d.\n", dev->irq, dev->dma);
+               printk(", probed IRQ %d, fixed at DMA %d.\n",
+                      dev->irq, dev->dma);
            else {
                printk(", failed to detect IRQ line.\n");
                return mem_start;
@@ -617,13 +616,6 @@ lance_interrupt(int reg_ptr)
     if (csr0 & 0x0200) {       /* Tx-done interrupt */
        int dirty_tx = lp->dirty_tx;
 
-       if (dirty_tx == lp->cur_tx - TX_RING_SIZE
-           && dev->tbusy) {
-           /* The ring is full, clear tbusy. */
-           dev->tbusy = 0;
-           mark_bh(INET_BH);
-       }
-
        while (dirty_tx < lp->cur_tx) {
            int entry = dirty_tx & TX_RING_MOD_MASK;
            int status = lp->tx_ring[entry].base;
@@ -650,7 +642,7 @@ lance_interrupt(int reg_ptr)
 
            /* We don't free the skb if it's a data-only copy in the bounce
               buffer.  The address checks here are sorted -- the first test
-              should always works.  */
+              should always work.  */
            if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE])
                || databuff < (void*)(lp->tx_bounce_buffs)) {
                struct sk_buff *skb = ((struct sk_buff *)databuff) - 1;
@@ -660,15 +652,21 @@ lance_interrupt(int reg_ptr)
            dirty_tx++;
        }
 
-       lp->dirty_tx = dirty_tx;
-
 #ifndef final_version
        if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
            printk("out-of-sync dirty pointer, %d vs. %d.\n",
                   dirty_tx, lp->cur_tx);
-           lp->dirty_tx += TX_RING_SIZE;
+           dirty_tx += TX_RING_SIZE;
        }
 #endif
+
+       if (dev->tbusy  &&  dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+           /* The ring is no longer full, clear tbusy. */
+           dev->tbusy = 0;
+           mark_bh(INET_BH);
+       }
+
+       lp->dirty_tx = dirty_tx;
     }
 
     if (csr0 & 0x8000) {
index 0542a82c80b41263328bef05e666d3f4f8db1f57..e198d55755e79e79f6f18f8d7600606863148e4f 100644 (file)
@@ -17,7 +17,7 @@
 /* Routines for the NatSemi-based designs (NE[12]000). */
 
 static char *version =
-    "ne.c:v0.99-14g 12/21/93 Donald Becker (becker@super.org)\n";
+    "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -25,9 +25,6 @@ static char *version =
 #include <linux/errno.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#ifndef port_read
-#include "iow.h"
-#endif
 
 #include "dev.h"
 #include "8390.h"
@@ -306,11 +303,11 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
     outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
     outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
     if (ei_status.word16) {
-      port_read(NE_BASE + NE_DATAPORT,buf,count>>1);
+      insw(NE_BASE + NE_DATAPORT,buf,count>>1);
       if (count & 0x01)
        buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++;
     } else {
-       port_read_b(NE_BASE + NE_DATAPORT, buf, count);
+       insb(NE_BASE + NE_DATAPORT, buf, count);
     }
 
     /* This was for the ALPHA version only, but enough people have
@@ -385,9 +382,9 @@ ne_block_output(struct device *dev, int count,
 
     outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
     if (ei_status.word16) {
-       port_write(NE_BASE + NE_DATAPORT, buf, count>>1);
+       outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
     } else {
-       port_write_b(NE_BASE + NE_DATAPORT, buf, count);
+       outsb(NE_BASE + NE_DATAPORT, buf, count);
     }
 
     /* This was for the ALPHA version only, but enough people have
index 48d64a81157ad23b1e9e17726f55ea4374adbf2a..760ca94e05eb592c72eca465b5bce4b7991c1191 100644 (file)
@@ -57,7 +57,6 @@ static char *version =
 #include <errno.h>
 
 #include "dev.h"
-#include "iow.h"
 #include "eth.h"
 #include "skbuff.h"
 #include "arp.h"
@@ -425,7 +424,7 @@ net_rx(struct device *dev)
                        memcpy((unsigned char *) (skb + 1), (void*)dev->rmem_start,
                                   pkt_len);
                        /* or */
-                       port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
+                       insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
 
 #ifdef HAVE_NETIF_RX
                        netif_rx(skb);
index 17010fb9b26f2f82e25df011e57dfa66ef1aa0a8..4939e6f0a75ff350fc2f094d72606f3ee3def983 100644 (file)
@@ -333,17 +333,6 @@ All Rights Reserved\r\n\0 \r\n \r\n", 0x1029, 102
 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
 
 
-/* These defines are copied from kernel/blk_drv/hd.c */
-
-#define insw( buf, count, port ) \
-  __asm__ volatile \
-  ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" )
-
-#define outsw( buf, count, port ) \
-  __asm__ volatile \
-  ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si")
-
-
 static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
 {
    unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
@@ -1469,9 +1458,9 @@ void aha152x_intr( int irqno )
           disp_ports();
 #endif
   
-          outsw( &current_SC->cmnd,
-                 COMMAND_SIZE(current_SC->cmnd[0])>>1,
-                 DATAPORT );
+          outsw( DATAPORT,
+                 &current_SC->cmnd,
+                 COMMAND_SIZE(current_SC->cmnd[0])>>1 );
 
 #if defined(DEBUG_CMD)
           printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
@@ -1763,7 +1752,7 @@ void aha152x_intr( int irqno )
                   {
                     CLRBITS(DMACNTRL0, _8BIT );
                     data_count >>= 1; /* Number of words */
-                    insw( current_SC->SCp.ptr, data_count, DATAPORT );
+                    insw( DATAPORT, current_SC->SCp.ptr, data_count );
 #if defined(DEBUG_DATAI)
 /* show what comes with the last transfer */
                     if(done)
@@ -1892,7 +1881,7 @@ void aha152x_intr( int irqno )
               {
                 CLRBITS(DMACNTRL0, _8BIT );
                 data_count >>= 1; /* Number of words */
-                outsw( current_SC->SCp.ptr, data_count, DATAPORT );
+                outsw( DATAPORT, current_SC->SCp.ptr, data_count );
                 current_SC->SCp.ptr           += 2 * data_count;
                 current_SC->SCp.this_residual -= 2 * data_count;
               }
index b82f031eecff0026bfa17bceb565ceb15d889c93..ac41368a764efb4e11b3556ae7a494b5c2187a08 100644 (file)
@@ -325,36 +325,6 @@ struct signature {
 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
 
 
-/* These functions are based on include/asm/io.h */
-
-inline static unsigned short inw( unsigned short port )
-{
-   unsigned short _v;
-   
-   __asm__ volatile ( "inw %1,%0"
-                     :"=a" (_v):"d" ((unsigned short) port) );
-   return _v;
-}
-
-inline static void outw( unsigned short value, unsigned short port )
-{
-   __asm__ volatile ( "outw %0,%1"
-                     : :"a" ((unsigned short) value),
-                     "d" ((unsigned short) port) );
-}
-
-
-/* These defines are copied from kernel/blk_drv/hd.c */
-
-#define insw( buf, count, port ) \
-   __asm__ volatile \
-      ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" )
-
-#define outsw( buf, count, port ) \
-    __asm__ volatile \
-       ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si")
-
-
 static void print_banner( void )
 {
    printk( "%s", fdomain_16x0_info() );
@@ -1113,7 +1083,7 @@ void fdomain_16x0_intr( int unused )
               --current_SC->SCp.this_residual;
            } else {
               data_count >>= 1;
-              outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port );
+              outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count );
               current_SC->SCp.ptr += 2 * data_count;
               current_SC->SCp.this_residual -= 2 * data_count;
            }
@@ -1146,7 +1116,7 @@ void fdomain_16x0_intr( int unused )
               --current_SC->SCp.this_residual;
            } else {
               data_count >>= 1; /* Number of words */
-              insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
+              insw( Read_FIFO_port, current_SC->SCp.ptr, data_count );
               current_SC->SCp.ptr += 2 * data_count;
               current_SC->SCp.this_residual -= 2 * data_count;
            }
index e8e25cc717155b9af584282d3825beb1e66057e7..f3f18a14e424c4ebde2604b4ebd5f240d4923907 100644 (file)
@@ -220,7 +220,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local)
   case SOUND_PCM_WRITE_CHANNELS:
     if (local)
       return dsp_set_stereo(arg-1)+1;
-    return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN (arg)-1))+1;
+    return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
     
   case SOUND_PCM_READ_CHANNELS:
     if (local)
index 97e29207ee285d666d45350ffdff0aa0ff21a62c..bc4b16c5b366b65749d73ff9352b9b5cf4359b9d 100644 (file)
@@ -25,16 +25,43 @@ void minix_put_inode(struct inode *inode)
        minix_free_inode(inode);
 }
 
+static void minix_commit_super (struct super_block * sb,
+                              struct minix_super_block * ms)
+{
+       sb->u.minix_sb.s_sbh->b_dirt = 1;
+       sb->s_dirt = 0;
+}
+
+void minix_write_super (struct super_block * sb)
+{
+       struct minix_super_block * ms;
+
+       if (!(sb->s_flags & MS_RDONLY)) {
+               ms = sb->u.minix_sb.s_ms;
+
+               if (ms->s_state & MINIX_VALID_FS)
+                       ms->s_state &= ~MINIX_VALID_FS;
+               minix_commit_super (sb, ms);
+       }
+       sb->s_dirt = 0;
+}
+
+
 void minix_put_super(struct super_block *sb)
 {
        int i;
 
        lock_super(sb);
+       if (!(sb->s_flags & MS_RDONLY)) {
+               sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
+               sb->u.minix_sb.s_sbh->b_dirt = 1;
+       }
        sb->s_dev = 0;
        for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
                brelse(sb->u.minix_sb.s_imap[i]);
        for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
                brelse(sb->u.minix_sb.s_zmap[i]);
+       brelse (sb->u.minix_sb.s_sbh);
        unlock_super(sb);
        return;
 }
@@ -45,11 +72,46 @@ static struct super_operations minix_sops = {
        minix_write_inode,
        minix_put_inode,
        minix_put_super,
-       NULL,
+       minix_write_super,
        minix_statfs,
-       NULL
+       minix_remount
 };
 
+int minix_remount (struct super_block * sb, int * flags, char * data)
+{
+       struct minix_super_block * ms;
+
+       ms = sb->u.minix_sb.s_ms;
+       if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+               return 0;
+       if (*flags & MS_RDONLY) {
+               if (ms->s_state & MINIX_VALID_FS ||
+                   !(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS))
+                       return 0;
+               /* Mounting a rw partition read-only. */
+               ms->s_state = sb->u.minix_sb.s_mount_state;
+               sb->u.minix_sb.s_sbh->b_dirt = 1;
+               sb->s_dirt = 1;
+               minix_commit_super (sb, ms);
+       }
+       else {
+               /* Mount a partition which is read-only, read-write. */
+               sb->u.minix_sb.s_mount_state = ms->s_state;
+               ms->s_state &= ~MINIX_VALID_FS;
+               sb->u.minix_sb.s_sbh->b_dirt = 1;
+               sb->s_dirt = 1;
+
+               if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS))
+                       printk ("MINIX-fs warning: remounting unchecked fs, "
+                               "running fsck is recommended.\n");
+               else if ((sb->u.minix_sb.s_mount_state & MINIX_ERROR_FS))
+                       printk ("MINIX-fs warning: remounting fs with errors, "
+                               "running fsck is recommended.\n");
+       }
+       return 0;
+}
+
+
 struct super_block *minix_read_super(struct super_block *s,void *data, 
                                     int silent)
 {
@@ -67,6 +129,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
                return NULL;
        }
        ms = (struct minix_super_block *) bh->b_data;
+       s->u.minix_sb.s_ms = ms;
+       s->u.minix_sb.s_sbh = bh;
+       s->u.minix_sb.s_mount_state = ms->s_state;
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
        s->u.minix_sb.s_ninodes = ms->s_ninodes;
@@ -77,7 +142,6 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
        s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size;
        s->u.minix_sb.s_max_size = ms->s_max_size;
        s->s_magic = ms->s_magic;
-       brelse(bh);
        if (s->s_magic == MINIX_SUPER_MAGIC) {
                s->u.minix_sb.s_dirsize = 16;
                s->u.minix_sb.s_namelen = 14;
@@ -87,9 +151,9 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
        } else {
                s->s_dev = 0;
                unlock_super(s);
+               brelse(bh);
                if (!silent)
-                       printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n",
-                                  dev);
+                       printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n", dev);
                return NULL;
        }
        for (i=0;i < MINIX_I_MAP_SLOTS;i++)
@@ -114,21 +178,34 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
                        brelse(s->u.minix_sb.s_zmap[i]);
                s->s_dev=0;
                unlock_super(s);
+               brelse(bh);
                printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
                return NULL;
        }
        set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
        set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
+       unlock_super(s);
        /* set up enough so that it can read an inode */
        s->s_dev = dev;
        s->s_op = &minix_sops;
        s->s_mounted = iget(s,MINIX_ROOT_INO);
-       unlock_super(s);
        if (!s->s_mounted) {
                s->s_dev = 0;
+               brelse(bh);
                printk("MINIX-fs: get root inode failed\n");
                return NULL;
        }
+       if (!(s->s_flags & MS_RDONLY)) {
+               ms->s_state &= ~MINIX_VALID_FS;
+               bh->b_dirt = 1;
+               s->s_dirt = 1;
+       }
+       if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS))
+               printk ("MINIX-fs: mounting unchecked file system, "
+                       "running fsck is recommended.\n");
+       else if (s->u.minix_sb.s_mount_state & MINIX_ERROR_FS)
+               printk ("MINIX-fs: mounting file system with errors, "
+                       "running fsck is recommended.\n");
        return s;
 }
 
index b51095970a8f88d8958b4fe2ac0ff89c3edfab4c..e9ad9407e39ca7f635dc7034a5680eed8b528e95 100644 (file)
@@ -52,6 +52,16 @@ __IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
 __IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; }
 
+#define __INS(s) \
+extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
+: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
+#define __OUTS(s) \
+extern inline void outs##s(unsigned short port, void * addr, unsigned long count) \
+{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
+: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
+
 __IN(b,"b","0" (0))
 __IN(w,"w","0" (0))
 __IN(l,"")
@@ -60,6 +70,14 @@ __OUT(b,"b",char)
 __OUT(w,"w",short)
 __OUT(l,,int)
 
+__INS(b)
+__INS(w)
+__INS(l)
+
+__OUTS(b)
+__OUTS(w)
+__OUTS(l)
+
 /*
  * Note that due to the way __builtin_constant_p() works, you
  *  - can't use it inside a inline function (it will never be true)
index 83e1d82976198e328a3669668edb47fdf300f4a5..cac50aa36b55759a94d174b30f6517eeb8e6fcc1 100644 (file)
@@ -49,6 +49,7 @@ extern unsigned long file_table_init(unsigned long start, unsigned long end);
 
 #define MAJOR(a) (int)((unsigned short)(a) >> 8)
 #define MINOR(a) (int)((unsigned short)(a) & 0xFF)
+#define MKDEV(a,b) ((int)((((a) & 0xff) << 8) | ((b) & 0xff)))
 
 #ifndef NULL
 #define NULL ((void *) 0)
index 45b546dac73ef448dcc2740968b094f0a4c712fc..3dedf801d7ed899ff8654cf0f81e7d4c9274e23c 100644 (file)
@@ -68,7 +68,7 @@
 /* borrowed from hd.c */
 
 #define READ_DATA(port, buf, nr) \
-__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","di")
+insb(port, buf, nr)
 
 #define SET_TIMER(func, jifs) \
        ((timer_table[MCD_TIMER].expires = jiffies + jifs), \
index ef59ad08dc283e3be12d2418dc99d01f574f4841..9ddfde70b4ccf475a25622633e5ed2f82295917b 100644 (file)
@@ -22,6 +22,8 @@
 #define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
 #define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
 #define NEW_MINIX_SUPER_MAGIC  0x2468          /* minix V2 - not implemented */
+#define MINIX_VALID_FS         0x0001          /* Clean fs. */
+#define MINIX_ERROR_FS         0x0002          /* fs has errors. */
 
 #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
 
@@ -65,6 +67,7 @@ struct minix_super_block {
        unsigned short s_log_zone_size;
        unsigned long s_max_size;
        unsigned short s_magic;
+       unsigned short s_state;
 };
 
 struct minix_dir_entry {
@@ -100,6 +103,8 @@ extern struct buffer_head * minix_bread(struct inode *, int, int);
 extern void minix_truncate(struct inode *);
 extern void minix_put_super(struct super_block *);
 extern struct super_block *minix_read_super(struct super_block *,void *,int);
+extern void minix_write_super(struct super_block *);
+extern int minix_remount (struct super_block * sb, int * flags, char * data);
 extern void minix_read_inode(struct inode *);
 extern void minix_write_inode(struct inode *);
 extern void minix_put_inode(struct inode *);
index c6f06254f6250574bdbb91190c66f005bebd9fdd..a483479807846409c792e8bd53b4adb924351b65 100644 (file)
@@ -16,6 +16,9 @@ struct minix_sb_info {
                        struct buffer_head * s_zmap[8];
                        unsigned long s_dirsize;
                        unsigned long s_namelen;
+                       struct buffer_head * s_sbh;
+                       struct minix_super_block * s_ms;
+                       unsigned short s_mount_state;
 };
 
 #endif
index 0ec321737a57e24009828cf38767d060418d2f2a..41e774296ad57ed8e74d0b18541a4f59df0dc7c3 100644 (file)
@@ -429,7 +429,7 @@ fake_volatile:
                current->p_cptr = p->p_osptr;
                p->p_ysptr = NULL;
                p->flags &= ~(PF_PTRACED|PF_TRACESYS);
-               if (task[1])
+               if (task[1] && task[1] != current)
                        p->p_pptr = task[1];
                else
                        p->p_pptr = task[0];
index 4a98ab17e7327e330b1809c8e63c5eb0389e0dc3..d46f0910e9054768492dcec1400509240dbffb28 100644 (file)
@@ -10,7 +10,7 @@
 #
 #
 
-trap "rm -f ksyms.tmp ksyms.lst" 1 2 
+trap "rm -f ksyms.tmp ksyms.lst" 1 2 
 
 sed -e '/^#/d' -e '/^[  ]*$/d' ksyms.lst | sort > ksyms.tmp
 
@@ -27,7 +27,7 @@ awk 'BEGIN {stringloc = 0}
 echo '
 strings:'
 awk '{print "  .ascii \"" $1 "\\0\""}' ksyms.tmp
-
+rm -f ksyms.tmp
 
 
 #
index 17eca1b9c0b796bcfab23dfa936f08589677faa1..17703c78aac10630a9edf9e1938ca2c745a228b8 100644 (file)
@@ -748,8 +748,10 @@ static void show_task(int nr,struct task_struct * p)
                printk(stat_nam[p->state]);
        else
                printk(" ");
-       /* this prints bogus values for the current process */
-       printk(" %08lX ", ((unsigned long *)p->tss.esp)[2]);
+       if (p == current)
+               printk(" current  ");
+       else
+               printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]);
        printk("%5lu %5d %6d ",
                p->tss.esp - p->kernel_stack_page, p->pid, p->p_pptr->pid);
        if (p->p_cptr)
index 03ddea5d10e0e3c66c64acea0b541d27d1692dfb..776dff0f57bf0c10d3c7b784de3b171e8aae9ea9 100644 (file)
 #include <asm/segment.h>
 #include <asm/io.h>
 
+static inline void console_verbose(void)
+{
+       extern int console_loglevel;
+       console_loglevel = 15;
+}
+
 #define DO_ERROR(trapnr, signr, str, name, tsk) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
@@ -78,6 +84,7 @@ asmlinkage void alignment_check(void);
        if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
                return;
 
+       console_verbose();
        printk("%s: %04lx\n", str, err & 0xffff);
        printk("EIP:    %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
        printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
index abd1cb5780c6e455b126cf69f1dc7c4d42aa4df7..31049b9fbaa485eacad43e24c23a497742880a68 100644 (file)
@@ -357,7 +357,6 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
         unsigned long saddr, int redo, struct inet_protocol *protocol)
 {
   struct icmphdr *icmph;
-  unsigned char *buff;
 
   /* Drop broadcast packets. */
   if (chk_addr(daddr) == IS_BROADCAST) {
@@ -368,8 +367,10 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
        return(0);
   }
 
-  buff = skb1->h.raw;
-  icmph = (struct icmphdr *) buff;
+  /* Skip IP-Header */
+  len -= skb1->h.iph->ihl << 2;
+  skb1->h.raw += skb1->h.iph->ihl << 2;
+  icmph = (struct icmphdr *) skb1->h.raw;
 
   /* Validate the packet first */
   if (ip_compute_csum((unsigned char *) icmph, len)) {
index 3a1b1fc1da1af6a261fb7e63c58c9f787a780c94..5f76d9158a243c0137f859fed658125dac10009c 100644 (file)
@@ -428,21 +428,22 @@ ip_fast_csum(unsigned char * buff, int wlen)
 {
     unsigned long sum = 0;
 
-    if (wlen)
+    if (wlen) {
+       unsigned long bogus;
         __asm__("clc\n"
                "1:\t"
                "lodsl\n\t"
-               "adcl %%eax, %0\n\t"
+               "adcl %3, %0\n\t"
                "decl %2\n\t"
                "jne 1b\n\t"
                "adcl $0, %0\n\t"
-               "movl %0, %%eax\n\t"
-               "shrl $16, %%eax\n\t"
-               "addw %%ax, %w0\n\t"
+               "movl %0, %3\n\t"
+               "shrl $16, %3\n\t"
+               "addw %w3, %w0\n\t"
                "adcw $0, %w0"
-           : "=r" (sum), "=S" (buff), "=r" (wlen)
-           : "0"  (sum),  "1" (buff),  "2" (wlen)
-           : "ax" );
+           : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
+           : "0"  (sum),  "1" (buff),  "2" (wlen));
+    }
     return (~sum) & 0xffff;
 }
 
@@ -1266,7 +1267,6 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
   }
   
   /* Point into the IP datagram, just past the header. */
-  skb->h.raw += iph->ihl*4;
   hash = iph->protocol & (MAX_INET_PROTOS -1);
   for (ipprot = (struct inet_protocol *)inet_protos[hash];
        ipprot != NULL;
@@ -1305,7 +1305,7 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        * check the protocol handler's return values here...
        */
        ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
-                       (ntohs(iph->tot_len) - (iph->ihl * 4)),
+                       ntohs(iph->tot_len),
                        iph->saddr, 0, ipprot);
 
   }
index c914c7c19c750a39420a4c4b62e8f3c13acd25a6..09ab0974b05ee5ff602bdd0abeeb776cbac11010 100644 (file)
@@ -44,7 +44,7 @@
 
 
 static struct rtable *rt_base = NULL;
-
+static struct rtable *rt_loopback = NULL;
 
 /* Dump the contents of a routing table entry. */
 static void
@@ -80,6 +80,8 @@ static void rt_del(unsigned long dst)
                        continue;
                }
                *rp = r->rt_next;
+               if (rt_loopback == r)
+                       rt_loopback = NULL;
                kfree_s(r, sizeof(struct rtable));
        } 
        restore_flags(flags);
@@ -105,6 +107,8 @@ void rt_flush(struct device *dev)
                        continue;
                }
                *rp = r->rt_next;
+               if (rt_loopback == r)
+                       rt_loopback = NULL;
                kfree_s(r, sizeof(struct rtable));
        } 
        restore_flags(flags);
@@ -216,6 +220,8 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
                        continue;
                }
                *rp = r->rt_next;
+               if (rt_loopback == r)
+                       rt_loopback = NULL;
                kfree_s(r, sizeof(struct rtable));
        }
        /* add the new route */
@@ -227,6 +233,8 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
        }
        rt->rt_next = r;
        *rp = rt;
+       if (rt->rt_dev->flags & IFF_LOOPBACK)
+               rt_loopback = rt;
        restore_flags(cpuflags);
        return;
 }
@@ -306,41 +314,28 @@ rt_get_info(char *buffer)
   return(pos - buffer);
 }
 
-
 /*
- * rewrote this too.. Maybe somebody can understand it now. Linus
+ * This is hackish, but results in better code. Use "-S" to see why.
  */
+#define early_out ({ goto no_route; 1; })
+
 struct rtable * rt_route(unsigned long daddr, struct options *opt)
 {
        struct rtable *rt;
-       int type;
 
-  /*
-   * This is a hack, I think. -FvK
-   */
-       if ((type=chk_addr(daddr)) == IS_MYADDR) daddr = my_addr();
-
-  /*
-   * Loop over the IP routing table to find a route suitable
-   * for this packet.  Note that we really should have a look
-   * at the IP options to see if we have been given a hint as
-   * to what kind of path we should use... -FvK
-   */
-  /*
-   * This depends on 'rt_mask' and the ordering set up in 'rt_add()' - Linus
-   */
-       for (rt = rt_base; rt != NULL; rt = rt->rt_next) {
-               if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) {
-                       rt->rt_use++;
-                       return rt;
-               }
+       for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) {
+               if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
+                       break;
                /* broadcast addresses can be special cases.. */
                if ((rt->rt_dev->flags & IFF_BROADCAST) &&
-                    rt->rt_dev->pa_brdaddr == daddr) {
-                       rt->rt_use++;
-                       return(rt);
-               }
+                    rt->rt_dev->pa_brdaddr == daddr)
+                       break;
        }
+       if (daddr == rt->rt_dev->pa_addr)
+               rt = rt_loopback;
+       rt->rt_use++;
+       return rt;
+no_route:
        return NULL;
 }
 
index 83dfb4171ddc68d5e31ad29ee9f5752c14de4750..c3be0bcdcab2a453746d99fea568ef2e39855811 100644 (file)
@@ -2934,6 +2934,9 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n"));
        return(0);
   }
+  /* Skip IP-Header */
+  len -= skb->h.iph->ihl << 2;
+  skb->h.raw += skb->h.iph->ihl << 2;
   th = skb->h.th;
 
   /* Find the socket. */
index 78066c3f629686d75fd2b5db8194477aa79f58ea..74e0a2e3fde527a4a7c7afed88d55a37ec501b4a 100644 (file)
@@ -550,6 +550,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
   struct sock *sk;
   struct udphdr *uh;
 
+  /* Skip IP-Header */
+  len -= skb->h.iph->ihl << 2;
+  skb->h.raw += skb->h.iph->ihl << 2;
   uh = (struct udphdr *) skb->h.uh;
   sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
   if (sk == NULL) 
index 6885fe7c232bfdfe546805f2cab19821767f9632..e679128cb3c986ad74713aed1f9fdb8647e92b5e 100644 (file)
@@ -231,6 +231,7 @@ static void
 sock_release(struct socket *sock)
 {
   int oldstate;
+  struct inode *inode;
   struct socket *peersock, *nextsock;
 
   DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n",
@@ -251,11 +252,12 @@ sock_release(struct socket *sock)
   peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;
   if (sock->ops) sock->ops->release(sock, peersock);
   if (peersock) sock_release_peer(peersock);
+  inode = SOCK_INODE(sock);
   sock->state = SS_FREE;               /* this really releases us */
   wake_up(&socket_wait_free);
 
   /* We need to do this. If sock alloc was called we already have an inode. */
-  iput(SOCK_INODE(sock));
+  iput(inode);
 }
 
 
index 68bd1069d69012e7aeeed22c75599a2129d39c92..8a80ad55b0bacf5eb341f59b239c07514b6e0b11 100644 (file)
@@ -16,7 +16,6 @@
  *             Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
  *
  * Fixes:
- *             Andriews Brouwer        :       Comment errors
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License