## Automatically generated incremental diff
## From:   linux-2.2.13-pre6
## To:     linux-2.2.13-pre7
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.2.13-pre6/arch/i386/kernel/setup.c linux-2.2.13-pre7/arch/i386/kernel/setup.c
--- linux-2.2.13-pre6/arch/i386/kernel/setup.c	1999-08-25 17:29:46.000000000 -0700
+++ linux-2.2.13-pre7/arch/i386/kernel/setup.c	2003-08-15 15:07:39.000000000 -0700
@@ -52,6 +52,7 @@
 #include <asm/smp.h>
 #include <asm/cobalt.h>
 #include <asm/msr.h>
+#include <asm/dma.h>
 
 /*
  * Machine setup..
@@ -631,6 +632,16 @@
 			c->x86_model = (dir1 & 0x20) ? 1 : 2;
 			c->x86_capability&=~X86_FEATURE_TSC;
 		}
+#ifdef CONFIG_PCI
+                /* It isnt really a PCI quirk directly, but the cure is the
+       	           same. The MediaGX has deep magic SMM stuff that handles the
+                   SB emulation. It thows away the fifo on disable_dma() which
+                   is wrong and ruins the audio. */
+
+		printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bug.\n");
+                isa_dma_bridge_buggy = 1;
+                  	                                                                     	        
+#endif
 		break;
 
         case 5: /* 6x86MX/M II */
diff -urN linux-2.2.13-pre6/Documentation/Configure.help linux-2.2.13-pre7/Documentation/Configure.help
--- linux-2.2.13-pre6/Documentation/Configure.help	2003-08-15 15:07:39.000000000 -0700
+++ linux-2.2.13-pre7/Documentation/Configure.help	2003-08-15 15:07:39.000000000 -0700
@@ -5515,6 +5515,18 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
   
+SBNI Leased Line Adapters
+CONFIG_SBNI
+  This is a driver for ISA SBNI12-xx cards that is a low cost
+  alternative to leased line modems. Say Y if you want to insert
+  driver into kernel or say M to compile driver as a module. 
+  
+  You can find more information and last versions of drivers and 
+  utilities at http://www.granch.ru. If you have any question you
+  can mail to sbni@granch.ru.
+  
+  Say N if unsure.
+  
 WAN Drivers
 CONFIG_WAN_DRIVERS
   Say Y to this option if your Linux box contains a WAN card and you
diff -urN linux-2.2.13-pre6/drivers/net/Config.in linux-2.2.13-pre7/drivers/net/Config.in
--- linux-2.2.13-pre6/drivers/net/Config.in	1999-08-25 17:29:48.000000000 -0700
+++ linux-2.2.13-pre7/drivers/net/Config.in	2003-08-15 15:07:39.000000000 -0700
@@ -298,3 +298,4 @@
     dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
 fi
 fi
+tristate 'SBNI12-xx support' CONFIG_SBNI
diff -urN linux-2.2.13-pre6/drivers/net/eepro100.c linux-2.2.13-pre7/drivers/net/eepro100.c
--- linux-2.2.13-pre6/drivers/net/eepro100.c	1999-08-09 12:04:39.000000000 -0700
+++ linux-2.2.13-pre7/drivers/net/eepro100.c	2003-08-15 15:07:39.000000000 -0700
@@ -459,7 +459,7 @@
 			irq = pdev->irq;
 		}
 		/* Remove I/O space marker in bit 0. */
-		ioaddr &= ~3;
+		ioaddr &= ~3UL;
 		if (speedo_debug > 2)
 			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
 				   ioaddr, irq);
@@ -685,7 +685,7 @@
 static int read_eeprom(long ioaddr, int location, int addr_len)
 {
 	unsigned short retval = 0;
-	int ee_addr = ioaddr + SCBeeprom;
+	long ee_addr = ioaddr + SCBeeprom;
 	int read_cmd = location | EE_READ_CMD;
 	int i;
 
@@ -802,8 +802,8 @@
 		u16 *setup_frm = (u16 *)&(sp->tx_ring[0].tx_desc_addr);
 
 		/* Avoid a bug(?!) here by marking the command already completed. */
-		sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000;
-		sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1]));
+		sp->tx_ring[0].status = cpu_to_le32(((CmdSuspend | CmdIASetup) << 16) | 0xa000);
+		sp->tx_ring[0].link = cpu_to_le32(virt_to_bus(&(sp->tx_ring[1])));
 		*setup_frm++ = eaddrs[0];
 		*setup_frm++ = eaddrs[1];
 		*setup_frm++ = eaddrs[2];
@@ -917,22 +917,22 @@
 		sp->rx_ringp[i] = rxf;
 		skb_reserve(skb, sizeof(struct RxFD));
 		if (last_rxf)
-			last_rxf->link = virt_to_bus(rxf);
+			last_rxf->link = cpu_to_le32(virt_to_bus(rxf));
 		last_rxf = rxf;
-		rxf->status = 0x00000001; 			/* '1' is flag value only. */
+		rxf->status = cpu_to_le32(0x00000001); 			/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
 		/* This field unused by i82557, we use it as a consistency check. */
 #ifdef final_version
 		rxf->rx_buf_addr = 0xffffffff;
 #else
-		rxf->rx_buf_addr = virt_to_bus(skb->tail);
+		rxf->rx_buf_addr = cpu_to_le32(virt_to_bus(skb->tail));
 #endif
 		rxf->count = 0;
-		rxf->size = PKT_BUF_SZ;
+		rxf->size = cpu_to_le16(PKT_BUF_SZ);
 	}
 	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
-	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */
+	last_rxf->status = cpu_to_le32(0xC0000002); 			/* '2' is flag value only. */
 	sp->last_rxf = last_rxf;
 }
 
@@ -945,7 +945,7 @@
 		   " %4.4x at %d/%d command %8.8x.\n",
 		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd),
 		   sp->dirty_tx, sp->cur_tx,
-		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);
+		   le32_to_cpu(sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status));
 	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
 		printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			   dev->name);
@@ -1010,21 +1010,21 @@
 		sp->tx_skbuff[entry] = skb;
 		/* Todo: be a little more clever about setting the interrupt bit. */
 		sp->tx_ring[entry].status =
-			(CmdSuspend | CmdTx | CmdTxFlex) << 16;
+			cpu_to_le32((CmdSuspend | CmdTx | CmdTxFlex) << 16);
 		sp->tx_ring[entry].link =
-		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+		  cpu_to_le32(virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
 		sp->tx_ring[entry].tx_desc_addr =
-		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
+		  cpu_to_le32(virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0));
 		/* The data region is always in one buffer descriptor, Tx FIFO
 		   threshold of 256. */
-		sp->tx_ring[entry].count = 0x01208000;
-		sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
-		sp->tx_ring[entry].tx_buf_size0 = skb->len;
+		sp->tx_ring[entry].count = cpu_to_le32(0x01208000);
+		sp->tx_ring[entry].tx_buf_addr0 = cpu_to_le32(virt_to_bus(skb->data));
+		sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len);
 		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
 		   than half full.  Argument against: we should be receiving packets
 		   and scavenging the queue.  Argument for: if so, it shouldn't
 		   matter. */
-		sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
+		sp->last_cmd->command &= cpu_to_le16(~(CmdSuspend | CmdIntr));
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 
 		/* Trigger the command unit resume. */
@@ -1102,7 +1102,7 @@
 
 			while (sp->cur_tx - dirty_tx > 0) {
 				int entry = dirty_tx % TX_RING_SIZE;
-				int status = sp->tx_ring[entry].status;
+				int status = le32_to_cpu(sp->tx_ring[entry].status);
 
 				if (speedo_debug > 5)
 					printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",
@@ -1115,7 +1115,7 @@
 					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; /* Count transmitted bytes */
 					dev_free_skb(sp->tx_skbuff[entry]);
 					sp->tx_skbuff[entry] = 0;
-				} else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)
+				} else if ((status&0x70000) == CmdNOp << 16)
 					sp->mc_setup_busy = 0;
 				dirty_tx++;
 			}
