Misc Fixes

Alan Cox (alan@lxorguk.ukuu.org.uk)
Sun, 7 Jul 1996 19:28:21 +0100 (BST)


Oops this bounced first time.

o Bridging basically works [say thanks to 3com for lending me the boards]
o Removed an excess initialiser
o 3c59x driver version 25 (that got in by accident but ought to be in 2.0
the shipped version is utterly useless with the current 3c590 cards)
o Ext2s module now loads
o Gratutious arp cleaned up and handled specially for Metricom STRIP

Now to finish debugging multicast routing

Alan

[Note just got mail from Linus bitching about the changes to BAYCOM_USE_BH
as CONFIG_BAYCOM_USE_BH] - really thats because it belongs in Config.in.
Baycom people might want to put that config item into drivers/char/Config.in
instead.]

diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/drivers/char/baycom.c linux/drivers/char/baycom.c
--- linux.vanilla/drivers/char/baycom.c Thu Jul 4 00:23:15 1996
+++ linux/drivers/char/baycom.c Sun Jul 7 14:44:41 1996
@@ -298,9 +298,9 @@
int opened;
struct tty_struct *tty;

-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
struct tq_struct tq_receiver, tq_transmitter, tq_arbitrate;
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */

struct packet_buffer rx_buf;
struct packet_buffer tx_buf;
@@ -330,9 +330,9 @@

struct baycom_state baycom_state[NR_PORTS];

-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
DECLARE_TASK_QUEUE(tq_baycom);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */

/* --------------------------------------------------------------------- */

@@ -565,14 +565,14 @@

/* ---------------------------------------------------------------------- */

-static inline unsigned int tenms_to_flags(struct baycom_state *bc,
+static inline unsigned int tenms_to_2flags(struct baycom_state *bc,
unsigned int tenms)
{
switch (bc->modem_type) {
case BAYCOM_MODEM_SER12:
- return tenms * 12 / 8;
+ return tenms * 3 / 4;
case BAYCOM_MODEM_PAR96:
- return tenms * 12;
+ return tenms * 6;
default:
return 0;
}
@@ -697,7 +697,7 @@
&bc->hdlc_tx.len);
if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) {
bc->hdlc_tx.tx_state = 1;
- bc->hdlc_tx.numflags = tenms_to_flags
+ bc->hdlc_tx.numflags = tenms_to_2flags
(bc, bc->ch_params.tx_tail);
break;
}
@@ -777,9 +777,10 @@
if ((random_num() % 256) > bc->ch_params.ppersist)
return;
}
- bc->hdlc_tx.ptt = 1;
bc->hdlc_tx.tx_state = 0;
- bc->hdlc_tx.numflags = tenms_to_flags(bc, bc->ch_params.tx_delay);
+ bc->hdlc_tx.numflags = tenms_to_2flags(bc, bc->ch_params.tx_delay);
+ bc->hdlc_tx.numbits = bc->hdlc_tx.bitbuf = bc->hdlc_tx.bitstream = 0;
+ bc->hdlc_tx.ptt = 1;
bc->stat.ptt_keyed++;
}

