aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-02-22 15:42:37 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:34 -0400
commiteaee9b0646fdb4acad111941255378b0e882ffa2 (patch)
treecc4fab413df296412ade8f5fc041ad7b9435382a
parentece0168d6056dde89594a5de89133ef9b2b7097c (diff)
downloadarchive-eaee9b0646fdb4acad111941255378b0e882ffa2.tar.gz
ALPHA-pl15h
-rw-r--r--Makefile4
-rw-r--r--config.in2
-rw-r--r--drivers/char/console.c16
-rw-r--r--drivers/net/8390.c10
-rw-r--r--drivers/net/CONFIG4
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/depca.c1364
-rw-r--r--drivers/net/depca.h128
-rw-r--r--fs/ext2/balloc.c19
-rw-r--r--fs/ext2/truncate.c13
-rw-r--r--include/linux/sched.h2
-rw-r--r--kernel/itimer.c9
-rw-r--r--kernel/sched.c4
-rw-r--r--net/inet/dev.c1
-rw-r--r--net/inet/tcp.c262
15 files changed, 1651 insertions, 189 deletions
diff --git a/Makefile b/Makefile
index 9d113f5..8b40870 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 15
-ALPHA = g
+ALPHA = h
all: Version zImage
@@ -188,7 +188,9 @@ zdisk: zImage
zlilo: $(CONFIGURE) zImage
if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi
+ if [ -f /zSystem.map ]; then mv /zSystem.map /zSystem.old; fi
cat zImage > /vmlinuz
+ cp zSystem.map /
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
diff --git a/config.in b/config.in
index 61146ca..a844923 100644
--- a/config.in
+++ b/config.in
@@ -76,7 +76,7 @@ bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
bool 'AT1700 support' CONFIG_AT1700 n
#bool 'Zenith Z-Note support' CONFIG_ZNET n
#bool 'EtherExpress support' CONFIG_EEXPRESS n
-#bool 'DEPCA support' CONFIG_DEPCA n
+bool 'DEPCA support' CONFIG_DEPCA n
#bool 'NI52** support' CONFIG_NI52 n
#bool 'NI65** support' CONFIG_NI65 n
#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
diff --git a/drivers/char/console.c b/drivers/char/console.c
index cfd1e0c..4b43d69 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -382,12 +382,18 @@ static void set_origin(int currcons)
__set_origin(__real_origin);
}
-static inline void hide_cursor(int currcons)
+/*
+ * Put the cursor just beyond the end of the display adaptor memory.
+ */
+static inline void hide_cursor(void)
{
+ /* This is inefficient, we could just put the cursor at 0xffff,
+ but perhaps the delays due to the inefficiency are useful for
+ some hardware... */
outb_p(14, video_port_reg);
- outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
+ outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
outb_p(15, video_port_reg);
- outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
+ outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
}
static inline void set_cursor(int currcons)
@@ -405,7 +411,7 @@ static inline void set_cursor(int currcons)
outb_p(15, video_port_reg);
outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
} else
- hide_cursor(currcons);
+ hide_cursor();
restore_flags(flags);
}
@@ -1546,7 +1552,7 @@ void blank_screen(void)
return;
timer_table[BLANK_TIMER].fn = unblank_screen;
get_scrmem(fg_console);
- hide_cursor(fg_console);
+ hide_cursor();
console_blanked = 1;
memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
}
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 024568e..e2125af 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -122,12 +122,6 @@ int ei_open(struct device *dev)
irq2dev_map[dev->irq] = dev;
NS8390_init(dev, 1);
- ei_local->tx1 = ei_local->tx2 = 0;
- /* The old local flags... */
- ei_local->txing = 0;
- /* ... are now global. */
- dev->tbusy = 0;
- dev->interrupt = 0;
dev->start = 1;
ei_local->irqlock = 0;
return 0;
@@ -684,6 +678,10 @@ void NS8390_init(struct device *dev, int startp)
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
sti();
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_local->txing = 0;
if (startp) {
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
diff --git a/drivers/net/CONFIG b/drivers/net/CONFIG
index cb9bbed..2231fa7 100644
--- a/drivers/net/CONFIG
+++ b/drivers/net/CONFIG
@@ -30,6 +30,9 @@
# D_LINK_IO The D-Link I/O address (0x378 == typical)
# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == typical)
# D_LINK_DEBUG Enable or disable D-Link debugging
+# DEPCA The DIGITAL series of AT Ethernet Cards (DE100, DE200)
+# DEPCA_IRQ Set the desired IRQ (=0, for autoprobe)
+# DEPCA_DEBUG Set the desired debug level
#
# The following options exist, but cannot be set in this file.
@@ -50,6 +53,7 @@ EL2_OPTS = #-DEL2_AUI
NE_OPTS =
HP_OPTS =
PLIP_OPTS =
+DEPCA_OPTS = -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1
# The following are the only parameters that must be set in this file.
DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 51c1c8d..de6fc06 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -105,6 +105,8 @@ NETDRV_OBJS := $(NETDRV_OBJS) net.a(znet.o)
endif
ifdef CONFIG_DEPCA
NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o)
+depca.o: depca.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
endif
ifdef CONFIG_ATP
NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o)
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
new file mode 100644
index 0000000..50efe69
--- /dev/null
+++ b/drivers/net/depca.c
@@ -0,0 +1,1364 @@
+/* depca.c: A DIGITAL DEPCA ethernet driver for linux.
+
+ Written 1994 by David C. Davies.
+
+ Copyright 1994 David C. Davies and 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 driver is written for the Digital Equipment Corporation series
+ of DEPCA ethernet cards:
+
+ DE100 DEPCA
+ DE200 DEPCA Turbo
+ DE202 DEPCA Turbo (TP BNC)
+ DE210 DEPCA
+
+ The driver has been tested on DE100 and DE20x cards in a relatively busy
+ network.
+
+ The author may be reached as davies@wanton.enet.dec.com or
+ Digital Equipment Corporation, 146 Main Street, Maynard MA 01754.
+
+ =========================================================================
+ The driver was based on the 'lance.c' driver from Donald Becker which is
+ included with the standard driver distribution for linux. Modifications
+ were made to most routines and the hardware recognition routines were
+ written from scratch. Primary references used were:
+
+ 1) Lance.c code in /linux/drivers/net/
+ 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
+ AMD, 1992 [(800) 222-9323].
+ 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
+ AMD, Pub. #17881, May 1993.
+ 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
+ AMD, Pub. #16907, May 1992
+ 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
+ Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
+ 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
+ Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
+ 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
+ Digital Equipment Corporation, 1989
+ 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
+ Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
+
+ Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
+ The hash filter code was derived from Reference 3 and has been tested
+ only to the extent that the Table A-1, page A-7, was confirmed to fill
+ the filter bit positions correctly. Hash filtering is not yet
+ implemented in the current driver set.
+
+ The DE200 series boards have on-board 64kB RAM for use as a shared
+ memory network buffer. Only the DE100 cards make use of a 2kB buffer
+ mode which has not been implemented in this driver (only the 32kB and
+ 64kB modes are supported).
+
+ At the most only 2 DEPCA cards can be supported because there is only
+ provision for two I/O base addresses on the cards (0x300 and 0x200). The
+ base address is 'autoprobed' by looking for the self test PROM and
+ detecting the card name. The shared memory base address is decoded by
+ 'autoprobing' the Ethernet PROM address information. The second DEPCA is
+ detected and information placed in the base_addr variable of the next
+ device structure (which is created if necessary), thus enabling
+ ethif_probe initialization for the device.
+
+ ************************************************************************
+
+ NOTE: If you are using two DEPCAs, it is important that you assign the
+ base memory addresses correctly. The driver autoprobes I/O 0x300 then
+ 0x200. The base memory address for the first device must be less than
+ that of the second so that the auto probe will correctly assign the I/O
+ and memory addresses on the same card. I can't think of a way to do
+ this unambiguously at the moment, since there is nothing on the cards to
+ tie I/O and memory information together.
+
+ I am unable to test 2 DEPCAs together for now, so this code is
+ unchecked. All reports, good or bad, are welcome.
+
+ ************************************************************************
+
+ The board IRQ setting must be at an unused IRQ which is auto-probed
+ using Donald Becker's autoprobe routines. DE100 board IRQs are
+ {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is
+ really IRQ9 in machines with 16 IRQ lines.
+
+ No 16MB memory limitation should exist with this driver as DMA is not
+ used and the common memory area is in low memory on the network card (my
+ current system has 20MB and I've not had problems yet).
+
+ The DE203, DE204 and DE205 cards may also work with this driver (I
+ haven't tested them so I don't know). If you have one of these cards,
+ place the name in the DEPCA_SIGNATURE string around line 160, recompile
+ the kernel and reboot. Check if the card is recognised and works - mail
+ me if so, so that I can add it into the list of supported cards!
+
+ TO DO:
+ ------
+
+ 1. Implement the 2k buffer mode - does anyone need it??
+
+ Revision History
+ ----------------
+
+ Version Date Description
+
+ 0.1 25-jan-94 Initial writing
+ 0.2 27-jan-94 Added LANCE TX buffer chaining
+ 0.3 1-feb-94 Added multiple DEPCA support
+ 0.31 4-feb-94 Added DE202 recognition
+ 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support.
+
+ =========================================================================
+*/
+
+static char *version = "depca.c:v0.32 2/19/94 davies@wanton.enet.dec.com\n";
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+#include "depca.h"
+
+extern int vsprintf(char *buf, const char *fmt, ...);
+
+#ifdef DEPCA_DEBUG
+int depca_debug = DEPCA_DEBUG;
+#else
+int depca_debug = 1;
+#endif
+
+#ifndef DEPCA_IRQ
+/*#define DEPCA_IRQ {5,9,10,11,15,0}*/
+#define DEPCA_IRQ 5
+#endif
+
+#ifndef PROBE_LENGTH
+#define PROBE_LENGTH 32
+#endif
+
+#ifndef PROBE_SEQUENCE
+#define PROBE_SEQUENCE "FF0055AAFF0055AA"
+#endif
+
+#ifndef DEPCA_SIGNATURE
+#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE202","DE210",""}
+#define DEPCA_NAME_LENGTH 8
+#endif
+
+#ifndef DEPCA_RAM_BASE_ADDRESSES
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#endif
+static short mem_chkd = 0; /* holds which base addrs have been */
+ /* checked, for multi-DEPCA case */
+
+#ifndef DEPCA_IO_PORTS
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#endif
+
+#ifndef DEPCA_TOTAL_SIZE
+#define DEPCA_TOTAL_SIZE 0x10
+#endif
+
+#ifndef MAX_NUM_DEPCAS
+#define MAX_NUM_DEPCAS 2
+#endif
+
+/*
+** Set the number of Tx and Rx buffers.
+*/
+#ifndef DEPCA_BUFFER_LOG_SZ
+#define RING_SIZE 16 /* 16 buffers */
+#else
+#define RING_SIZE (1 << (DEPCA_BUFFERS_LOG_SZ))
+#endif /* DEPCA_BUFFER_LOG_SZ */
+
+#define PKT_BUF_SZ 1544 /* Buffer size for each Tx/Rx buffer */
+#define PKT_SZ 1514 /* Maximum ethernet packet length */
+#define DAT_SZ 1500 /* Maximum ethernet data length */
+#define PKT_HDR_LEN 14 /* Addresses and data length info */
+
+#ifdef HAVE_MULTICAST
+#ifndef CRC_POLYNOMIAL
+#define CRC_POLYNOMIAL 0x04c11db7 /* Ethernet CRC polynomial */
+#endif /* CRC_POLYNOMIAL */
+#endif /* HAVE_MULTICAST */
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif /* HAVE_ALLOC_SKB */
+
+/*
+** The DEPCA Rx and Tx ring descriptors.
+*/
+struct depca_rx_head {
+ long base;
+ short buf_length; /* This length is negative 2's complement! */
+ short msg_length; /* This length is "normal". */
+};
+
+struct depca_tx_head {
+ long base;
+ short length; /* This length is negative 2's complement! */
+ short misc; /* Errors and TDR info */
+};
+
+struct depca_ring_info {
+};
+
+/*
+** The Lance initialization block, described in databook, in common memory.
+*/
+struct depca_init {
+ unsigned short mode; /* Mode register */
+ unsigned char phys_addr[ETH_ALEN]; /* Physical ethernet address */
+ unsigned short filter[4]; /* Multicast filter. */
+ unsigned long rx_ring; /* Rx ring base pointer & ring length */
+ unsigned long tx_ring; /* Tx ring base pointer & ring length */
+};
+
+struct depca_private {
+ char devname[8]; /* Not used */
+ struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
+ struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
+ struct depca_init init_block;/* Initialization block */
+ long dma_buffs; /* Start address of Rx and Tx buffers. */
+ int cur_rx, cur_tx; /* The next free ring entry */
+ int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ int dma;
+ struct enet_statistics stats;
+ char old_depca;
+ short ringSize; /* ring size based on available memory */
+ short rmask; /* modulus mask based on ring size */
+ long rlen; /* log2(ringSize) for the descriptors */
+};
+
+/*
+** Public Functions
+*/
+static int depca_open(struct device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void depca_interrupt(int reg_ptr);
+static int depca_close(struct device *dev);
+static struct enet_statistics *depca_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+/*
+** Private functions
+*/
+static int depca_probe1(struct device *dev, short ioaddr);
+static void depca_init_ring(struct device *dev);
+static int depca_rx(struct device *dev);
+static int depca_tx(struct device *dev);
+
+static void LoadCSRs(struct device *dev);
+static int InitRestartDepca(struct device *dev);
+static char *DepcaSignature(unsigned long mem_addr);
+static int DevicePresent(short ioaddr);
+#ifdef HAVE_MULTICAST
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
+#endif
+
+static int num_depcas = 0, num_eth = 0;;
+
+/*
+** Miscellaneous defines...
+*/
+#define STOP_DEPCA \
+ outw(CSR0, DEPCA_ADDR);\
+ outw(STOP, DEPCA_DATA)
+
+
+
+int depca_probe(struct device *dev)
+{
+ int *port, ports[] = DEPCA_IO_PORTS;
+ int base_addr = dev->base_addr;
+ int status;
+ struct device *eth0 = (struct device *) NULL;
+
+ if (base_addr > 0x1ff) { /* Check a single specified location. */
+ status = depca_probe1(dev, base_addr);
+ } else if (base_addr > 0) { /* Don't probe at all. */
+ status = -ENXIO;
+ } else { /* First probe for the DEPCA test */
+ /* pattern in ROM */
+
+ for (status = -ENODEV, port = &ports[0];
+ *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
+ int ioaddr = *port;
+
+#ifdef HAVE_PORTRESERVE
+ if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
+ continue;
+#endif
+ if (DevicePresent(DEPCA_PROM) == 0) {
+ if (num_depcas > 0) { /* only gets here in autoprobe */
+
+ /*
+ ** Check the device structures for an end of list or unused device
+ */
+ while (dev->next != (struct device *)NULL) {
+ if (dev->next->base_addr == 0xffe0) break;
+ dev = dev->next; /* walk through eth device list */
+ num_eth++; /* increment eth device number */
+ }
+
+ /*
+ ** If no more device structures, malloc one up. If memory could
+ ** not be allocated, print an error message.
+ **
+ */
+ if (dev->next == (struct device *)NULL) {
+ dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+ GFP_KERNEL);
+ } else {
+ printk("eth%d: Device not initialised, insufficient memory\n",
+ num_eth);
+ }
+
+ /*
+ ** If the memory was allocated, point to the new memory area
+ ** and initialize it (name, I/O address, next device (NULL) and
+ ** initialisation probe routine).
+ */
+ if ((dev->next != (struct device *)NULL) &&
+ (num_eth > 0) && (num_eth < 9999)) {
+ dev = dev->next; /* point to the new device */
+ dev->name = (char *)(dev + sizeof(struct device));
+ vsprintf(dev->name,"eth%d", num_eth); /* New device name */
+ dev->base_addr = ioaddr; /* assign the io address */
+ dev->next = (struct device *)NULL; /* mark the end of list */
+ dev->init = &depca_probe;/* initialisation routine */
+ }
+ } else {
+ eth0 = dev; /* remember the first device */
+ status = depca_probe1(dev, ioaddr);
+ }
+ num_depcas++;
+ num_eth++;
+ }
+ }
+ if (eth0) dev = eth0; /* restore the first device */
+ }
+
+ if (status) dev->base_addr = base_addr;
+
+ return status; /* ENODEV would be more accurate. */
+}
+
+static int
+depca_probe1(struct device *dev, short ioaddr)
+{
+ struct depca_private *lp;
+ int i,j, status=0;
+ unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+ char *name=(char *)NULL;
+ int nicsr, offset;
+
+
+ /*
+ ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot
+ */
+ STOP_DEPCA;
+
+ nicsr = inw(DEPCA_NICSR);
+ nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+ outw(nicsr, DEPCA_NICSR);
+
+ if (inw(DEPCA_DATA) == STOP) {
+
+ /* Now find out what kind of DEPCA we have. The DE100 uses a different
+ ** addressing scheme for some registers compared to the DE2xx series.
+ ** Note that a base address location is marked as checked if no DEPCA is
+ ** there or one is found (when the search is immediately terminated). This
+ ** shortens the search time a little for multiple DEPCAs.
+ */
+
+ for (j = 0, i = 0; mem_base[i] && (j == 0);) {
+ if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
+ name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
+ mem_chkd |= (0x01 << i); /* mark location checked */
+ if (*name != (char)NULL) { /* one found? */
+ j = 1; /* set exit flag */
+ } else {
+ i++; /* increment search index */
+ }
+ }
+ }
+
+ if (*name != (char)NULL) { /* found a DEPCA device */
+ mem_start = mem_base[i];
+ dev->base_addr = ioaddr;
+
+ printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name);
+
+ /* There is a 32 byte station address PROM at DEPCA_PROM address.
+ The first six bytes are the station address. They can be read
+ directly since the signature search set up the ROM address
+ counter correctly just before this function.
+
+ For the DE100 we have to be careful about which port is used to
+ read the ROM info.
+ */
+
+ if (strstr(name,"DE100")!=(char *)NULL) {
+ j = 1;
+ } else {
+ j = 0;
+ }
+
+ printk("ethernet address ");
+ for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
+ printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+ }
+ printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+
+ for (;i<32;i++) { /* leave ROM counter in known state */
+ j=inb(DEPCA_PROM);
+ }
+
+#ifdef HAVE_PORTRESERVE
+ snarf_region(ioaddr, DEPCA_TOTAL_SIZE);
+#endif
+
+ /*
+ ** Determine the base address for the DEPCA RAM from the NI-CSR
+ ** and make up a DEPCA-specific-data structure.
+ */
+
+ if (nicsr & BUF) {
+ offset = 0x8000; /* 32kbyte RAM */
+ nicsr &= ~BS; /* DEPCA RAM in top 32k */
+ printk(",\n with 32kB RAM");
+ } else {
+ offset = 0x0000; /* 64kbyte RAM */
+ printk(",\n with 64kB RAM");
+ }
+
+ mem_start += offset;
+ printk(" starting at 0x%.5lx", mem_start);
+
+ /*
+ ** Enable the shadow RAM.
+ */
+ nicsr |= SHE;
+ outw(nicsr, DEPCA_NICSR);
+
+ /*
+ ** Calculate the ring size based on the available RAM
+ ** found above. Allocate an equal number of buffers, each
+ ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx. Make sure
+ ** that this ring size is <= RING_SIZE. The ring size must be
+ ** a power of 2.
+ */
+
+ j = ((0x10000 - offset) / PKT_BUF_SZ) >> 1;
+ for (i=0;j>1;i++) {
+ j >>= 1;
+ }
+
+ /* Hold the ring size information here before the depca
+ ** private structure is allocated. Need this for the memory
+ ** space calculations.
+ */
+ j = 1 << i;
+
+ /*
+ ** Set up memory information in the device structure.
+ ** Align the descriptor rings on an 8 byte (quadword) boundary.
+ **
+ ** depca_private area
+ ** rx ring descriptors
+ ** tx ring descriptors
+ ** rx buffers
+ ** tx buffers
+ **
+ */
+
+ /* private area & initialise */
+ dev->priv = (void *)((mem_start + 0x07) & ~0x07);
+ lp = (struct depca_private *)dev->priv;
+ memset(dev->priv, 0, sizeof(struct depca_private));
+
+ /* Tx & Rx descriptors (aligned to a quadword boundary) */
+ mem_start = ((((unsigned long)dev->priv +
+ sizeof(struct depca_private)) +
+ (unsigned long)0x07) & (unsigned long)~0x07);
+ lp->rx_ring = (struct depca_rx_head *)mem_start;
+
+ mem_start += (sizeof(struct depca_rx_head) * j);
+ lp->tx_ring = (struct depca_tx_head *)mem_start;
+
+ mem_start += (sizeof(struct depca_tx_head) * j);
+ lp->dma_buffs = mem_start & 0x00ffffff;
+
+ mem_start += (PKT_BUF_SZ * j);
+ /* (mem_start now points to the start of the Tx buffers) */
+
+ /* Initialise the data structures */
+ memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
+ memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
+
+ /* This should never happen. */
+ if ((int)(lp->rx_ring) & 0x07) {
+ printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
+ return -ENXIO;
+ }
+
+ /*
+ ** Finish initialising the ring information.
+ */
+ lp->ringSize = j;
+ if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
+ lp->rmask = lp->ringSize - 1;
+
+ /*
+ ** calculate the real RLEN size for the descriptors. It is
+ ** log2(ringSize).
+ */
+ for (i=0, j = lp->ringSize; j>1; i++) {
+ j >>= 1;
+ }
+ lp->rlen = (unsigned long)(i << 29);
+
+ /*
+ ** load the initialisation block
+ */
+ depca_init_ring(dev);
+
+ /*
+ ** Initialise the control and status registers
+ */
+ LoadCSRs(dev);
+
+ /*
+ ** Enable DEPCA board interrupts for autoprobing
+ */
+ nicsr = ((nicsr & ~IM)|IEN);
+ outw(nicsr, DEPCA_NICSR);
+
+ /* The DMA channel may be passed in on this parameter. */
+ dev->dma = 0;
+
+ /* To auto-IRQ we enable the initialization-done and DMA err,
+ interrupts. For now we will always get a DMA error. */
+ if (dev->irq < 2) {
+ autoirq_setup(0);
+
+ /* Trigger an initialization just for the interrupt. */
+ outw(INEA | INIT, DEPCA_DATA);
+
+ dev->irq = autoirq_report(1);
+ if (dev->irq) {
+ printk(" and probed IRQ%d.\n", dev->irq);
+ } else {
+ printk(". Failed to detect IRQ line.\n");
+ status = -EAGAIN;
+ }
+ } else {
+ printk(". Assigned IRQ%d.\n", dev->irq);
+ }
+ } else {
+ status = -ENXIO;
+ }
+ if (!status) {
+ if (depca_debug > 0) {
+ printk(version);
+ }
+
+ /* The DEPCA-specific entries in the device structure. */
+ dev->open = &depca_open;
+ dev->hard_start_xmit = &depca_start_xmit;
+ dev->stop = &depca_close;
+ dev->get_stats = &depca_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+
+ dev->mem_start = 0;
+
+ /* Fill in the generic field of the device structure. */
+ 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 < dev->addr_len; 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);
+ }
+ } else {
+ status = -ENXIO;
+ }
+
+ return status;
+}
+
+
+static int
+depca_open(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i,nicsr,ioaddr = dev->base_addr;
+
+ if (request_irq(dev->irq, &depca_interrupt)) {
+ printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
+ return -EAGAIN;
+ }
+
+ irq2dev_map[dev->irq] = dev;
+
+ /*
+ ** Stop the DEPCA & get the board status information.
+ */
+ STOP_DEPCA;
+ nicsr = inw(DEPCA_NICSR);
+
+ /*
+ ** Re-initialize the DEPCA...
+ */
+ depca_init_ring(dev); /* initialize the descriptor rings */
+ LoadCSRs(dev);
+
+ if (depca_debug > 1){
+ printk("%s: depca open with irq %d\n",dev->name,dev->irq);
+ printk("Descriptor head addresses:\n");
+ printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+ printk("Descriptor addresses:\n");
+ for (i=0;i<lp->ringSize;i++){
+ printk("\t0x%8.8lx 0x%8.8lx\n",(long)&lp->rx_ring[i].base,
+ (long)&lp->tx_ring[i].base);
+ }
+ printk("Buffer addresses:\n");
+ for (i=0;i<lp->ringSize;i++){
+ printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring[i].base,
+ (long)lp->tx_ring[i].base);
+ }
+ printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
+ printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+ printk("\tphysical address: ");
+ for (i=0;i<6;i++){
+ printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+ }
+ printk("\n\tlogical address filter: 0x");
+ for (i=0;i<4;i++){
+ printk("%2.2x",(short)lp->init_block.filter[i]);
+ }
+ printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
+ printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
+ printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
+ printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n",
+ (short)lp->ringSize,
+ (char)lp->rmask,
+ (long)lp->rlen);
+ outw(CSR2,DEPCA_ADDR);
+ printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
+ outw(CSR1,DEPCA_ADDR);
+ printk("%4.4x\n",inw(DEPCA_DATA));
+ outw(CSR3,DEPCA_ADDR);
+ printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
+ }
+
+ /*
+ ** Enable DEPCA board interrupts
+ */
+ nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN);
+ outw(nicsr, DEPCA_NICSR);
+ outw(CSR0,DEPCA_ADDR);
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ InitRestartDepca(dev); /* ignore the return status */
+
+ if (depca_debug > 1){
+ printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
+ printk("nicsr: 0x%4.4x\n",inw(DEPCA_NICSR));
+ }
+
+ return 0; /* Always succeed */
+}
+
+/* Initialize the lance Rx and Tx descriptor rings. */
+static void
+depca_init_ring(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ unsigned long i;
+
+ lp->init_block.mode = DTX | DRX; /* Disable Rx and Tx. */
+ lp->cur_rx = lp->cur_tx = 0;
+ lp->dirty_rx = lp->dirty_tx = 0;
+
+ /* Initialize the base addresses and length of each buffer in the ring */
+ for (i = 0; i < lp->ringSize; i++) {
+ lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
+ lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+ lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
+ (unsigned long)(0x00ffffff);
+ }
+
+ /* Set up the initialization block */
+ for (i = 0; i < ETH_ALEN; i++) {
+ lp->init_block.phys_addr[i] = dev->dev_addr[i];
+ }
+ for (i = 0; i < 4; i++) {
+ lp->init_block.filter[i] = 0x0000;
+ }
+ lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen;
+ lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen;
+
+ lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+}
+
+/*
+** Writes a socket buffer to TX descriptor ring and starts transmission
+*/
+static int
+depca_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int status = 0;
+
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5) {
+ status = -1;
+ } else {
+ STOP_DEPCA;
+ printk("%s: transmit timed out, status %4.4x, resetting.\n",
+ dev->name, inw(DEPCA_DATA));
+
+ depca_init_ring(dev);
+ LoadCSRs(dev);
+ InitRestartDepca(dev);
+ dev->tbusy=0;
+ dev->trans_start = jiffies;
+ }
+ return status;
+ }
+
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* Fill in the ethernet header. */
+ if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp=1;
+
+ if (skb->len <= 0) {
+ return 0;
+ }
+
+ if (depca_debug > 3) {
+ outw(CSR0, DEPCA_ADDR);
+ printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
+ inw(DEPCA_DATA));
+ }
+
+ /* 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);
+
+ /*
+ ** The TX buffer, skb, has to be copied into the local network RAM
+ ** for the LANCE to access it. The skb may be at > 16MB for large
+ ** (memory) systems.
+ */
+ { /* Fill in a Tx ring entry */
+ unsigned char *buf;
+ int entry = lp->cur_tx++;
+ int len;
+ long skbL = skb->len;
+ char *p = (char *)(skb + 1);
+
+ entry &= lp->rmask; /* Ring around buffer number. */
+ buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+ /* Wait for a full ring to free up */
+ while (lp->tx_ring[entry].base < 0);
+
+ /*
+ ** Caution: the write order is important here... don't set up the
+ ** ownership rights until all the other information is in place.
+ */
+ len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
+ if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
+ skbL -= len;
+ lp->tx_ring[entry].length = -len;
+
+ /* Clears various error flags */
+ lp->tx_ring[entry].misc = 0x0000;
+
+ /* copy the data from the socket buffer to the net memory */
+ memcpy((unsigned char *)(buf), (unsigned char *)(skb + 1), len);
+
+ /* Hand over buffer ownership to the LANCE */
+ if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
+ lp->tx_ring[entry].base |= (T_OWN|T_STP);
+
+ /* Trigger an immediate send demand. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(INEA | TDMD, DEPCA_DATA);
+
+ dev->trans_start = jiffies;
+
+ for (p += len; skbL > 0; p += len) {
+
+ /* Get new buffer pointer */
+ entry = lp->cur_tx++;
+ entry &= lp->rmask; /* Ring around buffer number. */
+ buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+ /* Wait for a full ring to free up */
+ while (lp->tx_ring[entry].base < 0);
+ dev->tbusy=0;
+
+ /* Copy ethernet header to the new buffer */
+ memcpy((unsigned char *)buf, (unsigned char *)(skb + 1), PKT_HDR_LEN);
+
+ /* Determine length of data buffer */
+ len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
+ if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
+ skbL -= len;
+ lp->tx_ring[entry].length = -len;
+
+ /* Clears various error flags */
+ lp->tx_ring[entry].misc = 0x0000;
+
+ /* copy the data from the socket buffer to the net memory */
+ memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
+
+ /* Hand over buffer ownership to the LANCE */
+ if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
+ lp->tx_ring[entry].base |= T_OWN;
+ }
+
+ if (depca_debug > 4) {
+ unsigned char *pkt =
+ (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+ printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
+ dev->name, entry, (unsigned long) &lp->tx_ring[entry],
+ lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
+ printk("%s: Tx %2.2x %2.2x %2.2x ... %2.2x %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x %2.2x %2.2x.\n",
+ dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
+ pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
+ pkt[14], pkt[15]);
+ }
+
+ /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
+ if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
+ dev->tbusy=0;
+ }
+
+ if (skb->free) {
+ kfree_skb (skb, FREE_WRITE);
+ }
+ }
+
+ return 0;
+}
+
+/*
+** The DEPCA interrupt handler.
+*/
+static void
+depca_interrupt(int reg_ptr)
+{
+ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct depca_private *lp;
+ int csr0, ioaddr, nicsr;
+
+ if (dev == NULL) {
+ printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ } else {
+ lp = (struct depca_private *)dev->priv;
+ ioaddr = dev->base_addr;
+ }
+
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+ dev->interrupt = MASK_INTERRUPTS;
+
+ /* mask the DEPCA board interrupts and turn on the LED */
+ nicsr = inw(DEPCA_NICSR);
+ nicsr |= (IM|LED);
+ outw(nicsr, DEPCA_NICSR);
+
+ outw(CSR0, DEPCA_ADDR);
+ csr0 = inw(DEPCA_DATA);
+
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+
+ if (depca_debug > 5)
+ printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
+ dev->name, csr0, inw(DEPCA_DATA));
+
+ if (csr0 & RINT) /* Rx interrupt (packet arrived) */
+ depca_rx(dev);
+
+ if (csr0 & TINT) /* Tx interrupt (packet sent) */
+ depca_tx(dev);
+
+ /* Clear the interrupts we've handled. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+
+ if (depca_debug > 4) {
+ printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+ dev->name, inw(DEPCA_ADDR),
+ inw(DEPCA_DATA));
+ }
+
+ /* Unmask the DEPCA board interrupts and turn off the LED */
+ nicsr = (nicsr & ~IM & ~LED);
+ outw(nicsr, DEPCA_NICSR);
+
+ dev->interrupt = UNMASK_INTERRUPTS;
+ return;
+}
+
+static int
+depca_rx(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int entry = lp->cur_rx & lp->rmask;
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
+ int status = lp->rx_ring[entry].base >> 16 ;
+
+ if (status & R_ERR) { /* There was an error. */
+ lp->stats.rx_errors++; /* Update the error stats. */
+ if (status & R_FRAM) lp->stats.rx_frame_errors++;
+ if (status & R_OFLO) lp->stats.rx_over_errors++;
+ if (status & R_CRC) lp->stats.rx_crc_errors++;
+ if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+ } else { /* Malloc up new buffer, compatible with net-2e. */
+ short pkt_len = lp->rx_ring[entry].msg_length;
+ 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, deferring packet.\n", dev->name);
+ lp->stats.rx_dropped++; /* Really, deferred. */
+ break;
+ }
+ skb->mem_len = sksize;
+ skb->mem_addr = skb;
+ skb->len = pkt_len;
+ skb->dev = dev;
+ memcpy((unsigned char *)(skb + 1),
+ (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
+ pkt_len);
+ /*
+ ** Notify the upper protocol layers that there is another
+ ** packet to handle
+ */
+#ifdef HAVE_NETIF_RX
+ netif_rx(skb);
+#else
+ skb->lock = 0;
+ if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+ kfree_skbmem(skb, sksize);
+ lp->stats.rx_dropped++;
+ break;
+ }
+#endif
+ lp->stats.rx_packets++;
+ }
+
+ /* turn over ownership of the current entry back to the LANCE */
+ lp->rx_ring[entry].base |= R_OWN;
+ }
+
+ /*
+ ** We should check that at least two ring entries are free. If not,
+ ** we should free one and mark stats->rx_dropped++.
+ */
+
+ return 0;
+}
+
+/*
+** Buffer sent - check for buffer errors.
+*/
+static int
+depca_tx(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int dirty_tx = lp->dirty_tx & lp->rmask;
+
+ if (depca_debug > 5)
+ printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
+ dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
+
+ /*
+ ** While the dirty entry is not the current one AND
+ ** the LANCE doesn't own it...
+ */
+ for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
+ dirty_tx = ++lp->dirty_tx & lp->rmask) {
+ unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
+ int status = lp->tx_ring[dirty_tx].base >> 16;
+
+ if (status < 0) { /* Packet not yet sent! */
+ printk("interrupt for packet not yet sent!\n");
+ break;
+ }
+ if (status & T_ERR) { /* There was an major error, log it. */
+ int err_status = lp->tx_ring[dirty_tx].misc;
+
+ lp->stats.tx_errors++;
+ if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+ if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+ if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+ /* We should re-init() after the FIFO error. */
+ } else if (status & (T_MORE | T_ONE)) {
+ lp->stats.collisions++;
+ } else {
+ lp->stats.tx_packets++;
+ }
+
+ if (depca_debug > 5)
+ printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
+ dev->name, dirty_tx,
+ tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+ }
+ /*mark_bh(INET_BH);*/
+ return 0;
+}
+
+static int
+depca_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ outw(CSR0, DEPCA_ADDR);
+
+ if (depca_debug > 1) {
+ printk("%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inw(DEPCA_DATA));
+ }
+
+ /*
+ ** We stop the DEPCA here -- it occasionally polls
+ ** memory if we don't.
+ */
+ outw(STOP, DEPCA_DATA);
+
+ free_irq(dev->irq);
+
+ irq2dev_map[dev->irq] = 0;
+
+ return 0;
+}
+
+static void LoadCSRs(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
+ outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA);
+ outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
+ outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA);
+ outw(CSR3, DEPCA_ADDR); /* ALE control */
+ outw(ACON, DEPCA_DATA);
+ outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
+}
+
+static int InitRestartDepca(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int i, status=0;
+
+ outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
+ outw(INIT, DEPCA_DATA); /* initialize DEPCA */
+
+ /* wait for lance to complete initialisation */
+ for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++);
+
+ if (i!=100) {
+ /* clear IDON by writing a "1", enable interrupts and start lance */
+ outw(IDON | INEA | STRT, DEPCA_DATA);
+ if (depca_debug > 2) {
+ printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
+ dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+ }
+ } else {
+ status = -1;
+ printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
+ dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+ }
+
+ return status;
+}
+
+static struct enet_statistics *
+depca_get_stats(struct device *dev)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+
+ /* Null body since there is no framing error counter */
+
+ 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)
+{
+ short ioaddr = dev->base_addr;
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+
+ /* We take the simple way out and always enable promiscuous mode. */
+ STOP_DEPCA; /* Temporarily stop the depca. */
+
+ lp->init_block.mode = PROM; /* Set promiscuous mode */
+ if (num_addrs >= 0) {
+ short multicast_table[4];
+ int i;
+
+ SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table);
+
+ /* We don't use the multicast table, but rely on upper-layer filtering. */
+ memset(multicast_table, (num_addrs==0) ? 0 : -1, sizeof(multicast_table));
+
+ for (i = 0; i < 4; i++) {
+ lp->init_block.filter[i] = multicast_table[i];
+ }
+ lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
+ } else {
+ lp->init_block.mode |= PROM; /* Set promiscuous mode */
+ }
+
+ outw(CSR0, DEPCA_ADDR);
+ outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Derived from a 'C' program in the AMD data book:
+** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
+** Pub #17781, Rev. A, May 1993
+*/
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
+{
+ char j, ctrl, bit, octet, hashcode;
+ short int i;
+ long int CRC, poly = (long int) CRC_POLYNOMIAL;
+
+ for (i=0;i<num_addrs;i++) { /* for each address in the list */
+ if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */
+ CRC = (long int) 0xffffffff; /* init CRC for each address */
+ for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
+ for(j=0;j<8;j++) { /* process each address bit */
+ bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
+ ctrl = ((CRC < 0) ? 1 : 0); /* shift the control bit */
+ CRC <<= 1; /* shift the CRC */
+ if (bit ^ ctrl) { /* (bit) XOR (control bit) */
+ CRC ^= poly; /* (CRC) XOR (polynomial) */
+ }
+ }
+ }
+ hashcode = (CRC & 0x00000001); /* hashcode is 6 LSb of CRC ... */
+ for (j=0;j<5;j++) { /* ... in reverse order. */
+ hashcode <<= 1;
+ CRC >>= 1;
+ hashcode |= (CRC & 0x00000001);
+ }
+ octet = hashcode >> 3; /* bit[3-5] -> octet in filter */
+ /* bit[0-2] -> bit in octet */
+ multicast_table[octet] |= (1 << (hashcode & 0x07));
+ }
+ }
+ return;
+}
+
+#endif /* HAVE_MULTICAST */
+
+/*
+** Look for a particular board name in the on-board Remote Diagnostics
+** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** base address.
+*/
+static char *DepcaSignature(unsigned long mem_addr)
+{
+ unsigned long i,j,k;
+ static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
+ static char thisName[DEPCA_NAME_LENGTH];
+ char tmpstr[17];
+
+ for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */
+ tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+ }
+ tmpstr[i]=(char)NULL;
+
+ strcpy(thisName,"");
+ for (i=0;*signatures[i]!=(char)NULL && *thisName==(char)NULL;i++) {
+ for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
+ if (signatures[i][k] == tmpstr[j]) { /* track signature */
+ k++;
+ } else { /* lost signature; begin search again */
+ k=0;
+ }
+ }
+ if (k == strlen(signatures[i])) {
+ strcpy(thisName,signatures[i]);
+ }
+ }
+
+ return thisName; /* return the device name string */
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all DEPCA products.
+*/
+
+static int DevicePresent(short ioaddr)
+{
+ static short fp=1,sigLength=0;
+ static char devSig[] = PROBE_SEQUENCE;
+ char data;
+ int i, j, status = 0;
+ static char asc2hex(char value);
+
+/*
+** Convert the ascii signature to a hex equivalent & pack in place
+*/
+ if (fp) { /* only do this once!... */
+ for (i=0,j=0;devSig[i]!=(char)NULL && !status;i+=2,j++) {
+ if ((devSig[i]=asc2hex(devSig[i]))>=0) {
+ devSig[i]<<=4;
+ if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){
+ devSig[j]=devSig[i]+devSig[i+1];
+ } else {
+ status= -1;
+ }
+ } else {
+ status= -1;
+ }
+ }
+ sigLength=j;
+ fp = 0;
+ }
+
+/*
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the length of the (signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+ if (!status) {
+ for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+ data = inb(ioaddr);
+ if (devSig[j] == data) { /* track signature */
+ j++;
+ } else { /* lost signature; begin search again */
+ j=0;
+ }
+ }
+
+ if (j!=sigLength) {
+ status = -ENODEV; /* search failed */
+ }
+ }
+
+ return status;
+}
+
+static char asc2hex(char value)
+{
+ value -= 0x30; /* normalise to 0..9 range */
+ if (value >= 0) {
+ if (value > 9) { /* but may not be 10..15 */
+ value &= 0x1f; /* make A..F & a..f be the same */
+ value -= 0x07; /* normalise to 10..15 range */
+ if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */
+ value = -1; /* ...signal error */
+ }
+ }
+ } else { /* outside 0..9 range... */
+ value = -1; /* ...signal error */
+ }
+ return value; /* return hex char or error */
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c depca.c"
+ * End:
+ */
+
+
+
diff --git a/drivers/net/depca.h b/drivers/net/depca.h
new file mode 100644
index 0000000..4f5d719
--- /dev/null
+++ b/drivers/net/depca.h
@@ -0,0 +1,128 @@
+/*
+ Written 1994 by David C. Davies.
+
+ Copyright 1994 David C. Davies. This software may be used and distributed
+ according to the terms of the GNU Public License, incorporated herein by
+ reference.
+*/
+
+/*
+** I/O addresses. Note that the 2k buffer option is not supported in
+** this driver.
+*/
+#define DEPCA_NICSR ioaddr+0x00 /* Network interface CSR */
+#define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */
+#define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */
+#define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */
+#define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */
+#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
+
+/*
+** These are LANCE registers addressable through DEPCA_ADDR
+*/
+#define CSR0 0
+#define CSR1 1
+#define CSR2 2
+#define CSR3 3
+
+/*
+** NETWORK INTERFACE CSR (NI_CSR) bit definitions
+*/
+
+#define TO 0x0100 /* Time Out for remote boot */
+#define SHE 0x0080 /* SHadow memory Enable */
+#define BS 0x0040 /* Bank Select */
+#define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */
+#define RBE 0x0010 /* Remote Boot Enable (1->net boot) */
+#define AAC 0x0008 /* for DEPCA family compatability */
+#define IM 0x0004 /* Interrupt Mask (1->mask) */
+#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
+#define LED 0x0001 /* LED control */
+
+/*
+** Control and Status Register 0 (CSR0) bit definitions
+*/
+
+#define ERR 0x8000 /* Error summary */
+#define BABL 0x4000 /* Babble transmitter timeout error */
+#define CERR 0x2000 /* Collision Error */
+#define MISS 0x1000 /* Missed packet */
+#define MERR 0x0800 /* Memory Error */
+#define RINT 0x0400 /* Receiver Interrupt */
+#define TINT 0x0200 /* Transmit Interrupt */
+#define IDON 0x0100 /* Initialization Done */
+#define INTR 0x0080 /* Interrupt Flag */
+#define INEA 0x0040 /* Interrupt Enable */
+#define RXON 0x0020 /* Receiver on */
+#define TXON 0x0010 /* Transmitter on */
+#define TDMD 0x0008 /* Transmit Demand */
+#define STOP 0x0004 /* Stop */
+#define STRT 0x0002 /* Start */
+#define INIT 0x0001 /* Initialize */
+
+/*
+** CONTROL AND STATUS REGISTER 3 (CSR3)
+*/
+
+#define BSWP 0x0004 /* Byte SWaP */
+#define ACON 0x0002 /* ALE control */
+#define BCON 0x0001 /* Byte CONtrol */
+
+/*
+** Initialization Block Mode Register
+*/
+
+#define PROM 0x8000 /* Promiscuous Mode */
+#define EMBA 0x0080 /* Enable Modified Back-off Algorithm */
+#define INTL 0x0040 /* Internal Loopback */
+#define DRTY 0x0020 /* Disable Retry */
+#define COLL 0x0010 /* Force Collision */
+#define DTCR 0x0008 /* Disable Transmit CRC */
+#define LOOP 0x0004 /* Loopback */
+#define DTX 0x0002 /* Disable the Transmitter */
+#define DRX 0x0001 /* Disable the Receiver */
+
+/*
+** Receive Message Descriptor 1 (RMD1) bit definitions.
+*/
+
+#define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
+#define R_ERR 0x4000 /* Error Summary */
+#define R_FRAM 0x2000 /* Framing Error */
+#define R_OFLO 0x1000 /* Overflow Error */
+#define R_CRC 0x0800 /* CRC Error */
+#define R_BUFF 0x0400 /* Buffer Error */
+#define R_STP 0x0200 /* Start of Packet */
+#define R_ENP 0x0100 /* End of Packet */
+
+/*
+** Transmit Message Descriptor 1 (TMD1) bit definitions.
+*/
+
+#define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
+#define T_ERR 0x4000 /* Error Summary */
+#define T_ADD_FCS 0x2000 /* More the 1 retry needed to Xmit */
+#define T_MORE 0x1000 /* >1 retry to transmit packet */
+#define T_ONE 0x0800 /* 1 try needed to transmit the packet */
+#define T_DEF 0x0400 /* Deferred */
+#define T_STP 0x02000000 /* Start of Packet */
+#define T_ENP 0x01000000 /* End of Packet */
+
+/*
+** Transmit Message Descriptor 3 (TMD3) bit definitions.
+*/
+
+#define TMD3_BUFF 0x8000 /* BUFFer error */
+#define TMD3_UFLO 0x4000 /* UnderFLOw error */
+#define TMD3_RES 0x2000 /* REServed */
+#define TMD3_LCOL 0x1000 /* Late COLlision */
+#define TMD3_LCAR 0x0800 /* Loss of CARrier */
+#define TMD3_RTRY 0x0400 /* ReTRY error */
+
+/*
+** Miscellaneous
+*/
+
+#define MASK_INTERRUPTS 1
+#define UNMASK_INTERRUPTS 0
+
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index e6c3dbe..a8d8689 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -605,6 +605,7 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
struct buffer_head * bh;
struct ext2_super_block * es;
unsigned long desc_count, bitmap_count, x;
+ unsigned long desc_blocks;
int bitmap_nr;
struct ext2_group_desc * gdp;
int i, j;
@@ -614,12 +615,24 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
+ desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
+ EXT2_DESC_PER_BLOCK(sb);
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
gdp = get_group_desc (sb, i, NULL);
desc_count += gdp->bg_free_blocks_count;
bitmap_nr = load_block_bitmap (sb, i);
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
+ if (!test_bit (0, bh->b_data))
+ ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Superblock in group %d is marked free", i);
+
+ for (j = 0; j < desc_blocks; j++)
+ if (!test_bit (j + 1, bh->b_data))
+ ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Descriptor block #%d in group "
+ "%d is marked free", j, i);
+
if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
"Block bitmap for group %d is marked free",
@@ -632,9 +645,9 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++)
if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
- ext2_error (sb, "ext2_check_blocks_bitmap",
- "Block #%d of the inode table in group %d "
- "is marked free", j, i);
+ ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Block #%d of the inode table in "
+ "group %d is marked free", j, i);
x = ext2_count_free (bh, sb->s_blocksize);
if (gdp->bg_free_blocks_count != x)
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index cc28496..b36598a 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -12,6 +12,11 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
@@ -28,6 +33,10 @@
:"a" (value), "c" (size / 4), "D" ((long) (addr)) \
:"cx", "di")
+static int ext2_secrm_seed = 152; /* Random generator base */
+
+#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
+
/*
* Truncate has the most races in the whole filesystem: coding it is
* a pain in the a**. Especially as I don't do any locking...
@@ -80,7 +89,7 @@ repeat:
inode->i_dirt = 1;
if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
clear_block (bh->b_data, inode->i_sb->s_blocksize,
- CURRENT_TIME);
+ RANDOM_INT);
bh->b_dirt = 1;
}
brelse (bh);
@@ -156,7 +165,7 @@ repeat:
ind_bh->b_dirt = 1;
if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
clear_block (bh->b_data, inode->i_sb->s_blocksize,
- CURRENT_TIME);
+ RANDOM_INT);
bh->b_dirt = 1;
}
brelse (bh);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 932d26c..36f302d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -302,6 +302,8 @@ extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern unsigned long volatile jiffies;
+extern unsigned long itimer_ticks;
+extern unsigned long itimer_next;
extern struct timeval xtime;
extern int need_resched;
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 39d95e3..922029c 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -81,14 +81,23 @@ int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
return k;
switch (which) {
case ITIMER_REAL:
+ if (j) {
+ j += 1+itimer_ticks;
+ if (j < itimer_next)
+ itimer_next = j;
+ }
current->it_real_value = j;
current->it_real_incr = i;
break;
case ITIMER_VIRTUAL:
+ if (j)
+ j++;
current->it_virt_value = j;
current->it_virt_incr = i;
break;
case ITIMER_PROF:
+ if (j)
+ j++;
current->it_prof_value = j;
current->it_prof_incr = i;
break;
diff --git a/kernel/sched.c b/kernel/sched.c
index a9f52ce..cbd4725 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -192,8 +192,8 @@ asmlinkage void math_emulate(long arg)
#endif /* CONFIG_MATH_EMULATION */
-static unsigned long itimer_ticks = 0;
-static unsigned long itimer_next = ~0;
+unsigned long itimer_ticks = 0;
+unsigned long itimer_next = ~0;
static unsigned long lost_ticks = 0;
/*
diff --git a/net/inet/dev.c b/net/inet/dev.c
index a620738..5d8c570 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -966,7 +966,6 @@ dev_ioctl(unsigned int cmd, void *arg)
{
struct iflink iflink;
struct ddi_device *dev;
- int ret;
switch(cmd) {
case IP_SET_DEV:
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index dc06c75..30c48e2 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -60,7 +60,9 @@
* Charles Hedrick : TCP fixes
* Toomas Tamm : TCP window fixes
* Alan Cox : Small URG fix to rlogin ^C ack fight
- * Linus : Rewrote URG handling completely
+ * Charles Hedrick : Window fix
+ * Linus : Rewrote tcp_read() and URG handling
+ * completely
*
*
* To Fix:
@@ -1293,175 +1295,111 @@ tcp_read_urg(struct sock * sk, int nonblock,
/* This routine copies from a sock struct into the user buffer. */
-static int
-tcp_read(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags)
+static int tcp_read(struct sock *sk, unsigned char *to,
+ int len, int nonblock, unsigned flags)
{
- int copied = 0; /* will be used to say how much has been copied. */
- struct sk_buff *skb;
- unsigned long peek_seq;
- unsigned long offset;
- unsigned long *seq;
- int err;
+ struct wait_queue wait = { current, NULL };
+ int copied = 0;
+ unsigned long peek_seq;
+ unsigned long *seq;
+ unsigned long used;
+ int err;
- if (len == 0)
- return 0;
+ if (len == 0)
+ return 0;
- if (len < 0)
- return -EINVAL;
+ if (len < 0)
+ return -EINVAL;
- err=verify_area(VERIFY_WRITE,to,len);
- if (err)
- return err;
+ err = verify_area(VERIFY_WRITE, to, len);
+ if (err)
+ return err;
- /* This error should be checked. */
- if (sk->state == TCP_LISTEN)
- return -ENOTCONN;
+ /* This error should be checked. */
+ if (sk->state == TCP_LISTEN)
+ return -ENOTCONN;
- /* Urgent data needs to be handled specially. */
- if (flags & MSG_OOB)
- return tcp_read_urg(sk, nonblock, to, len, flags);
+ /* Urgent data needs to be handled specially. */
+ if (flags & MSG_OOB)
+ return tcp_read_urg(sk, nonblock, to, len, flags);
- /* So no-one else will use this socket. */
- sk->inuse = 1;
- skb=skb_peek(&sk->rqueue);
+ peek_seq = sk->copied_seq;
+ seq = &sk->copied_seq;
+ if (flags & MSG_PEEK)
+ seq = &peek_seq;
- peek_seq = sk->copied_seq;
- seq = &sk->copied_seq;
- if (flags & MSG_PEEK)
- seq = &peek_seq;
+ add_wait_queue(sk->sleep, &wait);
+ sk->inuse = 1;
+ while (len > 0) {
+ struct sk_buff * skb;
+ unsigned long offset;
+
+ /*
+ * are we at urgent data? Stop if we have read anything.
+ */
+ if (copied && sk->urg_data && sk->urg_seq == 1+*seq)
+ break;
- DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
- sk, to, len, nonblock, flags));
+ current->state = TASK_INTERRUPTIBLE;
- while(len > 0) {
- /* skb->used just checks to see if we've gone all the way around. */
-
- /* While no data, or first data indicates some is missing, or data is used */
- while(skb == NULL || skb->used || before(1+*seq, skb->h.th->seq)) {
- DPRINTF((DBG_TCP, "skb = %X:\n", skb));
- cleanup_rbuf(sk);
- if (sk->err)
- {
- int tmp;
+ skb = sk->rqueue;
+ do {
+ if (!skb)
+ break;
+ if (before(1+*seq, skb->h.th->seq))
+ break;
+ offset = 1 + *seq - skb->h.th->seq;
+ if (skb->h.th->syn)
+ offset--;
+ if (offset < skb->len)
+ goto found_ok_skb;
+ if (!(flags & MSG_PEEK))
+ skb->used = 1;
+ skb = (struct sk_buff *)skb->next;
+ } while (skb != sk->rqueue);
- release_sock(sk);
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- tmp = -sk->err;
+ if (copied)
+ break;
+
+ if (sk->err) {
+ copied = -sk->err;
sk->err = 0;
- return(tmp);
+ break;
}
- if (sk->state == TCP_CLOSE)
- {
- release_sock(sk);
- if (copied) {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
+ if (sk->state == TCP_CLOSE) {
if (!sk->done) {
sk->done = 1;
- return(0);
+ break;
}
- return(-ENOTCONN);
+ copied = -ENOTCONN;
+ break;
}
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- if (copied == 0) sk->done = 1;
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- return(copied);
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ sk->done = 1;
+ break;
}
- if (nonblock || copied)
- {
- release_sock(sk);
- if(sk->debug)
- printk("read: EAGAIN\n");
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- return(-EAGAIN);
+ if (nonblock) {
+ copied = -EAGAIN;
+ break;
}
- if ((flags & MSG_PEEK) && copied != 0)
- {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- return(copied);
- }
-
- DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
- sk->state));
+ cleanup_rbuf(sk);
release_sock(sk);
-
- /*
- * Now we may have some data waiting or we could
- * have changed state.
- */
- cli();
- if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) {
- sk->inuse = 1;
- sti();
- continue;
- }
-
- skb = skb_peek(&sk->rqueue);
- if (skb == NULL || before(1+*seq, skb->h.th->seq)) {
- if(sk->debug)
- printk("Read wait sleep\n");
- interruptible_sleep_on(sk->sleep);
- if(sk->debug)
- printk("Read wait wakes\n");
- if (current->signal & ~current->blocked) {
- sti();
- if (copied) {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- return(-ERESTARTSYS);
- }
- }
+ schedule();
sk->inuse = 1;
- sti();
- DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
-
- skb=skb_peek(&sk->rqueue);
- /* That may have been null if we were beaten, if so we loop again */
- }
-
- /*
- * are we at urgent data? Stop if we have read anything.
- */
- if (copied && sk->urg_data && sk->urg_seq == 1+*seq) {
- release_sock(sk);
- return copied;
- }
-
- /*
- * Copy anything from the current block that needs
- * to go into the user buffer.
- */
- offset = *seq - skb->h.th->seq + 1;
-
- if (skb->h.th->syn) offset--;
+ if (current->signal & ~current->blocked) {
+ copied = -ERESTARTSYS;
+ break;
+ }
+ continue;
- if (offset < skb->len) /* Some of the packet is useful */
- {
+ found_ok_skb:
/* Ok so how much can we use ? */
- unsigned long used = skb->len - offset;
+ used = skb->len - offset;
if (len < used)
used = len;
/* do we have urgent data here? */
@@ -1469,50 +1407,38 @@ tcp_read(struct sock *sk, unsigned char *to,
unsigned long urg_offset = sk->urg_seq - (1 + *seq);
if (urg_offset < used) {
if (!urg_offset) {
- if (!(flags & MSG_PEEK))
- sk->urg_data = 0;
if (!sk->urginline) {
++*seq;
offset++;
used--;
}
} else
- used = offset;
+ used = urg_offset;
}
}
/* Copy it */
memcpy_tofs(to,((unsigned char *)skb->h.th) +
- skb->h.th->doff*4 + offset, used);
+ skb->h.th->doff*4 + offset, used);
copied += used;
len -= used;
to += used;
*seq += used;
-
- /*
- * Mark this data used if we are really reading it, and we
- * have used all the data.
- */
- if (!(flags & MSG_PEEK) && (used + offset >= skb->len))
- skb->used = 1;
- }
- else
- { /* already used this data, must be a retransmit */
- if (!(flags & MSG_PEEK))
+ if (after(sk->copied_seq+1,sk->urg_seq))
+ sk->urg_data = 0;
+ if (!(flags & MSG_PEEK) && (used + offset >= skb->len))
skb->used = 1;
}
- /* Move along a packet */
- skb =(struct sk_buff *)skb->next;
- }
- /* Clean up data we have read: This will do ACK frames */
- cleanup_rbuf(sk);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- if (copied == 0 && nonblock)
- return(-EAGAIN);
- return(copied);
+ remove_wait_queue(sk->sleep, &wait);
+ current->state = TASK_RUNNING;
+
+ /* Clean up data we have read: This will do ACK frames */
+ cleanup_rbuf(sk);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ return copied;
}
-
+
/*
* Send a FIN without closing the connection.
* Not called at interrupt time.