@@ -1170,13 +1170,13 @@
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while (sp->rx_ringp[entry] != NULL &&
-		   (status = sp->rx_ringp[entry]->status) & RxComplete) {
+		   (status = le32_to_cpu(sp->rx_ringp[entry]->status)) & RxComplete) {
 
 		if (--rx_work_limit < 0)
 			break;
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
-				   sp->rx_ringp[entry]->count & 0x3fff);
+				   le16_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff);
 		if ((status & (RxErrTooBig|RxOK)) != RxOK) {
 			if (status & RxErrTooBig)
 				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
@@ -1189,7 +1189,7 @@
 					   dev->name, status);
 			}
 		} else {
-			int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
+			int pkt_len = le16_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff;
 			struct sk_buff *skb;
 
 			/* Check if the packet is long enough to just accept without
@@ -1202,12 +1202,12 @@
 #if 1 || USE_IP_CSUM
 				/* Packet is in one chunk -- we can copy + cksum. */
 				eth_copy_and_sum(skb,
-								 bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+								 bus_to_virt(le32_to_cpu(sp->rx_ringp[entry]->rx_buf_addr)),
 								 pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
 				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
+					   bus_to_virt(le32_to_cpu(sp->rx_ringp[entry]->rx_buf_addr)), pkt_len);
 #endif
 			} else {
 				void *temp;
@@ -1220,11 +1220,11 @@
 				}
 				sp->rx_skbuff[entry] = NULL;
 				temp = skb_put(skb, pkt_len);
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+				if (bus_to_virt(le32_to_cpu(sp->rx_ringp[entry]->rx_buf_addr)) != temp)
 					printk(KERN_ERR "%s: Rx consistency error -- the skbuff "
 						   "addresses do not match in speedo_rx: %p vs. %p "
 						   "/ %p.\n", dev->name,
-						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+						   bus_to_virt(le32_to_cpu(sp->rx_ringp[entry]->rx_buf_addr)),
 						   skb->head, temp);
 				sp->rx_ringp[entry] = NULL;
 			}
@@ -1252,16 +1252,16 @@
 			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
 			skb->dev = dev;
 			skb_reserve(skb, sizeof(struct RxFD));
-			rxf->rx_buf_addr = virt_to_bus(skb->tail);
+			rxf->rx_buf_addr = cpu_to_le32(virt_to_bus(skb->tail));
 		} else {
 			rxf = sp->rx_ringp[entry];
 		}
-		rxf->status = 0xC0000001; 	/* '1' for driver use only. */
+		rxf->status = cpu_to_le32(0xC0000001); 	/* '1' for driver use only. */
 		rxf->link = 0;			/* None yet. */
 		rxf->count = 0;
-		rxf->size = PKT_BUF_SZ;
-		sp->last_rxf->link = virt_to_bus(rxf);
-		sp->last_rxf->status &= ~0xC0000000;
+		rxf->size = cpu_to_le16(PKT_BUF_SZ);
+		sp->last_rxf->link = cpu_to_le32(virt_to_bus(rxf));
+		sp->last_rxf->status &= cpu_to_le32(~0xC0000000);
 		sp->last_rxf = rxf;
 	}
 
@@ -1321,7 +1321,7 @@
 
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(KERN_DEBUG "  Rx ring entry %d  %8.8x.\n",
-				   i, (int)sp->rx_ringp[i]->status);
+				   i, (int)le32_to_cpu(sp->rx_ringp[i]->status));
 
 		for (i = 0; i < 5; i++)
 			printk(KERN_DEBUG "  PHY index %d register %d is %4.4x.\n",
@@ -1353,18 +1353,18 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (sp->lstats.done_marker == 0xA007) {	/* Previous dump finished */
-		sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
-		sp->stats.tx_window_errors += sp->lstats.tx_late_colls;
-		sp->stats.tx_fifo_errors += sp->lstats.tx_underruns;
-		sp->stats.tx_fifo_errors += sp->lstats.tx_lost_carrier;
-		/*sp->stats.tx_deferred += sp->lstats.tx_deferred;*/
-		sp->stats.collisions += sp->lstats.tx_total_colls;
-		sp->stats.rx_crc_errors += sp->lstats.rx_crc_errs;
-		sp->stats.rx_frame_errors += sp->lstats.rx_align_errs;
-		sp->stats.rx_over_errors += sp->lstats.rx_resource_errs;
-		sp->stats.rx_fifo_errors += sp->lstats.rx_overrun_errs;
-		sp->stats.rx_length_errors += sp->lstats.rx_runt_errs;
+	if (le32_to_cpu(sp->lstats.done_marker) == 0xA007) {	/* Previous dump finished */
+		sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats.tx_coll16_errs);
+		sp->stats.tx_window_errors += le32_to_cpu(sp->lstats.tx_late_colls);
+		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_underruns);
+		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_lost_carrier);
+		/*sp->stats.tx_deferred += le32_to_cpu(sp->lstats.tx_deferred);*/
+		sp->stats.collisions += le32_to_cpu(sp->lstats.tx_total_colls);
+		sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats.rx_crc_errs);
+		sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats.rx_align_errs);
+		sp->stats.rx_over_errors += le32_to_cpu(sp->lstats.rx_resource_errs);
+		sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs);
+		sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs);
 		sp->lstats.done_marker = 0x0000;
 		if (dev->start) {
 			wait_for_cmd_done(ioaddr + SCBCmd);
@@ -1440,9 +1440,9 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 
 		sp->tx_skbuff[entry] = 0;			/* Redundant. */
-		sp->tx_ring[entry].status = (CmdSuspend | CmdConfigure) << 16;
+		sp->tx_ring[entry].status = cpu_to_le32((CmdSuspend | CmdConfigure) << 16);
 		sp->tx_ring[entry].link =
-			virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+			cpu_to_le32(virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]));
 		config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr;
 		/* Construct a full CmdConfig frame. */
 		memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd));
@@ -1457,7 +1457,7 @@
 			config_cmd_data[8] = 0;
 		}
 		/* Trigger the command unit resume. */
-		last_cmd->command &= ~CmdSuspend;
+		last_cmd->command &= cpu_to_le16(~CmdSuspend);
 
 		wait_for_cmd_done(ioaddr + SCBCmd);
 		outw(CU_RESUME, ioaddr + SCBCmd);
@@ -1477,12 +1477,12 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 
 		sp->tx_skbuff[entry] = 0;
-		sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
+		sp->tx_ring[entry].status = cpu_to_le32((CmdSuspend | CmdMulticastList) << 16);
 		sp->tx_ring[entry].link =
-			virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]);
+			cpu_to_le32(virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]));
 		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
 		setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
-		*setup_params++ = dev->mc_count*6;
+		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
@@ -1492,7 +1492,7 @@
 			*setup_params++ = *eaddrs++;
 		}
 
-		last_cmd->command &= ~CmdSuspend;
+		last_cmd->command &= cpu_to_le16(~CmdSuspend);
 
 		/* Immediately trigger the command unit resume. */
 		wait_for_cmd_done(ioaddr + SCBCmd);
@@ -1533,10 +1533,10 @@
 				   "%d bytes.\n",
 				   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
 		mc_setup_frm->status = 0;
-		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
+		mc_setup_frm->command = cpu_to_le16(CmdSuspend | CmdIntr | CmdMulticastList);
 		/* Link set below. */
 		setup_params = (u16 *)&mc_setup_frm->params;
-		*setup_params++ = dev->mc_count*6;
+		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
@@ -1556,14 +1556,14 @@
 
 		/* Change the command to a NoOp, pointing to the CmdMulti command. */
 		sp->tx_skbuff[entry] = 0;
-		sp->tx_ring[entry].status = CmdNOp << 16;
-		sp->tx_ring[entry].link = virt_to_bus(mc_setup_frm);
+		sp->tx_ring[entry].status = cpu_to_le32(CmdNOp << 16);
+		sp->tx_ring[entry].link = cpu_to_le32(virt_to_bus(mc_setup_frm));
 
 		/* Set the link in the setup frame. */
 		mc_setup_frm->link =
-			virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE]));
+			cpu_to_le32(virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE])));
 
-		last_cmd->command &= ~CmdSuspend;
+		last_cmd->command &= cpu_to_le16(~CmdSuspend);
 
 		/* Immediately trigger the command unit resume. */
 		wait_for_cmd_done(ioaddr + SCBCmd);