@@ -899,7 +900,7 @@
bc->hdlc_tx.shreg1 = 0x10000;
bc->calibrate--;
} else {
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2;
bc->hdlc_tx.shreg2 = 0;
queue_task_irq_off(&bc->tq_transmitter,
@@ -910,13 +911,13 @@
queue_task_irq_off(&bc->tq_receiver,
&tq_baycom);
#endif /* HDLC_LOOPBACK */
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
bc->hdlc_tx.shreg1 = hdlc_tx_word(bc)
| 0x10000;
#ifdef HDLC_LOOPBACK
hdlc_rx_word(bc, bc->hdlc_tx.shreg1);
#endif /* HDLC_LOOPBACK */
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
}
}
if (!(bc->hdlc_tx.shreg1 & 1))
@@ -1042,22 +1043,22 @@
bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
}
if (bc->hdlc_rx.shreg1 & 1) {
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
bc->hdlc_rx.shreg2 = (bc->hdlc_rx.shreg1 >> 1) | 0x10000;
queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
mark_bh(BAYCOM_BH);
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
hdlc_rx_word(bc, bc->hdlc_rx.shreg1 >> 1);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
bc->hdlc_rx.shreg1 = 0x10000;
}
if (--bc->modem.arb_divider <= 0) {
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom);
mark_bh(BAYCOM_BH);
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
tx_arbitrate(bc);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
bc->modem.arb_divider = bc->ch_params.slottime *
SER12_ARB_DIVIDER(bc);
}
@@ -1160,7 +1161,7 @@
ser12_set_divisor(bc, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6);
outb(0x0d, MCR(bc->iobase));
outb(0, IER(bc->iobase));
- if (request_irq(bc->irq, baycom_ser12_interrupt, 0,
+ if (request_irq(bc->irq, baycom_ser12_interrupt, SA_INTERRUPT,
"baycom_ser12", bc))
return -EBUSY;
/*
@@ -1210,7 +1211,7 @@
{
register struct baycom_state *bc = (struct baycom_state *)dev_id;
int i;
- unsigned int data, mask, mask2;
+ unsigned int data, descx, mask, mask2;

if (!bc || bc->magic != BAYCOM_MAGIC)
return;
@@ -1247,7 +1248,7 @@
bc->hdlc_tx.shreg1 = 0x10000;
bc->calibrate--;
} else {
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2;
bc->hdlc_tx.shreg2 = 0;
queue_task_irq_off(&bc->tq_transmitter, &tq_baycom);
@@ -1256,12 +1257,12 @@
bc->hdlc_rx.shreg2 = bc->hdlc_tx.shreg1;
queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
#endif /* HDLC_LOOPBACK */
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
bc->hdlc_tx.shreg1 = hdlc_tx_word(bc);
#ifdef HDLC_LOOPBACK
hdlc_rx_word(bc, bc->hdlc_tx.shreg1);
#endif /* HDLC_LOOPBACK */
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
}
return;
}
@@ -1269,7 +1270,6 @@
* do receiver; differential decode and descramble on the fly
*/
for(data = i = 0; i < PAR96_BURSTBITS; i++) {
- unsigned int descx;
bc->modem.par96.descram = (bc->modem.par96.descram << 1);
if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT)
bc->modem.par96.descram |= 1;
@@ -1285,14 +1285,14 @@
outb(PAR97_POWER | PAR96_PTT | PAR96_BURST,
LPT_DATA(bc->iobase));
}
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
bc->hdlc_rx.shreg2 = bc->hdlc_rx.shreg1;
bc->hdlc_rx.shreg1 = data | 0x10000;
queue_task_irq_off(&bc->tq_receiver, &tq_baycom);
mark_bh(BAYCOM_BH);
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
hdlc_rx_word(bc, data);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
/*
* do DCD algorithm
*/
@@ -1307,24 +1307,24 @@
/* check for abort/noise sequences */
for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0;
i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
- if ((bc->modem.par96.dcd_shreg & mask) == mask2)
- if (bc->modem.par96.dcd_count >= 0)
- bc->modem.par96.dcd_count -=
- BAYCOM_MAXFLEN-10;
+ if (((bc->modem.par96.dcd_shreg & mask) == mask2) &&
+ (bc->modem.par96.dcd_count >= 0))
+ bc->modem.par96.dcd_count -= BAYCOM_MAXFLEN-10;
/* decrement and set the dcd variable */
if (bc->modem.par96.dcd_count >= 0)
bc->modem.par96.dcd_count -= 2;
bc->modem.dcd = bc->modem.par96.dcd_count > 0;
} else {
- bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) & PAR96_DCD);
+ bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase))
+ & PAR96_DCD);
}
if (--bc->modem.arb_divider <= 0) {
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom);
mark_bh(BAYCOM_BH);
-#else /* BAYCOM_USE_BH */
+#else /* CONFIG_BAYCOM_USE_BH */
tx_arbitrate(bc);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
bc->modem.arb_divider = bc->ch_params.slottime * 6;
}
}
@@ -1400,7 +1400,7 @@
outb(0, LPT_CONTROL(bc->iobase)); /* disable interrupt */
/* switch off PTT */
outb(PAR96_PTT | PAR97_POWER, LPT_DATA(bc->iobase));
- if (request_irq(bc->irq, baycom_par96_interrupt, 0,
+ if (request_irq(bc->irq, baycom_par96_interrupt, SA_INTERRUPT,
"baycom_par96", bc))
return -EBUSY;
outb(LPT_IRQ_ENABLE, LPT_CONTROL(bc->iobase)); /* enable interrupt */
@@ -1424,7 +1424,7 @@
* ===================== Bottom half (soft interrupt) ====================
*/

-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
static void bh_receiver(void *private)
{
struct baycom_state *bc = (struct baycom_state *)private;
@@ -1469,7 +1469,7 @@
{
run_task_queue(&tq_baycom);
}
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */

/* --------------------------------------------------------------------- */
/*
@@ -1586,6 +1586,10 @@
}
if (!bc->kiss_decode.dec_state)
return;
+ if (ch == KISS_FESC) {
+ bc->kiss_decode.escaped = 1;
+ return;
+ }
if (bc->kiss_decode.wr >= sizeof(bc->kiss_decode.pkt_buf)) {
bc->kiss_decode.wr = 0;
bc->kiss_decode.dec_state = 0;
@@ -2085,7 +2089,7 @@

bc->ch_params = dflt_ch_params;

-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
bc->tq_receiver.next = bc->tq_transmitter.next =
bc->tq_arbitrate.next = NULL;
bc->tq_receiver.sync = bc->tq_transmitter.sync =
@@ -2095,7 +2099,7 @@
bc->tq_receiver.routine = bh_receiver;
bc->tq_transmitter.routine = bh_transmitter;
bc->tq_arbitrate.routine = bh_arbitrate;
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
}

static void init_datastructs(void)
@@ -2134,9 +2138,9 @@
/*
* initialize bottom half handler
*/
-#ifdef BAYCOM_USE_BH
+#ifdef CONFIG_BAYCOM_USE_BH
init_bh(BAYCOM_BH, baycom_bottom_half);
-#endif /* BAYCOM_USE_BH */
+#endif /* CONFIG_BAYCOM_USE_BH */
/*
* register the driver as tty driver
*/
@@ -2269,6 +2273,7 @@

printk(KERN_INFO "baycom: cleanup_module called\n");

+ disable_bh(BAYCOM_BH);
if (tty_unregister_driver(&baycom_driver))
printk(KERN_WARNING "baycom: failed to unregister tty "
"driver\n");
@@ -2320,20 +2325,3 @@

#endif /* MODULE */
/* --------------------------------------------------------------------- */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- linux.vanilla/drivers/net/3c59x.c Sun Jun 9 13:12:13 1996
+++ linux/drivers/net/3c59x.c Sun Jul 7 14:44:24 1996
@@ -7,25 +7,27 @@

This driver is for the 3Com "Vortex" series ethercards. Members of
the series include the 3c590 PCI EtherLink III and 3c595-Tx PCI Fast
- EtherLink. It also works with the 10Mbs-only 3c590 PCI EtherLink III.
+ EtherLink.

The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
*/

-static char *version = "3c59x.c:v0.13 2/13/96 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";

/* "Knobs" that turn on special features. */
+/* Enable the experimental automatic media selection code. */
+#define AUTOMEDIA 1
+
/* Allow the use of bus master transfers instead of programmed-I/O for the
Tx process. Bus master transfers are always disabled by default, but
iff this is set they may be turned on using 'options'. */
#define VORTEX_BUS_MASTER

-/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 1
-
+#ifdef MODULE
#include <linux/module.h>
+#endif

#include <linux/kernel.h>
#include <linux/sched.h>
@@ -46,11 +48,63 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>

+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#include <linux/version.h> /* Evil, but neccessary */
+#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
+
+#if (LINUX_VERSION_CODE < VERSION(1,3,0))
+#define RUN_AT(x) (x) /* What to put in timer->expires. */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+struct device *init_etherdev(struct device *dev, int sizeof_private,
+ unsigned long *mem_startp);
+#else /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(1,3,38))
+#ifdef MODULE
+#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
+char kernel_version[] = UTS_RELEASE;
+#endif
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+#endif /* 1.3.38 */
+
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+#define NEW_MULTICAST
+#endif
+
+#if (LINUX_VERSION_CODE >= VERSION(1,3,70))
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
+#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
+#else
+#define FREE_IRQ(irqnum, dev) free_irq(irqnum)
+#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n)
+#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
+#endif
+
+/* This my implementation of shared IRQs, now only used for 1.2.13. */
#ifdef HAVE_SHARED_IRQ
#define USE_SHARED_IRQ
#include <linux/shared_irq.h>
#endif

+/* "Knobs" for adjusting internal parameters. */
+/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
+#define VORTEX_DEBUG 2
+
+/* Number of times to check to see if the Tx FIFO has space, used in some
+ limited cases. */
+#define WAIT_TX_AVAIL 200
+
+/* Operational parameter that usually are not changed. */
+#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */
+
/* The total size is twice that of the original EtherLinkIII series: the
runtime register window, window 1, is now always mapped in. */
#define VORTEX_TOTAL_SIZE 0x20
@@ -117,7 +171,7 @@
Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing both
3c590 and 3c595 boards.
The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
-the not-yet-released (3/95) EISA version is called "Demon". According to
+the EISA version is called "Demon". According to
Terry these names come from rides at the local amusement park.

The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
@@ -176,6 +230,7 @@
};
enum Window0 {
Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
+ Wn0EepromData = 12, /* Window 0: EEPROM results register. */
};
enum Win0_EEPROM_bits {
EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
@@ -206,7 +261,10 @@
Wn4_Media = 0x0A, /* Window 4: Various transcvr/media bits. */
};
enum Win4_Media_bits {
- Media_TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
+ Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
+ Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
+ Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
+ Media_LnkBeat = 0x0800,
};
enum Window7 { /* Window 7: Bus Master control. */
Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
@@ -217,17 +275,36 @@
const char *product_name;
struct device *next_module;
struct enet_statistics stats;
-#ifdef VORTEX_BUS_MASTER
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
-#endif
struct timer_list timer; /* Media selection timer. */
- int options; /* User-settable driver options (none yet). */
- unsigned int media_override:3, full_duplex:1, bus_master:1, autoselect:1;
+ int options; /* User-settable misc. driver options. */
+ int last_rx_packets; /* For media autoselection. */
+ unsigned int available_media:8, /* From Wn3_Options */
+ media_override:3, /* Passed-in media type. */
+ default_media:3, /* Read from the EEPROM. */
+ full_duplex:1, bus_master:1, autoselect:1;
};

-static char *if_names[] = {
- "10baseT", "10Mbs AUI", "undefined", "10base2",
- "100baseTX", "100baseFX", "MII", "undefined"};
+/* The action to take with a media selection timer tick.
+ Note that we deviate from the 3Com order by checking 10base2 before AUI.
+ */
+static struct media_table {
+ char *name;
+ unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
+ mask:8, /* The transceiver-present bit in Wn3_Config.*/
+ next:8; /* The media type to try next. */
+ short wait; /* Time before we check media status. */
+} media_tbl[] = {
+ { "10baseT", Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10},
+ { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10},
+ { "undefined", 0, 0x80, 0 /* Undefined */, 0},
+ { "10base2", 0, 0x10, 1 /* 10base2->AUI. */, (1*HZ)/10},
+ { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10},
+ { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10},
+ { "MII", 0, 0x40, 0 /* MII->10baseT */, (14*HZ)/10},
+ { "undefined", 0, 0x01, 0 /* Undefined/100baseT4 */, 0},
+ { "Default", 0, 0xFF, 0 /* Use default */, 0},
+};

static int vortex_scan(struct device *dev);
static int vortex_found_device(struct device *dev, int ioaddr, int irq,
@@ -237,11 +314,14 @@
static void vortex_timer(unsigned long arg);
static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
static int vortex_rx(struct device *dev);
-static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
static int vortex_close(struct device *dev);
static void update_stats(int addr, struct device *dev);
static struct enet_statistics *vortex_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
+static void set_rx_mode(struct device *dev);
+#ifndef NEW_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif


/* Unlike the other PCI cards the 59x cards don't need a large contiguous
@@ -260,7 +340,7 @@
*/
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
/* Note: this is the only limit on the number of cards supported!! */
-int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};

#ifdef MODULE
static int debug = -1;
@@ -283,7 +363,7 @@
}

