Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
new file mode 100644
index 0000000..1798ce7
--- /dev/null
+++ b/drivers/net/atari_bionet.c
@@ -0,0 +1,674 @@
+/* bionet.c     BioNet-100 device driver for linux68k.
+ *
+ * Version:	@(#)bionet.c	1.0	02/06/96
+ *
+ * Author:	Hartmut Laue <laue@ifk-mp.uni-kiel.de>
+ * and		Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
+ *
+ * Little adaptions for integration into pl7 by Roman Hodek
+ *
+ * Some changes in bionet_poll_rx by Karl-Heinz Lohner
+ *
+	What is it ?
+	------------
+	This driver controls the BIONET-100 LAN-Adapter which connects
+	an ATARI ST/TT via the ACSI-port to an Ethernet-based network.
+
+	This version can be compiled as a loadable module (See the
+	compile command at the bottom of this file).
+	At load time, you can optionally set the debugging level and the
+	fastest response time on the command line of 'insmod'.
+
+	'bionet_debug'
+		controls the amount of diagnostic messages:
+	  0  : no messages
+	  >0 : see code for meaning of printed messages
+
+	'bionet_min_poll_time' (always >=1)
+		gives the time (in jiffies) between polls. Low values
+		increase the system load (beware!)
+
+	When loaded, a net device with the name 'bio0' becomes available,
+	which can be controlled with the usual 'ifconfig' command.
+
+	It is possible to compile this driver into the kernel like other
+	(net) drivers. For this purpose, some source files (e.g. config-files
+	makefiles, Space.c) must be changed accordingly. (You may refer to
+	other drivers how to do it.) In this case, the device will be detected
+	at boot time and (probably) appear as 'eth0'.
+
+	This code is based on several sources:
+	- The driver code for a parallel port ethernet adapter by
+	  Donald Becker (see file 'atp.c' from the PC linux distribution)
+	- The ACSI code by Roman Hodek for the ATARI-ACSI harddisk support
+	  and DMA handling.
+	- Very limited information about moving packets in and out of the
+	  BIONET-adapter from the TCP package for TOS by BioData GmbH.
+
+	Theory of Operation
+	-------------------
+	Because the ATARI DMA port is usually shared between several
+	devices (eg. harddisk, floppy) we cannot block the ACSI bus
+	while waiting for interrupts. Therefore we use a polling mechanism
+	to fetch packets from the adapter. For the same reason, we send
+	packets without checking that the previous packet has been sent to
+	the LAN. We rely on the higher levels of the networking code to detect
+	missing packets and resend them.
+
+	Before we access the ATARI DMA controller, we check if another
+	process is using the DMA. If not, we lock the DMA, perform one or
+	more packet transfers and unlock the DMA before returning.
+	We do not use 'stdma_lock' unconditionally because it is unclear
+	if the networking code can be set to sleep, which will happen if
+	another (possibly slow) device is using the DMA controller.
+
+	The polling is done via timer interrupts which periodically
+	'simulate' an interrupt from the Ethernet adapter. The time (in jiffies)
+	between polls varies depending on an estimate of the net activity.
+	The allowed range is given by the variable 'bionet_min_poll_time'
+	for the lower (fastest) limit and the constant 'MAX_POLL_TIME'
+	for the higher (slowest) limit.
+
+	Whenever a packet arrives, we switch to fastest response by setting
+	the polling time to its lowest limit. If the following poll fails,
+	because no packets have arrived, we increase the time for the next
+	poll. When the net activity is low, the polling time effectively
+	stays at its maximum value, resulting in the lowest load for the
+	machine.
+ */
+
+#define MAX_POLL_TIME	10
+
+static char version[] =
+	"bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n";
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_acsi.h>
+#include <asm/atari_stdma.h>
+
+
+/* use 0 for production, 1 for verification, >2 for debug
+ */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+/*
+ * Global variable 'bionet_debug'. Can be set at load time by 'insmod'
+ */
+unsigned int bionet_debug = NET_DEBUG;
+MODULE_PARM(bionet_debug, "i");
+MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
+MODULE_LICENSE("GPL");
+
+static unsigned int bionet_min_poll_time = 2;
+
+
+/* Information that need to be kept for each board.
+ */
+struct net_local {
+	struct net_device_stats stats;
+	long open_time;			/* for debugging */
+	int  poll_time;			/* polling time varies with net load */
+};
+
+static struct nic_pkt_s {		/* packet format */
+	unsigned char	status;
+	unsigned char	dummy;
+	unsigned char	l_lo, l_hi;
+	unsigned char	buffer[3000];
+} *nic_packet;
+unsigned char *phys_nic_packet;
+
+/* Index to functions, as function prototypes.
+ */
+static int bionet_open(struct net_device *dev);
+static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void bionet_poll_rx(struct net_device *);
+static int bionet_close(struct net_device *dev);
+static struct net_device_stats *net_get_stats(struct net_device *dev);
+static void bionet_tick(unsigned long);
+
+static struct timer_list bionet_timer = TIMER_INITIALIZER(bionet_tick, 0, 0);
+
+#define STRAM_ADDR(a)	(((a) & 0xff000000) == 0)
+
+/* The following routines access the ethernet board connected to the
+ * ACSI port via the st_dma chip.
+ */
+#define NODE_ADR 0x60
+
+#define C_READ 8
+#define C_WRITE 0x0a
+#define C_GETEA 0x0f
+#define C_SETCR 0x0e
+
+static int
+sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) {
+	unsigned int c;
+
+	dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88);
+	dma_wd.fdc_acces_seccount = cmd;
+	dma_wd.dma_mode_status = (mod | 0x8a);
+
+	if( !acsi_wait_for_IRQ(HZ/2) )	/* wait for cmd ack */
+		return -1;		/* timeout */
+
+	c = dma_wd.fdc_acces_seccount;
+	return (c & 0xff);
+}
+
+
+static void
+set_status(int cr) {
+	sendcmd(0,0x100,NODE_ADR | C_SETCR);    /* CMD: SET CR */
+	sendcmd(1,0x100,cr);
+
+	dma_wd.dma_mode_status = 0x80;
+}
+
+static int
+get_status(unsigned char *adr) {
+	int i,c;
+
+	DISABLE_IRQ();
+	c = sendcmd(0,0x00,NODE_ADR | C_GETEA);  /* CMD: GET ETH ADR*/
+	if( c < 0 ) goto gsend;
+
+	/* now read status bytes */
+
+	for (i=0; i<6; i++) {
+		dma_wd.fdc_acces_seccount = 0;	/* request next byte */
+
+    		if( !acsi_wait_for_IRQ(HZ/2) ) {	/* wait for cmd ack */
+			c = -1;
+			goto gsend;		/* timeout */
+		}
+		c = dma_wd.fdc_acces_seccount;
+		*adr++ = (unsigned char)c;
+	}
+	c = 1;
+gsend:
+  	dma_wd.dma_mode_status = 0x80;
+	return c;
+}
+
+static irqreturn_t
+bionet_intr(int irq, void *data, struct pt_regs *fp) {
+	return IRQ_HANDLED;
+}
+
+
+static int
+get_frame(unsigned long paddr, int odd) {
+	int c;
+	unsigned long flags;
+
+	DISABLE_IRQ();
+	local_irq_save(flags);
+
+	dma_wd.dma_mode_status		= 0x9a;
+	dma_wd.dma_mode_status		= 0x19a;
+	dma_wd.dma_mode_status		= 0x9a;
+	dma_wd.fdc_acces_seccount	= 0x04;		/* sector count (was 5) */
+	dma_wd.dma_lo			= (unsigned char)paddr;
+	paddr >>= 8;
+	dma_wd.dma_md			= (unsigned char)paddr;
+	paddr >>= 8;
+	dma_wd.dma_hi			= (unsigned char)paddr;
+	local_irq_restore(flags);
+
+	c = sendcmd(0,0x00,NODE_ADR | C_READ);	/* CMD: READ */
+	if( c < 128 ) goto rend;
+
+	/* now read block */
+
+	c = sendcmd(1,0x00,odd);	/* odd flag for address shift */
+	dma_wd.dma_mode_status	= 0x0a;
+
+	if( !acsi_wait_for_IRQ(100) ) {	/* wait for DMA to complete */
+		c = -1;
+		goto rend;
+	}
+	dma_wd.dma_mode_status	= 0x8a;
+	dma_wd.dma_mode_status	= 0x18a;
+	dma_wd.dma_mode_status	= 0x8a;
+	c = dma_wd.fdc_acces_seccount;
+
+	dma_wd.dma_mode_status	= 0x88;
+	c = dma_wd.fdc_acces_seccount;
+	c = 1;
+
+rend:
+	dma_wd.dma_mode_status	= 0x80;
+	udelay(40);
+	acsi_wait_for_noIRQ(20);
+	return c;
+}
+
+
+static int
+hardware_send_packet(unsigned long paddr, int cnt) {
+	unsigned int c;
+	unsigned long flags;
+
+	DISABLE_IRQ();
+	local_irq_save(flags);
+
+	dma_wd.dma_mode_status	= 0x19a;
+	dma_wd.dma_mode_status	= 0x9a;
+	dma_wd.dma_mode_status	= 0x19a;
+	dma_wd.dma_lo		= (unsigned char)paddr;
+	paddr >>= 8;
+	dma_wd.dma_md		= (unsigned char)paddr;
+	paddr >>= 8;
+	dma_wd.dma_hi		= (unsigned char)paddr;
+
+	dma_wd.fdc_acces_seccount	= 0x4;		/* sector count */
+	local_irq_restore(flags);
+
+	c = sendcmd(0,0x100,NODE_ADR | C_WRITE);	/* CMD: WRITE */
+	c = sendcmd(1,0x100,cnt&0xff);
+	c = sendcmd(1,0x100,cnt>>8);
+
+	/* now write block */
+
+	dma_wd.dma_mode_status	= 0x10a;	/* DMA enable */
+	if( !acsi_wait_for_IRQ(100) )		/* wait for DMA to complete */
+		goto end;
+
+	dma_wd.dma_mode_status	= 0x19a;	/* DMA disable ! */
+	c = dma_wd.fdc_acces_seccount;
+
+end:
+	c = sendcmd(1,0x100,0);
+	c = sendcmd(1,0x100,0);
+
+	dma_wd.dma_mode_status	= 0x180;
+	udelay(40);
+	acsi_wait_for_noIRQ(20);
+	return( c & 0x02);
+}
+
+
+/* Check for a network adaptor of this type, and return '0' if one exists.
+ */
+struct net_device * __init bionet_probe(int unit)
+{
+	struct net_device *dev;
+	unsigned char station_addr[6];
+	static unsigned version_printed;
+	static int no_more_found;	/* avoid "Probing for..." printed 4 times */
+	int i;
+	int err;
+
+	if (!MACH_IS_ATARI || no_more_found)
+		return ERR_PTR(-ENODEV);
+
+	dev = alloc_etherdev(sizeof(struct net_local));
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+	if (unit >= 0) {
+		sprintf(dev->name, "eth%d", unit);
+		netdev_boot_setup_check(dev);
+	}
+	SET_MODULE_OWNER(dev);
+
+	printk("Probing for BioNet 100 Adapter...\n");
+
+	stdma_lock(bionet_intr, NULL);
+	i = get_status(station_addr);	/* Read the station address PROM.  */
+	ENABLE_IRQ();
+	stdma_release();
+
+	/* Check the first three octets of the S.A. for the manufactor's code.
+	 */
+
+	if( i < 0
+	||  station_addr[0] != 'B'
+	||  station_addr[1] != 'I'
+	||  station_addr[2] != 'O' ) {
+		no_more_found = 1;
+		printk( "No BioNet 100 found.\n" );
+		free_netdev(dev);
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (bionet_debug > 0 && version_printed++ == 0)
+		printk(version);
+
+	printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n",
+		dev->name, "BioNet 100",
+		station_addr[0], station_addr[1], station_addr[2],
+		station_addr[3], station_addr[4], station_addr[5]);
+
+	/* Initialize the device structure. */
+
+	nic_packet = (struct nic_pkt_s *)acsi_buffer;
+	phys_nic_packet = (unsigned char *)phys_acsi_buffer;
+	if (bionet_debug > 0) {
+		printk("nic_packet at 0x%p, phys at 0x%p\n",
+			nic_packet, phys_nic_packet );
+	}
+
+	dev->open		= bionet_open;
+	dev->stop		= bionet_close;
+	dev->hard_start_xmit	= bionet_send_packet;
+	dev->get_stats		= net_get_stats;
+
+	/* Fill in the fields of the device structure with ethernet-generic
+	 * values. This should be in a common file instead of per-driver.
+	 */
+
+	for (i = 0; i < ETH_ALEN; i++) {
+#if 0
+		dev->broadcast[i] = 0xff;
+#endif
+		dev->dev_addr[i]  = station_addr[i];
+	}
+	err = register_netdev(dev);
+	if (!err)
+		return dev;
+	free_netdev(dev);
+	return ERR_PTR(err);
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+ */
+static int
+bionet_open(struct net_device *dev) {
+	struct net_local *lp = netdev_priv(dev);
+
+	if (bionet_debug > 0)
+		printk("bionet_open\n");
+	stdma_lock(bionet_intr, NULL);
+
+	/* Reset the hardware here.
+	 */
+	set_status(4);
+	lp->open_time = 0;	/*jiffies*/
+	lp->poll_time = MAX_POLL_TIME;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	stdma_release();
+	bionet_timer.data = (long)dev;
+	bionet_timer.expires = jiffies + lp->poll_time;
+	add_timer(&bionet_timer);
+	return 0;
+}
+
+static int
+bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
+	struct net_local *lp = netdev_priv(dev);
+	unsigned long flags;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	local_irq_save(flags);
+
+	if (stdma_islocked()) {
+		local_irq_restore(flags);
+		lp->stats.tx_errors++;
+	}
+	else {
+		int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned long buf = virt_to_phys(skb->data);
+		int stat;
+
+		stdma_lock(bionet_intr, NULL);
+		local_irq_restore(flags);
+		if( !STRAM_ADDR(buf+length-1) ) {
+			memcpy(nic_packet->buffer, skb->data, length);
+			buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
+		}
+
+		if (bionet_debug >1) {
+			u_char *data = nic_packet->buffer, *p;
+			int i;
+			
+			printk( "%s: TX pkt type 0x%4x from ", dev->name,
+				  ((u_short *)data)[6]);
+
+			for( p = &data[6], i = 0; i < 6; i++ )
+				printk("%02x%s", *p++,i != 5 ? ":" : "" );
+			printk(" to ");
+
+			for( p = data, i = 0; i < 6; i++ )
+				printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+
+			printk( "%s: ", dev->name );
+			printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+			       " %02x%02x%02x%02x len %d\n",
+				  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+				  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+				  data[28], data[29], data[30], data[31], data[32], data[33],
+				  length );
+		}
+		dma_cache_maintenance(buf, length, 1);
+
+		stat = hardware_send_packet(buf, length);
+		ENABLE_IRQ();
+		stdma_release();
+
+		dev->trans_start = jiffies;
+		dev->tbusy	 = 0;
+		lp->stats.tx_packets++;
+		lp->stats.tx_bytes+=length;
+	}
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/* We have a good packet(s), get it/them out of the buffers.
+ */
+static void
+bionet_poll_rx(struct net_device *dev) {
+	struct net_local *lp = netdev_priv(dev);
+	int boguscount = 10;
+	int pkt_len, status;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/* ++roman: Take care at locking the ST-DMA... This must be done with ints
+	 * off, since otherwise an int could slip in between the question and the
+	 * locking itself, and then we'd go to sleep... And locking itself is
+	 * necessary to keep the floppy_change timer from working with ST-DMA
+	 * registers. */
+	if (stdma_islocked()) {
+		local_irq_restore(flags);
+		return;
+	}
+	stdma_lock(bionet_intr, NULL);
+	DISABLE_IRQ();
+	local_irq_restore(flags);
+
+	if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
+
+	while(boguscount--) {
+		status = get_frame((unsigned long)phys_nic_packet, 0);
+
+		if( status == 0 ) break;
+
+		/* Good packet... */
+
+		dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0);
+
+		pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
+
+		lp->poll_time = bionet_min_poll_time;    /* fast poll */
+		if( pkt_len >= 60 && pkt_len <= 1520 ) {
+					/*	^^^^ war 1514  KHL */
+			/* Malloc up new buffer.
+			 */
+			struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet.\n",
+					dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+
+			skb->dev = dev;
+			skb_reserve( skb, 2 );		/* 16 Byte align  */
+			skb_put( skb, pkt_len );	/* make room */
+
+			/* 'skb->data' points to the start of sk_buff data area.
+			 */
+			memcpy(skb->data, nic_packet->buffer, pkt_len);
+			skb->protocol = eth_type_trans( skb, dev ); 
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			lp->stats.rx_packets++;
+			lp->stats.rx_bytes+=pkt_len;
+
+	/* If any worth-while packets have been received, dev_rint()
+	   has done a mark_bh(INET_BH) for us and will work on them
+	   when we get to the bottom-half routine.
+	 */
+
+ 			if (bionet_debug >1) {
+ 				u_char *data = nic_packet->buffer, *p;
+ 				int i;
+ 				
+ 				printk( "%s: RX pkt type 0x%4x from ", dev->name,
+ 					  ((u_short *)data)[6]);
+ 					 
+ 				
+ 				for( p = &data[6], i = 0; i < 6; i++ )
+ 					printk("%02x%s", *p++,i != 5 ? ":" : "" );
+ 				printk(" to ");
+ 				for( p = data, i = 0; i < 6; i++ )
+ 					printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
+ 
+ 				printk( "%s: ", dev->name );
+ 				printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
+ 				       " %02x%02x%02x%02x len %d\n",
+ 					  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
+ 					  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
+ 					  data[28], data[29], data[30], data[31], data[32], data[33],
+ 						  pkt_len );
+ 			}
+ 		}
+ 		else {
+ 			printk(" Packet has wrong length: %04d bytes\n", pkt_len);
+ 			lp->stats.rx_errors++;
+ 		}
+ 	}
+	stdma_release();
+	ENABLE_IRQ();
+	return;
+}
+
+/* bionet_tick: called by bionet_timer. Reads packets from the adapter,
+ * passes them to the higher layers and restarts the timer.
+ */
+static void
+bionet_tick(unsigned long data) {
+	struct net_device	 *dev = (struct net_device *)data;
+	struct net_local *lp = netdev_priv(dev);
+
+	if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 )
+		printk("bionet_tick: %ld\n", lp->open_time);
+
+	if( !stdma_islocked() ) bionet_poll_rx(dev);
+
+	bionet_timer.expires = jiffies + lp->poll_time;
+	add_timer(&bionet_timer);
+}
+
+/* The inverse routine to bionet_open().
+ */
+static int
+bionet_close(struct net_device *dev) {
+	struct net_local *lp = netdev_priv(dev);
+
+	if (bionet_debug > 0)
+		printk("bionet_close, open_time=%ld\n", lp->open_time);
+	del_timer(&bionet_timer);
+	stdma_lock(bionet_intr, NULL);
+
+	set_status(0);
+	lp->open_time = 0;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	stdma_release();
+	return 0;
+}
+
+/* Get the current statistics.
+   This may be called with the card open or closed.
+ */
+static struct net_device_stats *net_get_stats(struct net_device *dev) 
+{
+	struct net_local *lp = netdev_priv(dev);
+	return &lp->stats;
+}
+
+
+#ifdef MODULE
+
+static struct net_device *bio_dev;
+
+int init_module(void)
+{
+	bio_dev = bionet_probe(-1);
+	if (IS_ERR(bio_dev))
+		return PTR_ERR(bio_dev);
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(bio_dev);
+	free_netdev(bio_dev);
+}
+
+#endif /* MODULE */
+
+/* Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include
+	-b m68k-linuxaout -Wall -Wstrict-prototypes -O2
+	-fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 8
+ * End:
+ */