diff -urN linux-2.2.13-pre6/drivers/net/Makefile linux-2.2.13-pre7/drivers/net/Makefile
--- linux-2.2.13-pre6/drivers/net/Makefile	1999-08-25 17:29:48.000000000 -0700
+++ linux-2.2.13-pre7/drivers/net/Makefile	2003-08-15 15:07:39.000000000 -0700
@@ -1147,6 +1147,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SBNI),y)
+L_OBJS += sbni.o
+else
+  ifeq ($(CONFIG_SBNI),m)
+  M_OBJS += sbni.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
diff -urN linux-2.2.13-pre6/drivers/net/sbni.c linux-2.2.13-pre7/drivers/net/sbni.c
--- linux-2.2.13-pre6/drivers/net/sbni.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.13-pre7/drivers/net/sbni.c	2003-08-15 15:07:39.000000000 -0700
@@ -0,0 +1,1533 @@
+/*
+ * Driver for Granch SBNI-12 leased line network adapters.
+ * 
+ * Copyright 1997 - 1999, Granch ltd.
+ * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ * 
+ *   // Whole developers team:
+ *   //   Yaroslav Polyakov (xenon@granch.ru)
+ *   //      - main developer of this version
+ *   //   Alexey Zverev (zverev@granch.ru)
+ *   //      - previous SBNI driver for linux
+ *   //   Alexey Chirkov (chirkov@granch.ru)
+ *   //      - all the hardware work and consulting
+ *   //   Max Khon (max@iclub.nsu.ru)
+ *   //      - first SBNI driver for linux
+ *   // --------------------------------------------
+ *   // also I thank: 
+ *   //   Max Krasnyansky (max@uznet.net)
+ *   //      - for bug hunting and many ideas
+ *   //   Alan Cox (Alan.Cox@linux.org)
+ *   //	     - for consulting in some hardcore questions
+ *   //   Donald Becker (becker@cesdis.gsfc.nasa.gov)
+ *   //      - for pretty nice skeleton 
+ * 
+ *   More info and useful utilities to work w/ SBNI you can find at 
+ *   http://www.granch.ru.
+ *
+ *  3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ *        - added pre-calculation for CRC, fixed bug with "len-2" frames, 
+ *        - removed outbound fragmentation (MTU=1000), written CRC-calculation 
+ *        - on asm, added work with hard_headers and now we have our own cache 
+ *        - for them, optionally supported word-interchange on some chipsets,
+ *        - something else I cant remember ;) 
+ * 
+ *  3.0.1 = just fixed some bugs (14 apr 1999).
+ * 	  - fixed statistical tx bug 
+ *        - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
+ * 	  - fixed source address bug.
+ *        - fixed permanent nirvana bug 
+ * 
+ *  3.1.0 = (Katyusha) (26 apr 1999)
+ *        - Added balancing feature
+ * 
+ *  3.1.1 = (Medea) (5 aug 1999)
+ *        - Fixed mac.raw bug
+ *	  - Thanks to tolix@olviko.ru and 
+ *        - to Barnaul Brewery, producers of my favorite beer "Medea".
+ *
+ *
+ */
+
+
+#undef GOODBUS16
+#define CRCASM
+#define KATYUSHA
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >=0x020200
+#define v22
+#endif
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/config.h>	/* for CONFIG_INET. do we need this?*/
+
+#include <net/arp.h>
+
+
+
+#ifdef v22
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#endif
+
+#include "sbni.h"
+
+
+static const char *version = 
+"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+
+int sbni_probe(struct device *dev);
+static int  sbni_probe1(struct device *dev, int ioaddr);
+static int  sbni_open(struct device *dev);
+static int  sbni_start_xmit(struct sk_buff *skb, struct device *dev);
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  sbni_close(struct device *dev);
+static void sbni_drop_tx_queue(struct device *dev);
+static struct enet_statistics *sbni_get_stats(struct device *dev);
+void card_start(struct device *dev);
+static inline unsigned short sbni_recv(struct device *dev);
+void change_level(struct device *dev);
+static inline void sbni_xmit(struct device *dev);
+static inline void sbni_get_packet(struct device* dev);
+static void sbni_watchdog(unsigned long arg);
+static void set_multicast_list(struct device *dev);
+static int sbni_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int sbni_set_mac_address(struct device *dev, void *addr);
+unsigned long calc_crc(char *mem, int len, unsigned initial);
+void sbni_nirvana(struct device *dev);
+static int sbni_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+		void *daddr, void *saddr, unsigned len);
+
+static int sbni_rebuild_header(struct sk_buff *skb);
+static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+
+static inline void sbni_outs(int port, void *data, int len);
+static inline void sbni_ins(int port, void *data, int len);
+
+
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static u_char timeout_rxl_tab[] = {
+  0x03, 0x05, 0x08, 0x0b
+};
+
+static u_char rxl_tab[] = {
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 
+  0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+/* A zero-terminated list of I/O addresses to be probed */
+static unsigned int netcard_portlist[] =  { 
+	0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250, 
+	0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254, 
+	0x264, 0x294, 0x2a4, 0x2b4, 0};
+
+static unsigned char magic_reply[] = {
+	0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+};
+
+static int def_baud = DEF_RATE;
+static int def_rxl = DEF_RXL_DELTA;
+static long def_mac = 0;
+
+
+/*
+ * CRC-32 stuff
+ */
+
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+/* CRC generator 0xEDB88320 */
+/* CRC remainder 0x2144DF1C */
+/* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
+
+static unsigned long crc32tab[] = {
+	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
+	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
+	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
+	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
+	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
+	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
+	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
+	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
+	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
+	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
+	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
+	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
+	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
+	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
+	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
+	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
+	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
+	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
+	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
+	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
+	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
+	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
+	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
+	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
+	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
+	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
+	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
+	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
+	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
+	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,	
+	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
+	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
+	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
+	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
+	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
+	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
+	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
+	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
+	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
+	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
+	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
+	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
+	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
+	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
+	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
+	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
+	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
+	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
+	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
+	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
+	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
+	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
+	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
+	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
+	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
+	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
+	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
+	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
+	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
+	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
+	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
+	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
+	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
+	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
+};
+
+static inline void sbni_outs(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+	outsw(port,data,len/2);
+	if(len & 1)
+		outb(((char*)data)[len - 1],port);
+#else
+	outsb(port,data,len);
+#endif
+}
+
+static inline void sbni_ins(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+	insw(port,data,len/2);
+	if(len & 1)
+		((char*)data)[len - 1] = inb(port);
+#else
+	insb(port,data,len);
+#endif
+}
+
+
+static int sbni_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+	   void *daddr, void *saddr, unsigned len)
+{
+	struct sbni_hard_header *hh = (struct sbni_hard_header *) 
+			skb_push(skb, sizeof(struct sbni_hard_header));
+  
+  
+	if(type!=ETH_P_802_3) 
+		hh->h_proto = htons(type);
+	else
+		hh->h_proto = htons(len);
+  
+	if(saddr)
+		memcpy(hh->h_source,saddr,dev->addr_len);
+	else
+		memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
+
+	if(daddr)
+	{
+		memcpy(hh->h_dest,daddr,dev->addr_len);
+		return dev->hard_header_len;
+	} 
+	return -dev->hard_header_len;
+}
+
+
+int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+	unsigned short type = hh->hh_type;
+	struct sbni_hard_header *sbni = (struct sbni_hard_header*)
+						(((u8*)hh->hh_data) - 8);
+	struct device *dev = neigh->dev;
+  
+  
+	if (type == __constant_htons(ETH_P_802_3))
+		return -1;
+  
+	sbni->h_proto = type;
+	memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
+	return 0;
+}
+
+static int sbni_rebuild_header(struct sk_buff *skb)
+{
+	struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
+	/*
+	 *	Only ARP/IP is currently supported
+	 */
+
+	/*
+	 *	Try to get ARP to resolve the header.
+	 */
+  
+#ifdef CONFIG_INET
+  	return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;  
+#else
+	return 0;	
+#endif	
+}
+
+static void sbni_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+	memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+}
+
+
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry sbni_drv = {
+	"sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist 
+};
+
+#else
+
+int __init sbni_probe(struct device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+	
+	DP( printk("%s: sbni_probe\n", dev->name); )
+
+	if(base_addr > 0x1ff)	/* Check a single specified location. */
+		return sbni_probe1(dev, base_addr);
+	else if(base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+	for(i = 0; (base_addr = netcard_portlist[i]); i++)
+	{ 
+		if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
+		{
+			/* Lock this address, or later we'll try it again */
+			netcard_portlist[i] = 1;
+			if(sbni_probe1(dev, base_addr) == 0)
+				return 0;
+		}
+	}
+	return ENODEV;
+}
+
+#endif /* have devlist*/
+
+/*
+ *	The actual probe. 
+ */
+
+/*
+	Valid combinations in CSR0 (for probing):
+
+	VALID_DECODER	0000,0011,1011,1010
+
+				    	; 0   ; -
+				TR_REQ	; 1   ; +
+			TR_RDY	    	; 2   ; -
+			TR_RDY	TR_REQ	; 3   ; +
+		BU_EMP		    	; 4   ; +
+		BU_EMP	     	TR_REQ	; 5   ; +
+		BU_EMP	TR_RDY	    	; 6   ; -
+		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
+	RC_RDY 		     		; 8   ; +
+	RC_RDY			TR_REQ	; 9   ; +
+	RC_RDY		TR_RDY		; 10  ; -
+	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
+	RC_RDY	BU_EMP			; 12  ; -
+	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
+	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
+	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
+*/
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+static int __init sbni_probe1(struct device *dev, int ioaddr)
+
+{
+	int autoirq = 0;
+	int bad_card = 0;
+	unsigned char csr0;
+	struct net_local* lp;
+	static int version_printed = 0;
+
+	DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
+       
+	if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
+		return -ENODEV;
+	if(version_printed++ == 0)
+		printk(version);
+     
+	/* check for valid combination in CSR0 */
+	csr0 = inb(ioaddr + CSR0);
+	if(csr0 == 0xff || csr0 == 0)
+		bad_card = 1;
+	else 
+	{
+		csr0 &= ~EN_INT;
+		if(csr0 & BU_EMP)
+			csr0 |= EN_INT;
+		if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
+			bad_card = 1;
+	}
+
+	if(bad_card)
+		return ENODEV;
+	else
+		outb(0, ioaddr + CSR0); 
+	if(dev->irq < 2)
+	{
+		DP( printk("%s: autoprobing\n", dev->name); );
+		autoirq_setup(5);
+		outb(EN_INT | TR_REQ, ioaddr + CSR0);
+		outb(PR_RES, ioaddr + CSR1);
+		autoirq = autoirq_report(5);
+
+		if(autoirq == 0)
+		{
+			printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
+			return EAGAIN;
+		}
+	}
+	/* clear FIFO buffer */
+	outb(0, ioaddr + CSR0);
+   
+	if(autoirq)
+		dev->irq = autoirq;
+
+	{
+   		int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
+		if (irqval) 
+		{
+			printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
+			return EAGAIN;
+		}
+	}
+     
+	/* 
+	 *	Initialize the device structure. 
+	 */
+
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if(dev->priv == NULL)
+	{
+		DP( printk("%s: cannot allocate memory\n", dev->name); )
+		return -ENOMEM;
+	}
+   
+	memset(dev->priv, 0, sizeof(struct net_local));
+	dev->base_addr = ioaddr;
+	request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
+
+	/* 
+	 * generate Ethernet address (0x00ff01xxxxxx)
+	 */
+
+	*(u16*)dev->dev_addr = htons(0x00ff);
+	*(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
+   
+	lp = dev->priv;
+	if(def_rxl < 0)
+	{
+		/* autodetect receive level */
+		lp->rxl_curr = 0xf;
+		lp->rxl_delta = -1;
+	} else {
+		/* fixed receive level */
+		lp->rxl_curr = def_rxl & 0xf;
+		lp->rxl_delta = 0;
+	}
+	lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+	lp->csr1.rate = def_baud & 3;
+	lp->frame_len = DEF_FRAME_LEN;
+	printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", 
+		dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
+	       *(unsigned char*)(dev->dev_addr+3),
+	       *(unsigned char*)(dev->dev_addr+4),
+	       *(unsigned char*)(dev->dev_addr+5)
+	);
+
+	printk("%s: receive level: ", dev->name);
+	if(lp->rxl_delta == 0)
+		printk ("%#1x (fixed)", lp->rxl_curr); 
+	else
+		printk ("autodetect");
+	printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
+   
+	/*
+	 *	The SBNI-specific entries in the device structure. 
+	 */
+	dev->open = &sbni_open;
+	dev->hard_start_xmit = &sbni_start_xmit;
+	dev->stop = &sbni_close;
+	dev->get_stats = &sbni_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &sbni_set_mac_address;
+	dev->do_ioctl = &sbni_ioctl;
+   
+	/*
+	 *	Setup the generic properties 
+	 */
+
+	ether_setup(dev);
+   
+	dev->hard_header = sbni_header;
+	dev->hard_header_len = sizeof(struct sbni_hard_header);
+	dev->rebuild_header=sbni_rebuild_header;
+	dev->mtu = DEF_FRAME_LEN;
+
+	dev->hard_header_cache = sbni_header_cache;
+	dev->header_cache_update = sbni_header_cache_update;
+  
+	lp->m=dev;
+	lp->me=dev;
+	lp->next_lp=NULL;
+  
+	return 0;
+}
+
+/*
+ *	Open/initialize the board. 
+ */
+
+static int sbni_open(struct device *dev)
+{
+	struct net_local* lp = (struct net_local*)dev->priv;
+	struct timer_list* watchdog = &lp->watchdog;
+   
+      
+	DP( printk("%s: sbni_open\n", dev->name); )
+     
+	cli();
+	lp->currframe = NULL;
+   
+	card_start(dev);
+	dev->start = 1;
+	/* set timer  watchdog */
+	init_timer(watchdog);
+	watchdog->expires = jiffies + SBNI_TIMEOUT;
+	watchdog->data = (unsigned long)dev;
+	watchdog->function = sbni_watchdog;
+	add_timer(watchdog);
+	DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
+   
+	sti();
+   
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sbni_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct net_local* lp = (struct net_local*) dev->priv;
+	struct timer_list* watchdog = &lp->watchdog;
+
+   
+	DP( printk("%s: sbni_close\n", dev->name); )
+
+	cli();
+   
+	sbni_drop_tx_queue(dev);	
+   
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	del_timer(watchdog);
+
+	outb(0, ioaddr + CSR0);
+	sti();
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int sbni_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+	struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
+  
+#ifdef KATYUSHA   
+	struct net_local *nl;
+	int stop;
+#endif
+  
+	DP( printk("%s: sbni_start_xmit In \n", dev->name); );
+  
+  
+	if(lp->me != dev)
+		panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
+  
+	if(dev->interrupt)
+	{
+		DP( printk("sbni_xmit_start: interrupt\n"); )
+		/* May be unloading, don't stamp on */	
+		return 1;	/* the packet buffer this time      */
+	}
+  
+	hh->number = 1;
+	hh->reserv = 0;
+  
+	hh->packetlen =  (skb->len - sizeof (unsigned short) - 
+			(sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) 
+			| PACKET_SEND_OK | PACKET_FIRST_FRAME;
+  
+	/* we should use hairy method to calculate crc because of extra bytes are 
+	  livin between hard header and data*/
+	hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
+	hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
+		       skb->len - sizeof(struct sbni_hard_header),
+		       hh->crc);
+  
+#ifdef KATYUSHA
+	/* looking for first idle device */
+	for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
+	{
+		if((!nl->currframe) && (nl->carrier)) /* if idle */
+		{
+			skb->dev = lp->me;
+			nl->currframe = skb;
+			/* set request for transmit */
+			outb(inb(nl->me->base_addr + CSR0) | TR_REQ, 
+				nl->me->base_addr + CSR0);
+			stop=1;
+		}
+	}
+  
+	if(!stop) /* we havent found any idle.*/
+	{
+		skb_queue_tail(&lp->queue,skb);
+		outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+      
+	}		
+#else 
+	if (lp->currframe || 1)
+	{
+		skb_queue_tail(&lp->queue,skb);
+		  
+	}
+	else
+	{
+		lp->currframe = skb;
+	}
+	/* set request for transmit */
+	outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+#endif
+	return 0;
+}
+
+void card_start(struct device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+   
+	DP( printk("%s: card_start\n",dev->name); )
+	lp->wait_frame_number = 0;
+	lp->inppos = lp->outpos = 0;
+	lp->eth_trans_buffer_len = 0;
+	lp->tr_err = TR_ERROR_COUNT;
+	lp->last_receive_OK = FALSE;
+	lp->tr_resend = FALSE;
+	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	lp->timeout_rxl = 0;
+
+	lp->waitack=0;
+	skb_queue_head_init(&lp->queue);
+	sbni_drop_tx_queue(dev);
+	dev->tbusy = 0;
+   
+	dev->interrupt = 0;
+	/* Reset the card and set start parameters */
+	outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
+	outb(EN_INT, dev->base_addr + CSR0);
+}
+
+void sbni_nirvana(struct device *dev)
+{
+	sbni_outs(dev->base_addr+DAT,magic_reply,9);
+}
+
+static inline unsigned short sbni_recv(struct device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+	unsigned long crc;
+	unsigned short packetlen = 0;
+	unsigned short packetinf, packetfirst, receiveframeresend;
+	unsigned char current_frame;
+	unsigned int i, j;
+	unsigned char delme,rcv_res=RCV_WR;
+  
+	lp->in_stats.all_rx_number++;
+  
+	if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
+	{
+		crc = CRC32_INITIAL;
+		*(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
+		crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
+		*(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
+		crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
+		packetinf = packetlen & PACKET_INF_MASK;
+		packetfirst = packetlen & PACKET_FIRST_FRAME;
+		receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
+		packetlen = packetlen & PACKET_LEN_MASK;
+    
+    
+		if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
+		{
+			/* read frame number */
+			current_frame = inb(dev->base_addr + DAT);
+			crc = CRC32(current_frame, crc);
+			/* read HandShake counter */
+			lp->HSCounter = inb(dev->base_addr + DAT);
+			crc = CRC32(lp->HSCounter, crc);
+			packetlen -= 2;
+      
+			sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
+      
+			for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
+			{
+				crc = CRC32(lp->eth_rcv_buffer[i], crc);
+			}
+      
+			if(crc == CRC32_REMAINDER)
+			{
+				if(packetlen > 4) 
+					rcv_res=RCV_OK;
+				else if(packetlen == 4) 
+					rcv_res=RCV_NO;
+      		
+				if(lp->waitack && packetinf == PACKET_RESEND)
+					lp->in_stats.resend_tx_number++;
+	
+	
+				switch(packetinf)
+				{
+				case PACKET_SEND_OK:
+				{
+					lp->tr_err = TR_ERROR_COUNT;
+					lp->tr_resend = FALSE;
+					/* if(lp->trans_frame_number){ */
+					lp->outpos += lp->realframelen;
+	      
+					/* SendComplete
+					 * not supported
+					 */
+					DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
+					/*
+					 *	We sucessfully sent current packet
+					 */
+	      
+					if(lp->waitack)
+					{
+						dev_kfree_skb(lp->currframe);
+						lp->stats.tx_packets++;
+#ifdef KATYUSHA
+						lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+#else
+						lp->currframe=skb_dequeue(&lp->queue);
+#endif		       
+						lp->in_stats.all_tx_number++;
+						lp->waitack=0;
+					}
+	      
+					/*
+	      				 * reset output active flags
+					 */
+					dev->tbusy = 0;
+					mark_bh(NET_BH);
+					/*} if */
+				}
+				case PACKET_RESEND:
+				{
+					if(lp->tr_err) /**/
+						lp->tr_err--;
+					if(lp->ok_curr < 0xffffffff)
+						lp->ok_curr++;
+					if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
+					{
+						if(packetfirst)
+						{
+							if(lp->wait_frame_number)
+							{
+								for(i = lp->inppos, j = 0; 
+									i < (lp->inppos + packetlen - 4); 
+									i++, j++)
+								lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
+							}
+							lp->wait_frame_number = current_frame;
+							lp->inppos = 0;
+						}
+						if(current_frame == lp->wait_frame_number)
+						{
+							lp->inppos += (packetlen - 4);
+							if(lp->wait_frame_number == 1)
+		  					{
+								sbni_get_packet(dev);
+								lp->inppos = 0;
+							}
+							lp->wait_frame_number--;
+						}
+					}
+					lp->last_receive_OK = TRUE;
+					break;
+				}
+				default:
+					break;
+				}
+			}
+			else 
+			{
+				DP(printk("%s: bad CRC32\n",dev->name));
+				change_level(dev);
+			}
+		}
+		else 
+		{
+			DP(printk("%s: bad len\n ",dev->name));
+			change_level(dev);
+			lp->stats.rx_over_errors++;
+		}
+	}
+	else 
+	{
+		DP(printk("%s: bad sig\n",dev->name));
+		change_level(dev);
+	}
+	outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
+	return (rcv_res);
+}
+
+void change_level(struct device *dev)
+{
+	struct net_local *lp = (struct net_local*)dev->priv;
+
+	lp->in_stats.bad_rx_number++;
+	lp->stats.tx_errors++;
+	if(lp->rxl_delta == 0)
+		return;
+	/* 
+	 * set new rxl_delta value
+	 */
+	if(lp->rxl_curr == 0)
+		lp->rxl_delta = 1;
+	else if(lp->rxl_curr == 0xf)
+		lp->rxl_delta = -1;
+	else if(lp->ok_curr < lp->ok_prev)
+		lp->rxl_delta = -lp->rxl_delta;
+	/*
+	 * set new rxl_curr value
+	 */
+	lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
+	outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
+  
+  
+	/*
+	 * update ok_prev/ok_curr counters
+	 */
+	lp->ok_prev = lp->ok_curr;
+	lp->ok_curr = 0;
+
+	DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
+		   dev->name,lp->rxl_curr, lp->rxl_delta); )
+     
+}
+
+static inline void sbni_xmit(struct device *dev)
+{
+	struct net_local* lp = (struct net_local *)dev->priv;
+	struct sk_buff *skb;
+ 
+	skb=lp->currframe;
+  
+	DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
+	  
+	/* push signature*/  
+	outb(SBNI_SIG, dev->base_addr + DAT);
+	
+	/* push frame w/o crc [HAiRY]*/
+	sbni_outs(dev->base_addr + DAT,
+	      &((struct sbni_hard_header *)(skb->data))->packetlen,
+	      SBNI_HH_SZ - sizeof(unsigned)); 
+	
+	sbni_outs(dev->base_addr + DAT,
+	      skb->data + sizeof(struct sbni_hard_header),
+	      skb->len - sizeof(struct sbni_hard_header)); /* успеем еще */
+
+	/* push crc */
+	sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
+	
+	lp->waitack=1;
+}
+
+/*
+ *	The typical workload of the driver:
+ *	Handle the ether interface interrupts. 
+ */
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = dev_id;
+	struct net_local* lp;
+	u_char csr0;
+	unsigned short rcv_res = RCV_NO;
+  
+  
+	if(dev == NULL || dev->irq != irq)
+	{
+		printk("sbni: irq %d for unknown device\n", irq);
+		return;
+	}
+   
+	if(dev->interrupt)
+	{
+		printk("%s: Reentering the interrupt driver!\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+   
+	csr0 = inb(dev->base_addr + CSR0);
+	DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
+     
+	lp=dev->priv;
+  
+	if(!lp->carrier)
+		lp->carrier=1;
+  
+	/*
+	 * Disable adapter interrupts
+	 */
+	outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
+	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	csr0 = inb(dev->base_addr + CSR0);
+   
+	if(csr0 & (TR_RDY | RC_RDY))
+	{
+		if(csr0 & RC_RDY)
+			rcv_res = sbni_recv(dev);
+	   
+		if((lp->currframe) && (rcv_res != RCV_WR))
+			sbni_xmit(dev);
+		else if (rcv_res == RCV_OK)
+			sbni_nirvana(dev);
+       
+		csr0 = inb(dev->base_addr + CSR0);
+		DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
+	}
+   
+  
+	DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
+     
+	/* here we should send pong */
+	outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
+	if(lp->currframe)
+		outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
+	else
+		csr0 = inb(dev->base_addr + CSR0);
+  
+	/*
+	 * Enable adapter interrupts
+	 */
+  
+	outb(csr0 | EN_INT, dev->base_addr + CSR0);
+	dev->interrupt = 0;
+}
+
+static struct enet_statistics *sbni_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	return &lp->stats;
+}
+
+static inline void sbni_get_packet(struct device* dev)
+{
+	struct net_local* lp = (struct net_local*)dev->priv;
+	struct sk_buff* skb;
+	unsigned char *rawp;
+    
+   
+     
+	skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
+   
+	if(skb == NULL)
+	{
+		DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
+		lp->stats.rx_dropped++;
+		return;
+	} else {
+#ifdef KATYUSHA
+		skb->dev = lp->m;
+#else
+		skb->dev = dev;
+#endif      
+		memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
+			lp->eth_rcv_buffer,
+			lp->inppos);
+      
+      
+		skb->mac.raw = skb->data + 8;
+    
+		if((*(char*)lp->eth_rcv_buffer) & 1)
+		{
+			if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
+				skb->pkt_type=PACKET_BROADCAST;
+			else
+				skb->pkt_type=PACKET_MULTICAST;
+		}
+		else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
+		{
+			if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
+				skb->pkt_type=PACKET_OTHERHOST;
+		}
+      
+		if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
+			skb->protocol =  *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
+		else
+		{
+			rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
+			if (*(unsigned short *)rawp == 0xFFFF)
+				skb->protocol=htons(ETH_P_802_3);
+			else
+				skb->protocol=htons(ETH_P_802_2);
+		}
+            
+
+		skb_pull(skb,SBNI_HH_SZ);
+   
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+	}
+	return;
+}
+
+static void sbni_watchdog(unsigned long arg)
+{
+	struct device* dev = (struct device*)arg;
+	struct net_local* lp = (struct net_local *)dev->priv;
+	u_char csr0;
+
+
+  
+	DP( printk("%s: watchdog start\n",dev->name); )	
+	/*
+	 * if no pong received and transmission is not in progress
+	 * then assume error
+	 */
+	cli();
+	csr0 = inb(dev->base_addr + CSR0);
+	if(csr0 & (RC_CHK | TR_REQ))
+	{
+		if(lp->timer_ticks)
+		{
+			if(csr0 & (RC_RDY | BU_EMP))
+			{
+				lp->timer_ticks--;
+			}
+		}
+		else 
+		{
+			if(lp->rxl_delta)
+			{
+				lp->ok_prev = lp->ok_curr;
+				lp->ok_curr = 0;
+				lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
+				lp->timeout_rxl++;
+				if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
+					lp->timeout_rxl = 0; 
+				lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+				/*
+				 * update ok_prev/ok_curr counters
+				 */
+				lp->ok_prev = lp->ok_curr;
+				lp->ok_curr = 0;
+			}
+			if(lp->tr_err)
+				lp->tr_err--;
+			else 
+			{
+				/* Drop the queue of tx packets */
+				sbni_drop_tx_queue(dev);
+				lp->carrier=0;
+			}
+	     
+			/*
+			 * send pong
+			 */
+
+			csr0 = inb(dev->base_addr + CSR0);
+			outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
+			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+			lp->in_stats.timeout_number++;
+		}
+	}
+	sti();
+	outb(csr0 | RC_CHK, dev->base_addr + CSR0);
+	if(dev->start)
+	{
+		struct timer_list* watchdog = &lp->watchdog; 
+		init_timer(watchdog);
+		watchdog->expires = jiffies + SBNI_TIMEOUT;
+		watchdog->data = arg;
+		watchdog->function = sbni_watchdog;
+		add_timer(watchdog);
+	}
+}
+
+static void sbni_drop_tx_queue(struct device *dev)
+{
+	struct net_local* lp = (struct net_local *)dev->priv,*nl;
+	struct sk_buff *tmp;
+   
+	/* first of all, we should try to gift our packets to another interface */
+  
+	nl=(struct net_local *)lp->m->priv;
+	if(nl==lp)
+		nl=lp->next_lp;
+  
+	if(nl)
+	{
+		/* we found device*/
+		if(lp->currframe)
+		{
+			if(!nl->currframe)
+			{
+				nl->currframe=lp->currframe;
+			}
+			else
+			{
+				skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
+			}
+		}
+		lp->currframe=NULL;
+
+		if(!nl->currframe)
+			nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
+
+		/* set request for transmit */
+		outb(inb(nl->me->base_addr + CSR0) | TR_REQ,  nl->me->base_addr + CSR0);
+    
+	}
+	else
+	{
+		/* *sigh*, we should forget this packets */
+		nl=lp->m->priv;
+    
+		while((tmp = skb_dequeue(&nl->queue)) != NULL)
+		{
+			dev_kfree_skb(tmp);
+			lp->stats.tx_packets++;
+		}
+    
+		if (lp->currframe)
+		{
+			dev_kfree_skb(lp->currframe);
+			lp->currframe = NULL;
+			lp->stats.tx_packets++;
+		}
+	}
+	lp->waitack=0;
+  	dev->tbusy = 0;
+  
+	mark_bh(NET_BH);
+	DP( printk("%s: queue dropping stoped\n",dev->name); );	
+}
+
+/*
+ * 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)
+{
+	/*
+	 * always enabled promiscuous mode.
+	*/
+	return;
+}
+
+static int sbni_set_mac_address(struct device *dev, void *addr)
+{	
+	/* struct net_local *lp = (struct net_local *)dev->priv; */
+	struct sockaddr *saddr = addr;
+	
+	if(dev->start)
+	{
+		/* Only possible while card isn't started */
+		return -EBUSY;
+	}
+	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
+	return (0);
+}
+
+static int sbni_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct net_local* lp = (struct net_local *)dev->priv,*tlp; 
+	struct device *slave;
+	int error = 0;
+	char tmpstr[6];
+  
+  
+	switch(cmd)
+	{
+		case SIOCDEVGETINSTATS:
+		{
+			struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
+			DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
+			if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
+				return -EFAULT;
+			break;
+		}
+		case SIOCDEVRESINSTATS:
+		{
+			DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
+			lp->in_stats.all_rx_number = 0;
+			lp->in_stats.bad_rx_number = 0;
+			lp->in_stats.timeout_number = 0;
+			lp->in_stats.all_tx_number = 0;
+			lp->in_stats.resend_tx_number = 0;
+			break;
+		}
+		case SIOCDEVGHWSTATE:
+		{
+			struct sbni_flags flags;
+			flags.rxl = lp->rxl_curr;
+			flags.rate = lp->csr1.rate;
+			flags.fixed_rxl = (lp->rxl_delta == 0);
+			flags.fixed_rate = 1;
+			ifr->ifr_data = *(caddr_t*)&flags;
+			DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
+			break;
+		}
+		case SIOCDEVSHWSTATE:
+		{
+			struct sbni_flags flags;
+			DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
+			/* root only */
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			flags = *(struct sbni_flags*)&ifr->ifr_data;
+			if(flags.fixed_rxl)
+			{
+				lp->rxl_delta = 0;
+				lp->rxl_curr = flags.rxl;
+			}
+			else
+			{
+				lp->rxl_delta = DEF_RXL_DELTA;
+				lp->rxl_curr = DEF_RXL;
+			}
+			lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+			if(flags.fixed_rate)
+				lp->csr1.rate = flags.rate;
+			else
+				lp->csr1.rate = DEF_RATE;
+			/*
+			 * Don't be afraid...
+			 */
+			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+
+			DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
+				dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
+			break;
+		}
+
+		case SIOCDEVENSLAVE:
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			if(copy_from_user( tmpstr, ifr->ifr_data, 6))
+				return -EFAULT;
+			slave=dev_get(tmpstr);
+			if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
+			{
+				printk("%s: Both devices should be UP to enslave!\n",dev->name);
+				return -EINVAL;
+			}
+		
+			if(slave)
+			{
+				if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
+				{
+					/* drop queue*/
+					sbni_drop_tx_queue(slave);
+					slave->flags |= IFF_SLAVE;
+					((struct net_local *)(slave->priv))->m=dev;
+					while(lp->next_lp)	//tail it after last slave
+						lp=lp->next_lp;
+					lp->next_lp=slave->priv;
+					lp=(struct net_local *)dev->priv;
+					dev->flags |= IFF_MASTER;
+					}
+				else
+				{
+					printk("%s: one of devices is already slave!\n",dev->name);
+					return -EBUSY;
+				}
+			}
+			else
+			{
+				printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
+				return -ENOENT;
+			}
+			break;    
+
+		case SIOCDEVEMANSIPATE:
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
+
+			if(dev->flags & IFF_SLAVE)
+			{
+				dev->flags &= ~IFF_SLAVE;
+				/* exclude us from masters slavelist*/
+				for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
+				if(tlp->next_lp)
+				{
+					tlp->next_lp = lp->next_lp;
+					if(!((struct net_local *)lp->m->priv)->next_lp)
+					{
+						lp->m->flags &= ~IFF_MASTER;	
+					}
+					lp->next_lp=NULL;
+					lp->m=dev;     	
+				}
+				else
+				{
+					printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
+					return -EIO;
+				}      
+			}
+			else
+			{
+				printk("%s: isn't slave device!\n",dev->name);
+				return -EINVAL;
+			}
+			break;    
+
+		default:
+			DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
+			error = -EINVAL;
+	}
+	return (error);
+}
+
+
+
+#ifdef CRCASM
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+   
+	__asm__ (
+		"xorl %%eax,%%eax\n\t"
+		"1:\n\t"
+		"lodsb\n\t"
+		"xorb %%dl,%%al\n\t"
+		"shrl $8,%%edx\n\t"
+		"xorl (%%edi,%%eax,4),%%edx\n\t"
+		"loop 1b\n\t"
+		"movl %%edx,%%eax"
+		: 
+		: "S" (mem), "D" (&crc32tab[0]), "c" (len), "d" (initial)
+		: "eax", "edx", "ecx"
+	);
+	/* return crc; */
+}
+
+#else
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+	unsigned crc;
+	crc = initial;
+   
+	for(;len;mem++,len--)
+	{
+		crc = CRC32(*mem, crc);
+	}
+	return(crc);
+}
+#endif /* CRCASM */
+#ifdef MODULE
+
+static int io[SBNI_MAX_NUM_CARDS] = { 0 };
+static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
+static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
+static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
+
+#ifdef v22
+MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+#endif
+
+
+static int sbniautodetect = -1;
+
+static struct device dev_sbni[SBNI_MAX_NUM_CARDS] = {
+	{
+		"sbni0",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni1",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni2",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni3",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni4",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni5",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni6",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	},
+	{
+		"sbni7",
+		0, 0, 0, 0,		/* memory */
+		0, 0,			/* base, irq */
+		0, 0, 0, NULL, sbni_probe 
+	}
+};
+
+int init_module(void)
+{
+	int devices = 0;
+	int installed = 0;
+	int i;
+
+	/* My simple plug for this huge init_module. "XenON */
+      
+	if(sbniautodetect != -1)
+	{
+		/* Autodetect mode */
+		printk("sbni: Autodetect mode (not recommended!) ...\n");
+		if(!sbniautodetect)
+			sbniautodetect=SBNI_MAX_NUM_CARDS;
+		printk("Trying to find %d SBNI cards...\n", sbniautodetect);
+		if(sbniautodetect > SBNI_MAX_NUM_CARDS)
+		{
+			sbniautodetect = SBNI_MAX_NUM_CARDS;
+			printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+		}
+		for(i = 0; i < sbniautodetect; i++)
+		{
+			if(!register_netdev(&dev_sbni[i]))
+				installed++;
+		}
+		if(installed)
+			return 0;
+		else
+		    return -EIO;
+	}
+	
+	/* Manual mode */
+	for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
+	{
+		if((io[i] != 0) || (irq[i] != 0))
+			devices++;
+	}
+	for(i = 0; i < devices; i++)
+	{
+		dev_sbni[i].irq = irq[i];
+		dev_sbni[i].base_addr = io[i];
+		def_rxl = rxl[i];
+		def_baud = baud[i];
+		def_mac = mac[i];
+		if(register_netdev(&dev_sbni[i]))
+			printk("sbni: card not found!\n");
+		else
+			installed++;
+	}
+	if(installed)
+		return 0;
+	else
+		return -EIO;
+}
+
+void cleanup_module(void)
+{
+	int i;
+	for(i = 0; i < 4; i++)
+	{
+		if(dev_sbni[i].priv)
+		{
+			free_irq(dev_sbni[i].irq, &dev_sbni[i]);
+			release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
+			unregister_netdev(&dev_sbni[i]);
+			kfree(dev_sbni[i].priv);
+			dev_sbni[i].priv = NULL;
+		}
+	}
+}
+#endif /* MODULE */
diff -urN linux-2.2.13-pre6/drivers/net/sbni.h linux-2.2.13-pre7/drivers/net/sbni.h
--- linux-2.2.13-pre6/drivers/net/sbni.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.13-pre7/drivers/net/sbni.h	2003-08-15 15:07:39.000000000 -0700
@@ -0,0 +1,194 @@
+/*
+ * sbni.h - header file for sbni linux device driver
+ *
+ * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
+ *
+ */
+
+/*
+ * SBNI12 definitions
+ *
+ * Revision 2.0.0  1997/08/27
+ * Initial revision
+ *
+ * Revision 2.1.0  1999/04/26
+ * dev_priv structure changed to support balancing and some other features.
+ *
+ */
+
+#ifndef __SBNI_H
+#define __SBNI_H
+
+#define SBNI_DEBUG 0
+
+#if SBNI_DEBUG
+#define DP( A ) A
+#else
+#define DP( A )
+#endif
+
+typedef unsigned char BOOLEAN;
+
+#define TRUE 1
+#define FALSE 0
+
+#define	SBNI_IO_EXTENT	0x4
+#define SB_MAX_BUFFER_ARRAY 1023
+
+#define CSR0	0
+#define CSR1	1
+
+#define	DAT	2
+
+/* CSR0 mapping */
+#define BU_EMP	(1 << 1)	/* r z    */
+#define	RC_CHK	(1 << 2)	/* rw     */
+#define	CT_ZER	(1 << 3)	/*  w     */
+#define	TR_REQ	(1 << 4)	/* rwz*   */
+
+#define TR_RDY	(1 << 5)	/* r z    */
+#define EN_INT	(1 << 6)	/* rwz* */
+#define RC_RDY	(1 << 7)	/* r z    */
+
+/* CSR1 mapping */
+#define PR_RES	(1 << 7)	/*  w     */
+
+struct sbni_csr1 {
+	unsigned rxl:5;
+	unsigned rate:2;
+	unsigned:1;
+};
+
+#define DEF_RXL_DELTA	-1
+#define DEF_RXL		0xf
+#define DEF_RATE	0
+#define DEF_FRAME_LEN	(1023 - 14 - 9)
+
+#ifdef MODULE
+
+#define SBNI_MAX_NUM_CARDS 8
+#define SBNI_MAX_SLAVES 8
+
+
+#endif				/* MODULE */
+
+#define SBNI_SIG 0x5a
+
+#define	SB_ETHER_MIN_LEN 60
+
+#define SB_FILLING_CHAR (unsigned char)0x00
+#define TR_ERROR_COUNT 32
+#define CHANGE_LEVEL_START_TICKS 4
+#define SBNI_INTERNAL_QUEUE_SIZE 10	/* 100 ? */
+
+#define PACKET_FIRST_FRAME (unsigned short)0x8000
+#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
+#define PACKET_RESEND 0x4000
+#define PACKET_SEND_OK 0x3000
+#define PACKET_LEN_MASK (unsigned short)0x03ff
+#define PACKET_INF_MASK (unsigned short)0x7000
+
+#define ETHER_ADDR_LEN 6
+
+#define SBNI_TIMEOUT HZ/10	/* ticks to wait for pong or packet */
+		/* sbni watchdog called SBNI_HZ times per sec. */
+
+struct sbni_in_stats {
+	unsigned int all_rx_number;
+	unsigned int bad_rx_number;
+	unsigned int timeout_number;
+	unsigned int all_tx_number;
+	unsigned int resend_tx_number;
+};
+
+
+/*
+ *    Board-specific info in dev->priv. 
+ */
+struct net_local {
+	struct enet_statistics stats;
+
+	struct timer_list watchdog;
+	unsigned int realframelen;	/* the current size of the SB-frame */
+	unsigned int eth_trans_buffer_len;	/* tx buffer length */
+	unsigned int outpos;
+	unsigned int inppos;
+	unsigned int frame_len;	/* The set SB-frame size */
+	unsigned int tr_err;
+	unsigned int timer_ticks;
+	BOOLEAN last_receive_OK;
+	BOOLEAN tr_resend;
+
+	unsigned char wait_frame_number;
+	unsigned char eth_trans_buffer[1520];	/* tx buffer */
+	unsigned char HSCounter;	/* Reserved field */
+	unsigned char eth_rcv_buffer[2600];	/* rx buffer */
+	struct sbni_csr1 csr1;
+	/* Internal Statistics */
+	struct sbni_in_stats in_stats;
+
+	int rxl_curr;		/* current receive level value [0..0xf] */
+	int rxl_delta;		/* receive level delta (+1, -1)
+				   rxl_delta == 0 - receive level
+				   autodetection
+				   disabled            */
+	unsigned int ok_curr;	/* current ok frames received           */
+	unsigned int ok_prev;	/* previous ok frames received          */
+	unsigned int timeout_rxl;
+
+	struct sk_buff_head queue;
+	struct sk_buff *currframe;
+	BOOLEAN waitack;
+
+	struct device *m;	/* master */
+	struct device *me;	/* me */
+	struct net_local *next_lp;	/* next lp */
+
+	int carrier;
+
+
+};
+
+
+struct sbni_hard_header {
+
+	/* internal sbni stuff */
+	unsigned int crc;	/* 4 */
+	unsigned short packetlen;	/* 2 */
+	unsigned char number;	/* 1 */
+	unsigned char reserv;	/* 1 */
+
+	/* 8 */
+
+	/* ethernet stuff */
+	unsigned char h_dest[ETH_ALEN];		/* destination eth addr */
+	unsigned char h_source[ETH_ALEN];	/* source ether addr    */
+	unsigned short h_proto;	/* packet type ID field */
+	/* +14 */
+	/* 22 */
+
+};
+
+#define SBNI_HH_SZ 22
+
+struct sbni_flags {
+	unsigned rxl:4;
+	unsigned rate:2;
+	unsigned fixed_rxl:1;
+	unsigned fixed_rate:1;
+};
+
+#define RCV_NO 0
+#define RCV_OK 1
+#define RCV_WR 2
+
+
+#define SIOCDEVGETINSTATS 	SIOCDEVPRIVATE
+#define SIOCDEVRESINSTATS 	SIOCDEVPRIVATE+1
+#define SIOCDEVGHWSTATE   	SIOCDEVPRIVATE+2
+#define SIOCDEVSHWSTATE   	SIOCDEVPRIVATE+3
+#define SIOCDEVENSLAVE  	SIOCDEVPRIVATE+4
+#define SIOCDEVEMANSIPATE  	SIOCDEVPRIVATE+5
+
+
+#endif				/* __SBNI_H */
diff -urN linux-2.2.13-pre6/drivers/net/Space.c linux-2.2.13-pre7/drivers/net/Space.c
--- linux-2.2.13-pre6/drivers/net/Space.c	1999-08-25 17:29:48.000000000 -0700
+++ linux-2.2.13-pre7/drivers/net/Space.c	2003-08-15 15:07:39.000000000 -0700
@@ -139,6 +139,9 @@
 /* Fibre Channel adapters */
 extern int iph5526_probe(struct device *dev);
 