#else
-unsigned long tc59x_probe(struct device *dev)
+int tc59x_probe(struct device *dev)
{
int cards_found = 0;

@@ -302,55 +382,58 @@

if (pcibios_present()) {
static int pci_index = 0;
- for (; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
- unsigned int pci_ioaddr;
- unsigned short pci_command;
- int index;
-
- for (index = 0; product_ids[index]; index++) {
- if ( ! pcibios_find_device(TCOM_VENDOR_ID, product_ids[index],
- pci_index, &pci_bus,
- &pci_device_fn))
- break;
- }
- if ( ! product_ids[index])
- break;
+ static int board_index = 0;
+ for (; product_ids[board_index]; board_index++, pci_index = 0) {
+ for (; pci_index < 16; pci_index++) {
+ unsigned char pci_bus, pci_device_fn, pci_irq_line;
+ unsigned char pci_latency;
+#if (LINUX_VERSION_CODE < VERSION(1,3,0))
+ unsigned long pci_ioaddr;
+#else
+ unsigned int pci_ioaddr;
+#endif
+ unsigned short pci_command;

- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
+ if (pcibios_find_device(TCOM_VENDOR_ID,
+ product_ids[board_index], pci_index,
+ &pci_bus, &pci_device_fn))
+ break;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;

#ifdef VORTEX_BUS_MASTER
- /* Get and check the bus-master and latency values.
- Some PCI BIOSes fail to set the master-enable bit, and
- the latency timer must be set to the maximum value to avoid
- data corruption that occurs when the timer expires during
- a transfer. Yes, it's a bug. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(" PCI Master Bit has not been set! Setting...\n");
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
+ /* Get and check the bus-master and latency values.
+ Some PCI BIOSes fail to set the master-enable bit, and
+ the latency timer must be set to the maximum value to avoid
+ data corruption that occurs when the timer expires during
+ a transfer. Yes, it's a bug. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+ printk(" PCI Master Bit has not been set! Setting...\n");
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, pci_command);
+ }
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency != 255) {
- printk(" Overriding PCI latency timer (CFLT) setting of %d, new value is 255.\n", pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 255);
- }
+ if (pci_latency != 255) {
+ printk(" Overriding PCI latency timer (CFLT) setting of"
+ " %d, new value is 255.\n", pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 255);
+ }
#endif /* VORTEX_BUS_MASTER */
- vortex_found_device(dev, pci_ioaddr, pci_irq_line, index,
- dev && dev->mem_start ? dev->mem_start
- : options[cards_found]);
- dev = 0;
- cards_found++;
+ vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index,
+ dev && dev->mem_start ? dev->mem_start
+ : options[cards_found]);
+ dev = 0;
+ cards_found++;
+ }
}
}

@@ -361,9 +444,9 @@
/* Check the standard EISA ID register for an encoded '3Com'. */
if (inw(ioaddr + 0xC80) != 0x6d50)
continue;
- /* Check for a product that we support. */
- if ((inw(ioaddr + 0xC82) & 0xFFF0) != 0x5970
- && (inw(ioaddr + 0xC82) & 0xFFF0) != 0x5920)
+ /* Check for a product that we support, 3c59{2,7} any rev. */
+ if ((inw(ioaddr + 0xC82) & 0xF0FF) != 0x7059 /* 597 */
+ && (inw(ioaddr + 0xC82) & 0xF0FF) != 0x2059) /* 592 */
continue;
vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
DEMON_INDEX, dev && dev->mem_start
@@ -415,7 +498,11 @@
dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
memset(dev->priv, 0, sizeof (struct vortex_private));
}
+#if (LINUX_VERSION_CODE < VERSION(1,3,0))
+ dev = init_etherdev(dev, sizeof(struct vortex_private), 0);
+#else
dev = init_etherdev(dev, sizeof(struct vortex_private));
+#endif
dev->base_addr = ioaddr;
dev->irq = irq;
vp = (struct vortex_private *)dev->priv;
@@ -452,12 +539,12 @@
int timer;
outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
- for (timer = 0; timer < 162*4 + 400; timer++) {
+ for (timer = 162*4 + 400; timer >= 0; timer--) {
SLOW_DOWN_IO;
if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
break;
}
- phys_addr[i] = htons(inw(ioaddr + 12));
+ phys_addr[i] = htons(inw(ioaddr + Wn0EepromData));
}
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
@@ -470,6 +557,7 @@
char *ram_split[] = {"5:3", "3:1", "1:1", "invalid"};
union wn3_config config;
EL3WINDOW(3);
+ vp->available_media = inw(ioaddr + Wn3_Options);
config.i = inl(ioaddr + Wn3_Config);
if (vortex_debug > 1)
printk(" Internal config register is %4.4x, transceivers %#x.\n",
@@ -479,8 +567,9 @@
config.u.ram_width ? "word" : "byte",
ram_split[config.u.ram_split],
config.u.autoselect ? "autoselect/" : "",
- if_names[config.u.xcvr]);
+ media_tbl[config.u.xcvr].name);
dev->if_port = config.u.xcvr;
+ vp->default_media = config.u.xcvr;
vp->autoselect = config.u.autoselect;
}

@@ -492,9 +581,10 @@
dev->hard_start_xmit = &vortex_start_xmit;
dev->stop = &vortex_close;
dev->get_stats = &vortex_get_stats;
+#ifdef NEW_MULTICAST
+ dev->set_multicast_list = &set_rx_mode;
+#else
dev->set_multicast_list = &set_multicast_list;
-#if defined (HAVE_SET_MAC_ADDR) && 0
- dev->set_mac_address = &set_mac_address;
#endif

return 0;
@@ -518,11 +608,29 @@
if (vp->media_override != 7) {
if (vortex_debug > 1)
printk("%s: Media override to transceiver %d (%s).\n",
- dev->name, vp->media_override, if_names[vp->media_override]);
- config.u.xcvr = vp->media_override;
+ dev->name, vp->media_override,
+ media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
- outl(config.i, ioaddr + Wn3_Config);
- }
+ } else if (vp->autoselect) {
+ /* Find first available media type, starting with 100baseTx. */
+ dev->if_port = 4;
+ while (! (vp->available_media & media_tbl[dev->if_port].mask))
+ dev->if_port = media_tbl[dev->if_port].next;
+
+ if (vortex_debug > 1)
+ printk("%s: Initial media type %s.\n",
+ dev->name, media_tbl[dev->if_port].name);
+
+ init_timer(&vp->timer);
+ vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+ vp->timer.data = (unsigned long)dev;
+ vp->timer.function = &vortex_timer; /* timer handler */
+ add_timer(&vp->timer);
+ } else
+ dev->if_port = vp->default_media;
+
+ config.u.xcvr = dev->if_port;
+ outl(config.i, ioaddr + Wn3_Config);