+/* SBNI adapters */
+extern int sbni_probe(struct device *);
+
 struct devprobe
 {
 	int (*probe)(struct device *dev);
@@ -853,6 +856,29 @@
 #   undef       NEXT_DEV
 #   define      NEXT_DEV        (&fc0_dev)
 #endif
+
+
+#ifdef CONFIG_SBNI
+	static struct device sbni7_dev =
+		{"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
+	static struct device sbni6_dev =
+		{"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
+	static struct device sbni5_dev =
+		{"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
+	static struct device sbni4_dev =
+		{"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
+	static struct device sbni3_dev =
+		{"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
+	static struct device sbni2_dev =
+		{"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
+	static struct device sbni1_dev =
+		{"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
+	static struct device sbni0_dev =
+		{"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+
+#undef	NEXT_DEV
+#define	NEXT_DEV	(&sbni0_dev)
+#endif 
 	
 	
 #ifdef CONFIG_NET_SB1000
diff -urN linux-2.2.13-pre6/drivers/net/wavelan.c linux-2.2.13-pre7/drivers/net/wavelan.c
--- linux-2.2.13-pre6/drivers/net/wavelan.c	1999-08-09 12:04:57.000000000 -0700
+++ linux-2.2.13-pre7/drivers/net/wavelan.c	2003-08-15 15:07:39.000000000 -0700
@@ -2094,7 +2094,7 @@
 	  wrq->u.data.length = sizeof(struct iw_range);
 
 	  /* Set information in the range struct.  */
-	  range.throughput = 1.6 * 1024 * 1024;	/* don't argue on this ! */
+	  range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
 	  range.min_nwid = 0x0000;
 	  range.max_nwid = 0xFFFF;
 
@@ -2240,7 +2240,10 @@
 
     case SIOCSIPQTHR:
       if(!suser())
-	return -EPERM;
+        {
+	  ret = -EPERM;
+	  break;
+	}
       psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
 	       (unsigned char *)&psa.psa_quality_thr, 1);
@@ -2259,7 +2262,10 @@
     case SIOCSIPHISTO:
       /* Verify that the user is root. */
       if(!suser())
-	return -EPERM;
+        {
+	  ret = -EPERM;
+	  break;
+	}
 
       /* Check the number of intervals. */
       if(wrq->u.data.length > 16)
diff -urN linux-2.2.13-pre6/drivers/scsi/aha1542.c linux-2.2.13-pre7/drivers/scsi/aha1542.c
--- linux-2.2.13-pre6/drivers/scsi/aha1542.c	1999-08-09 12:04:39.000000000 -0700
+++ linux-2.2.13-pre7/drivers/scsi/aha1542.c	2003-08-15 15:07:39.000000000 -0700
@@ -20,7 +20,7 @@
  *        Recognize that DMA0 is valid DMA channel -- 13-Jul-98
  *  Modified by Chris Faulhaber	<jedgar@fxp.org>
  *        Added module command-line options
- *        18-Jul-99
+ *        19-Jul-99
  */
 
 #include <linux/module.h>
@@ -964,11 +964,30 @@
     tpnt->proc_dir = &proc_scsi_aha1542;
 
 #ifdef MODULE
-    bases[0] = 4;
-    bases[1] = aha1542[0];
-    bases[2] = aha1542[1];
-    bases[3] = aha1542[2];
-    bases[4] = aha1542[3];
+    bases[0]        = aha1542[0];              
+    setup_buson[0]  = aha1542[1];              
+    setup_busoff[0] = aha1542[2];              
+    {                                          
+      int atbt = -1;                           
+      switch (aha1542[3]) {                    
+        case 5:                                
+            atbt = 0x00;                       
+            break;                             
+        case 6:                                
+            atbt = 0x04;                       
+            break;                             
+        case 7:                                
+            atbt = 0x01;                       
+            break;                             
+        case 8:                                
+            atbt = 0x02;                       
+            break;                             
+        case 10:                               
+            atbt = 0x03;                       
+            break;                             
+      };                                       
+    setup_dmaspeed[0] = atbt;                  
+    }
 #endif
 
     for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++)
diff -urN linux-2.2.13-pre6/fs/dquot.c linux-2.2.13-pre7/fs/dquot.c
--- linux-2.2.13-pre6/fs/dquot.c	1999-08-25 17:29:49.000000000 -0700
+++ linux-2.2.13-pre7/fs/dquot.c	2003-08-15 15:07:40.000000000 -0700
@@ -97,6 +97,9 @@
 static struct wait_queue *dquot_wait = (struct wait_queue *)NULL,
                          *update_wait = (struct wait_queue *)NULL;
 
+void dqput(struct dquot *);
+static struct dquot *dqduplicate(struct dquot *);
+
 static inline char is_enabled(struct vfsmount *vfsmnt, short type)
 {
 	switch (type) {
@@ -390,7 +393,7 @@
 
 int sync_dquots(kdev_t dev, short type)
 {
-	struct dquot *dquot, *next;
+	struct dquot *dquot, *next, *ddquot;
 	int need_restart;
 
 restart:
@@ -407,9 +410,11 @@
 		if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD)))
 			continue;
 
-		wait_on_dquot(dquot);
-		if (dquot->dq_flags & DQ_MOD)
-			write_dquot(dquot);
+		if ((ddquot = dqduplicate(dquot)) == NODQUOT)
+			continue;
+		if (ddquot->dq_flags & DQ_MOD)
+			write_dquot(ddquot);
+		dqput(ddquot);
 		/* Set the flag for another pass. */
 		need_restart = 1;
 	}
@@ -424,6 +429,7 @@
 	return(0);
 }
 
+/* NOTE: If you change this function please check whether dqput_blocks() works right... */
 void dqput(struct dquot *dquot)
 {
 	if (!dquot)
@@ -688,6 +694,16 @@
 	}
 }
 
+/* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
+static inline int dqput_blocks(struct dquot *dquot)
+{
+	if (dquot->dq_flags & DQ_LOCKED)
+		return 1;
+	if (dquot->dq_count == 1)
+		return 1;
+	return 0;
+}
+
 static int reset_inode_dquot_ptrs(struct inode *inode, short type)
 {
 	struct dquot *dquot = inode->i_dquot[type];
@@ -701,13 +717,16 @@
 	}
 	inode->i_flags &= ~S_QUOTA;
 put_it:
-	if (dquot != NODQUOT) {
-		spin_unlock(&inode_lock);	/* We may block so drop the lock... */
-		dqput(dquot);
-		spin_lock(&inode_lock);		/* And capture lock again */
-		/* we may have blocked ... */
-		return 1;
-	}
+	if (dquot != NODQUOT)
+		if (dqput_blocks(dquot)) {
+			spin_unlock(&inode_lock);	/* We may block so drop the lock... */
+			dqput(dquot);
+			spin_lock(&inode_lock);		/* And capture lock again */
+			/* we may have blocked ... */
+			return 1;
+		}
+		else
+			dqput(dquot);	/* dqput() won't block so we can hold locks... */
 	return 0;
 }
 
diff -urN linux-2.2.13-pre6/Makefile linux-2.2.13-pre7/Makefile
--- linux-2.2.13-pre6/Makefile	2003-08-15 15:07:39.000000000 -0700
+++ linux-2.2.13-pre7/Makefile	2003-08-15 15:07:39.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 13
-EXTRAVERSION = pre6
+EXTRAVERSION = pre7
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.13-pre6/net/core/dev.c linux-2.2.13-pre7/net/core/dev.c
--- linux-2.2.13-pre6/net/core/dev.c	1999-08-09 12:04:41.000000000 -0700
+++ linux-2.2.13-pre7/net/core/dev.c	2003-08-15 15:07:40.000000000 -0700
@@ -1284,7 +1284,7 @@
 			       stats->qual.level,
 			       stats->qual.updated & 2 ? '.' : ' ',
 			       stats->qual.noise,
-			       stats->qual.updated & 3 ? '.' : ' ',
+			       stats->qual.updated & 4 ? '.' : ' ',
 			       stats->discard.nwid,
 			       stats->discard.code,
 			       stats->discard.misc);