if (vortex_debug > 1) {
printk("%s: vortex_open() InternalConfig %8.8x.\n",
@@ -542,7 +650,13 @@

outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);

-#ifdef USE_SHARED_IRQ
+#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
+ if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ,
+ vp->product_name, dev)) {
+ return -EAGAIN;
+ }
+#else
+#ifdef USE_SHARED_IRQ /* Use my shared IRQ implementation. */
i = request_shared_irq(dev->irq, &vortex_interrupt, dev, vp->product_name);
if (i) /* Error */
return i;
@@ -550,11 +664,12 @@
if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL)
return -EAGAIN;
irq2dev_map[dev->irq] = dev;
- if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name, NULL)) {
+ if (REQUEST_IRQ(dev->irq, &vortex_interrupt, 0, vp->product_name, NULL)) {
irq2dev_map[dev->irq] = NULL;
return -EAGAIN;
}
-#endif
+#endif /* USE_SHARED_IRQ */
+#endif /* SA_SHIRQ */

if (vortex_debug > 1) {
EL3WINDOW(4);
@@ -572,11 +687,9 @@
if (dev->if_port == 3)
/* Start the thinnet transceiver. We should really wait 50ms...*/
outw(StartCoax, ioaddr + EL3_CMD);
- else if (dev->if_port == 0) {
- /* 10baseT interface, enabled link beat and jabber check. */
- EL3WINDOW(4);
- outw(inw(ioaddr + Wn4_Media) | Media_TP, ioaddr + Wn4_Media);
- }
+ EL3WINDOW(4);
+ outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
+ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);

/* Switch to the stats window, and clear all stats by reading. */
outw(StatsDisable, ioaddr + EL3_CMD);
@@ -592,8 +705,8 @@
/* Switch to register set 7 for normal use. */
EL3WINDOW(7);

- /* Accept b-case and phys addr only. */
- outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+ /* Set reciever mode: presumably accept b-case and phys addr only. */
+ set_rx_mode(dev);
outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */

dev->tbusy = 0;
@@ -614,22 +727,81 @@
MOD_INC_USE_COUNT;
#endif

- if (vp->autoselect) {
- init_timer(&vp->timer);
- vp->timer.expires = (14*HZ)/10; /* 1.4 sec. */
- vp->timer.data = (unsigned long)dev;
- vp->timer.function = &vortex_timer; /* timer handler */
- add_timer(&vp->timer);
- }
return 0;
}

static void vortex_timer(unsigned long data)
{
+#ifdef AUTOMEDIA
struct device *dev = (struct device *)data;
- if (vortex_debug > 2)
- printk("%s: Media selection timer tick happened.\n", dev->name);
- /* ToDo: active media selection here! */
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ unsigned long flags;
+ int ok = 0;
+
+ if (vortex_debug > 1)
+ printk("%s: Media selection timer tick happened, %s.\n",
+ dev->name, media_tbl[dev->if_port].name);
+
+ save_flags(flags); cli(); {
+ int old_window = inw(ioaddr + EL3_CMD) >> 13;
+ int media_status;
+ EL3WINDOW(4);
+ media_status = inw(ioaddr + Wn4_Media);
+ switch (dev->if_port) {
+ case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */
+ if (media_status & Media_LnkBeat) {
+ ok = 1;
+ if (vortex_debug > 1)
+ printk("%s: Media %s has link beat, %x.\n",
+ dev->name, media_tbl[dev->if_port].name, media_status);
+ } else if (vortex_debug > 1)
+ printk("%s: Media %s is has no link beat, %x.\n",
+ dev->name, media_tbl[dev->if_port].name, media_status);
+
+ break;
+ default: /* Other media types handled by Tx timeouts. */
+ if (vortex_debug > 1)
+ printk("%s: Media %s is has no indication, %x.\n",
+ dev->name, media_tbl[dev->if_port].name, media_status);
+ ok = 1;
+ }
+ if ( ! ok) {
+ union wn3_config config;
+
+ do {
+ dev->if_port = media_tbl[dev->if_port].next;
+ } while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
+ if (dev->if_port == 8) { /* Go back to default. */
+ dev->if_port = vp->default_media;
+ if (vortex_debug > 1)
+ printk("%s: Media selection failing, using default %s port.\n",
+ dev->name, media_tbl[dev->if_port].name);
+ } else {
+ if (vortex_debug > 1)
+ printk("%s: Media selection failed, now trying %s port.\n",
+ dev->name, media_tbl[dev->if_port].name);
+ vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+ add_timer(&vp->timer);
+ }
+ outw((media_status & ~(Media_10TP|Media_SQE)) |
+ media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+
+ EL3WINDOW(3);
+ config.i = inl(ioaddr + Wn3_Config);
+ config.u.xcvr = dev->if_port;
+ outl(config.i, ioaddr + Wn3_Config);
+
+ outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+ }
+ EL3WINDOW(old_window);
+ } restore_flags(flags);
+ if (vortex_debug > 1)
+ printk("%s: Media selection timer finished, %s.\n",
+ dev->name, media_tbl[dev->if_port].name);
+
+#endif /* AUTOMEDIA*/
+ return;
}

static int
@@ -638,33 +810,49 @@
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;

- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
+ /* Part of the following code is inspired by code from Giuseppe Ciaccio,
+ ciaccio@disi.unige.it.
+ It works around a ?bug? in the 8K Vortex that only occurs on some
+ systems: the TxAvailable interrupt seems to be lost.
+ The ugly work-around is to busy-wait for room available in the Tx
+ buffer before deciding the transmitter is actually hung.
+ This busy-wait should never really occur, since the problem is that
+ there actually *is* room in the Tx FIFO.
+
+ This pointed out an optimization -- we can ignore dev->tbusy if
+ we actually have room for this packet.
+ */
+
+ if (inw(ioaddr + TxFree) > skb->len) /* We actually have free room. */
+ dev->tbusy = 0; /* Fake out the check below. */
+ else if (dev->tbusy) {
+ /* Transmitter timeout, serious problems. */
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 40)
+ int i;
+
+ if (tickssofar < 2) /* We probably aren't empty. */
return 1;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
- vp->stats.tx_errors++;
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- {
- int i;
+ /* Wait a while to see if there really is room. */
+ for (i = WAIT_TX_AVAIL; i >= 0; i--)
+ if (inw(ioaddr + TxFree) > skb->len)
+ break;
+ if ( i < 0) {
+ if (tickssofar < TX_TIMEOUT)
+ return 1;
+ printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
- break;
+ if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ dev->trans_start = jiffies;
+ dev->tbusy = 0;
+ vp->stats.tx_errors++;
+ vp->stats.tx_dropped++;
+ return 0; /* Yes, silently *drop* the packet! */
}
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
dev->tbusy = 0;
- return 0;
- }
-
- if (skb == NULL || skb->len <= 0) {
- printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
- dev->name);
- dev_tint(dev);
- return 0;
}

/* Block a timer-based transmit from overlapping. This could better be
@@ -684,6 +872,7 @@
outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
outw(StartDMADown, ioaddr + EL3_CMD);
+ /* dev->tbusy will be cleared at the DMADone interrupt. */
} else {
/* ... and the packet rounded to a doubleword. */
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
@@ -736,22 +925,28 @@

/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs)
{
+#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */
+ struct device *dev = dev_id;
+#else
#ifdef USE_SHARED_IRQ
struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]);
#else
struct device *dev = (struct device *)(irq2dev_map[irq]);
#endif
+#endif
struct vortex_private *lp;
int ioaddr, status;
int latency;
int i = 0;

+#ifndef SA_SHIRQ
if (dev == NULL) {
printk ("vortex_interrupt(): irq %d for unknown device.\n", irq);
return;
}
+#endif

if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
@@ -774,7 +969,7 @@
if (donedidthis++ > 1) {
printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
dev->name, status, dev->start);
- free_irq(dev->irq, NULL);
+ FREE_IRQ(dev->irq, dev);
}
}

@@ -833,10 +1028,7 @@
/* Adapter failure requires Rx reset and reinit. */
outw(RxReset, ioaddr + EL3_CMD);
/* Set the Rx filter to the current state. */
- outw(SetRxFilter | RxStation | RxBroadcast
- | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)
- | (dev->flags & IFF_PROMISC ? RxProm : 0),
- ioaddr + EL3_CMD);
+ set_rx_mode(dev);
outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
}
@@ -890,17 +1082,23 @@
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;

- skb = dev_alloc_skb(pkt_len + 5);
+ skb = DEV_ALLOC_SKB(pkt_len + 5);
if (vortex_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
if (skb != NULL) {
skb->dev = dev;
+#if (LINUX_VERSION_CODE > VERSION(1,3,0))
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
/* 'skb_put()' points to the start of sk_buff data area. */
insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
(pkt_len + 3) >> 2);
skb->protocol = eth_type_trans(skb, dev);
+#else
+ skb->len = pkt_len;
+ /* 'skb->data' points to the start of sk_buff data area. */
+ insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2);
+#endif /* KERNEL_1_3_0 */
netif_rx(skb);
outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
/* Wait a limited time to go to next packet. */
@@ -927,6 +1125,7 @@
static int
vortex_close(struct device *dev)
{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;

dev->start = 0;
@@ -936,6 +1135,8 @@
printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));

+ del_timer(&vp->timer);
+
/* Turn off statistics ASAP. We update lp->stats below. */
outw(StatsDisable, ioaddr + EL3_CMD);

@@ -946,19 +1147,18 @@
if (dev->if_port == 3)
/* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD);
- else if (dev->if_port == 0) {
- /* Disable link beat and jabber, if_port may change ere next open(). */
- EL3WINDOW(4);
- outw(inw(ioaddr + Wn4_Media) & ~Media_TP, ioaddr + Wn4_Media);
- }

+#ifdef SA_SHIRQ
+ FREE_IRQ(dev->irq, dev);
+#else
#ifdef USE_SHARED_IRQ
free_shared_irq(dev->irq, dev);
#else
- free_irq(dev->irq, NULL);
+ FREE_IRQ(dev->irq, NULL);
/* Mmmm, we should disable all interrupt sources here. */
irq2dev_map[dev->irq] = 0;
#endif
+#endif

update_stats(ioaddr, dev);
#ifdef MODULE
@@ -1019,26 +1219,52 @@
return;
}

-/* There are two version of set_multicast_list() to support both v1.2 and
- v1.4 kernels. */
+/* This new version of set_rx_mode() supports v1.4 kernels.
+ The Vortex chip has no documented multicast filter, so the only
+ multicast setting is to receive all multicast frames. At least
+ the chip has a very clean way to set the mode, unlike many others. */
static void
-set_multicast_list(struct device *dev)
+set_rx_mode(struct device *dev)
{
short ioaddr = dev->base_addr;
+ short new_mode;

- if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
- outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
- if (vortex_debug > 3) {
- printk("%s: Setting Rx multicast mode, %d addresses.\n",
- dev->name, dev->mc_count);
- }
- } else if (dev->flags & IFF_PROMISC) {
- outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
- ioaddr + EL3_CMD);
- } else
- outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+ if (dev->flags & IFF_PROMISC) {
+ if (vortex_debug > 3)
+ printk("%s: Setting promiscuous mode.\n", dev->name);
+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
+ } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
+ } else
+ new_mode = SetRxFilter | RxStation | RxBroadcast;
+
+ outw(new_mode, ioaddr + EL3_CMD);
}
+#ifndef NEW_MULTICAST
+/*
+ The old interface to set the Rx mode:
+ 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;
+ short new_mode;
+
+ if (num_addrs > 0) {
+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
+ } else if (num_addrs < 0) {
+ new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
+ } else
+ new_mode = SetRxFilter | RxStation | RxBroadcast;

+ outw(new_mode, ioaddr + EL3_CMD);
+}
+#endif

#ifdef MODULE
void
@@ -1050,6 +1276,7 @@
while (root_vortex_dev) {
next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
unregister_netdev(root_vortex_dev);
+ outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
release_region(root_vortex_dev->base_addr, VORTEX_TOTAL_SIZE);
kfree(root_vortex_dev);
root_vortex_dev = next_dev;
@@ -1059,7 +1286,7 @@

/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o 3c59x.o"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o"
* c-indent-level: 4
* tab-width: 4
* End:
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/include/linux/baycom.h linux/include/linux/baycom.h
--- linux.vanilla/include/linux/baycom.h Sun Jun 9 13:11:45 1996
+++ linux/include/linux/baycom.h Sun Jul 7 14:43:46 1996
@@ -8,6 +8,7 @@
#define _BAYCOM_H

#include <linux/ioctl.h>
+#undef BAYCOM_DEBUG

/* -------------------------------------------------------------------- */

@@ -55,7 +56,7 @@
/*
* use bottom halves? (HDLC processing done with interrupts on or off)
*/
-#define BAYCOM_USE_BH
+#define CONFIG_BAYCOM_USE_BH

/*
* modem types
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/kernel/ksyms.c linux/kernel/ksyms.c
--- linux.vanilla/kernel/ksyms.c Sun Jun 9 13:11:38 1996
+++ linux/kernel/ksyms.c Sun Jul 7 14:43:34 1996
@@ -333,6 +333,7 @@
X(insert_inode_hash),
X(event),
X(__down),
+ X(securelevel),
/* all busmice */
X(add_mouse_randomness),
X(fasync_helper),
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/net/Config.in linux/net/Config.in
--- linux.vanilla/net/Config.in Sun Jun 9 13:12:06 1996
+++ linux/net/Config.in Sun Jul 7 14:44:14 1996
@@ -20,9 +20,9 @@
bool 'AX.25 over Ethernet' CONFIG_BPQETHER
bool 'Amateur Radio NET/ROM' CONFIG_NETROM
fi
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-# bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+fi
bool 'Kernel/User network link driver' CONFIG_NETLINK
if [ "$CONFIG_NETLINK" = "y" ]; then
bool 'Routing messages' CONFIG_RTNETLINK
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/net/bridge/br.c linux/net/bridge/br.c
--- linux.vanilla/net/bridge/br.c Sun Jun 9 13:12:06 1996
+++ linux/net/bridge/br.c Sun Jul 7 14:44:14 1996
@@ -1052,6 +1052,7 @@
int br_receive_frame(struct sk_buff *skb) /* 3.5 */
{
int port;
+ int i;

if (br_stats.flags & BR_DEBUG)
printk("br_receive_frame: ");
@@ -1130,6 +1131,8 @@
port_info[port].dev->dev_addr,
ETH_ALEN) == 0)
{
+ /* Packet is for us */
+ skb->pkt_type = PACKET_HOST;
return(0); /* pass frame up our stack (this will */
/* happen in net_bh() in dev.c) */
}
@@ -1159,6 +1162,13 @@
printk(KERN_CRIT "br_tx_frame: no skb!\n");
return(0);
}
+
+ if (!skb->dev)
+ {
+ printk(KERN_CRIT "br_tx_frame: no dev!\n");
+ return(0);
+ }
+
/* check for loopback */
if (skb->dev->flags & IFF_LOOPBACK)
return(0);
@@ -1289,7 +1299,7 @@
/*
* Send flood and drop.
*/
- if (!f | !(f->flags & FDB_ENT_VALID)) {
+ if (!f || !(f->flags & FDB_ENT_VALID)) {
/* not found; flood all ports */
br_flood(skb, port);
return(br_dev_drop(skb));
@@ -1354,9 +1364,15 @@
if (port_info[i].state == Forwarding)
{
nskb = skb_clone(skb, GFP_ATOMIC);
+ if(nskb==NULL)
+ continue;
/* mark that's we've been here... */
nskb->pkt_bridged = IS_BRIDGED;
- nskb->arp = skb->arp;
+ /* Send to each port in turn */
+ nskb->dev= port_info[i].dev;
+ /* To get here we must have done ARP already,
+ or have a received valid MAC header */
+ nskb->arp = 1;

/* printk("Flood to port %d\n",i);*/
nskb->h.raw = nskb->data + ETH_HLEN;
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux.vanilla/net/ipv4/af_inet.c Sat Jul 6 00:37:30 1996
+++ linux/net/ipv4/af_inet.c Sun Jul 7 14:44:08 1996
@@ -692,7 +692,6 @@
sk->timer.function = &net_timer;
skb_queue_head_init(&sk->back_log);
sock->data =(void *) sk;
- sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
sk->ip_ttl=ip_statistics.IpDefaultTTL;
if(sk->type==SOCK_RAW && protocol==IPPROTO_RAW)
sk->ip_hdrincl=1;
diff --unified --recursive --exclude-from exclude --new-file linux.vanilla/net/ipv4/arp.c linux/net/ipv4/arp.c
--- linux.vanilla/net/ipv4/arp.c Sun Jun 9 13:11:59 1996
+++ linux/net/ipv4/arp.c Sun Jul 7 14:44:08 1996
@@ -58,6 +58,8 @@
* Jonathan Layes : Added arpd support through kerneld
* message queue (960314)
* Mike Shaver : /proc/sys/net/ipv4/arp_* support
+ * Stuart Cheshire : Metricom and grat arp fixes
+ * *** FOR 2.1 clean this up ***
*/

/* RFC1122 Status:
@@ -1931,18 +1933,10 @@
else
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);

-/*
- * Handle gratuitous arp.
- */
- arp_fast_lock();
- arp_update(sip, sha, dev, 0, NULL, 1);
- arp_unlock();
- kfree_skb(skb, FREE_READ);
- return 0;
}

arp_fast_lock();
- arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR);
+ arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR && dev->type != ARPHRD_METRICOM);
arp_unlock();
kfree_skb(skb, FREE_READ);
return 0;
@@ -1994,7 +1988,7 @@
}
else
{
- if (ip_chk_addr(ip))
+ if (ip_chk_addr(ip) && dev->type != ARPHRD_METRICOM)
return -EINVAL;
if (!dev)
{