/* znote.c: An Zenith Z-Note ethernet driver for linux. */
/*
    Written 1993 by Donald Becker.
    This software may be used and distributed according to the terms
    of the GNU Public License, incorporated herein by reference.
*/

static char *version = "znote.c:v0.00 8/11/93 becker@super.org\n";

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
/*#include <linux/interrupt.h>*/
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/system.h>

#include "dev.h"
/*#include "iow.h"*/
#include "eth.h"
#include "skbuff.h"
#include "arp.h"

/* From auto_irq.c, should be in a *.h file. */
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
extern struct device *irq2dev_map[16];

#ifdef ZNET_DEBUG
int znet_debug = ZNET_DEBUG;
#else
int znet_debug = 4;
#endif

/* The DMA modes we need aren't in <dma.h>. */
#define DMA_RX_MODE	0x14	/* Auto init, I/O to mem, ++, demand. */
#define DMA_TX_MODE	0x18	/* Auto init, Mem to I/O, ++, demand. */
#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
#define DMA_BUF_SIZE 8192

/* Offsets from base I/O address. */
#define ZNET_CMD 0x0
#define ZNET_STATUS 0x0
#define ZNET_CMD1 0x0

/* Commands to the i82593. */
#define CMD0_RESET 14

struct znet_private {
  int rx_dma, tx_dma;
  struct enet_statistics stats;
  void *buffer;
  short *rx_buffer;
  short *tx_buffer;
  short *rx_cur;
  short *tx_cur;
};
static struct znet_private zn;	/* Only one can be built-in;-> */
static char dma_buffer[3*DMA_BUF_SIZE];

/* The configuration block.  What an undocumented nightmare.  The first
   set of values are those suggested (without explaination) for ethernet
   in the Intel 82586 databook.  The rest appear to be completely undocumented,
   except for cryptic notes in the Crynwr packet driver.  This driver uses
   the Crynwr values verbatim. */

static unsigned char i593_init[] = {
  0xAA,			/* 1: 16-byte input & 80-byte output FIFO. */
			/*    threshhold, 96-byte FIFO, 82593 mode. */
  0x88,			/* 2: Continuous w/interrupts, 128-clock DMA.*/
  0x2E,			/* 3: 8-byte preamble, NO address insertion, */
			/*    6-byte Ethernet address, loopback off.*/
  0x00,			/* 4: Default priorities & backoff methods. */
  0x60,			/* 5: 96-bit interframe spacing. */
  0x00,			/* 6: 512-bit slot time (low-order). */
  0xF2,			/* 7: Slot time (high-order), 15 COLL retries. */
  0x00,			/* 8: Promisc-off, broadcast-on, default CRC. */
  0x00,			/* 9: Default carrier-sense, collision-detect. */
  0x40,			/* 10: 64-byte minimum frame length. */
  0x5F,			/* 11: Type/length checks OFF, no CRC input,
			   "jabber" termination, etc. */
  0x00,			/* 12: Full-duplex disabled. */
  0x3F,			/* 13: Default multicast addresses & backoff. */
  0x07,			/* 14:  Default IFS retriggering. */
  0x31,			/* 15:  Internal retransmit, drop "runt" packets,
			   synchr. DRQ deassertion, 6 status bytes. */
  0x22,			/* 16: Receive ring-buffer size (8K), 
			   receive-stop register enable. */
};

struct netidblk {
  char magic[8];	/* The magic number (string) "NETIDBLK" */
  unsigned char netid[8]; /* The physical station address */
  char nettype, globalopt;
  char vendor[8];	/* The machine vendor and product name. */ 
  char product[8];
  char irq1, irq2;	/* Interrupts, only one is currently used.  */
  char dma1, dma2;
  short dma_mem_misc[8];	/* DMA buffer locations (unused in Linux). */
  short iobase1, iosize1;
  short iobase2, iosize2;	/* Second iobase unused. */
  char driver_options;		/* Misc. bits */
  char pad;
};

int znet_probe(struct device *dev);
static int znet_open(struct device *dev);
static int znet_start_xmit(struct sk_buff *skb, struct device *dev);
static int znet_rx(struct device *dev);
static void znet_interrupt(int reg_ptr);
static int znet_close(struct device *dev);

#ifdef notdef
static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, };
#endif


/* The Z-Note probe is trival, just check a single location
   and initialize the 82593 if found. */

int znet_probe(struct device *dev)
{
    int i;
    struct netidblk *netinfo;
    char *p;

    /* This code should scan the region  0xf0000 to 0xffff
       for a "NETIDBLK".  The alpha version cheats. */
    for(p = (char *)0xf0000; p < (char *)0x100000; p++)
	if (*p == 'N'  &&  strncmp(p, "NETIDBLK", 8) == 0)
	    break;

    if (p >= (char *)0x100000) {
	if (znet_debug > 1)
	    printk("No Z-Note ethernet adaptor found.\n");
	return 0;
    }
    netinfo = (struct netidblk *)p;
    dev->base_addr = netinfo->iobase1;
    dev->irq = netinfo->irq1;

    printk("%s: ZNET at %#3x,", dev->name, dev->base_addr);

    /* The station address is in the "netidblk" at 0x0f0000. */
    for (i = 0; i < 6; i++)
	printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);

    printk(", using IRQ %d.\n", dev->irq);

    if (znet_debug > 1) {
	printk("%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
	       dev->name, netinfo->vendor,
	       netinfo->irq1, netinfo->irq2,
	       netinfo->dma1, netinfo->dma2);
	printk("%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
	       dev->name, netinfo->iobase1, netinfo->iosize1,
	       netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
    }

    if (znet_debug > 0)
	printk(version);

    dev->private = (void *) &zn;
    zn.rx_dma = netinfo->dma1;
    zn.tx_dma = netinfo->dma2;

    /* The ZNET-specific entries in the device structure. */
    dev->open = &znet_open;
    dev->hard_start_xmit = &znet_start_xmit;
    dev->stop = &znet_close;

    /* Fill in the generic field of the device structure. */
    for (i = 0; i < DEV_NUMBUFFS; i++)
	dev->buffs[i] = NULL;

    dev->hard_header	= eth_header;
    dev->add_arp	= eth_add_arp;
    dev->queue_xmit	= dev_queue_xmit;
    dev->rebuild_header	= eth_rebuild_header;
    dev->type_trans	= eth_type_trans;

    dev->type		= ARPHRD_ETHER;
    dev->hard_header_len = ETH_HLEN;
    dev->mtu		= 1500; /* eth_mtu */
    dev->addr_len	= ETH_ALEN;
    for (i = 0; i < dev->addr_len; i++) {
	dev->broadcast[i]=0xff;
    }

    /* New-style flags. */
    dev->flags		= IFF_BROADCAST;
    dev->family		= AF_INET;
    dev->pa_addr	= 0;
    dev->pa_brdaddr	= 0;
    dev->pa_mask	= 0;
    dev->pa_alen	= sizeof(unsigned long);

    return 0;
}


static int
znet_open(struct device *dev)
{
    int ioaddr = dev->base_addr;

    if (znet_debug > 2)
      printk("%s: znet_open() called.\n", dev->name);

    /* There must be a better way to write this. */
    if (request_irq(dev->irq, &znet_interrupt))
	return -EBUSY;
    if (request_dma(zn.rx_dma)) {
	free_irq(dev->irq);
	return -EBUSY;
    }
    if (request_dma(zn.tx_dma)) {
	free_dma(zn.tx_dma);
	free_irq(dev->irq);
	return -EBUSY;
    }

    irq2dev_map[dev->irq] = dev;

    /* Turn on the 82501 SIA, using zenith-specific magic. */
    outb(0x10, 0xe6);			/* Select LAN control register */
    outb(inb(0xe7) | 0x84, 0xe7); 	/* Turn on LAN power (bit 2). */

    /* Allocate buffer memory.  We can cross a 128K boundary, so we
       must be careful about the allocation.  It's easiest to waste 8K. */
    if (dma_page_eq(&dma_buffer[0], &dma_buffer[DMA_BUF_SIZE])) {
	zn.rx_buffer = (short *)dma_buffer;
	if (dma_page_eq(&dma_buffer[DMA_BUF_SIZE],
			&dma_buffer[2*DMA_BUF_SIZE]))
	    zn.tx_buffer = (short *)&dma_buffer[DMA_BUF_SIZE];
	else
	    zn.tx_buffer = (short *)&dma_buffer[2*DMA_BUF_SIZE];
    } else {
	zn.rx_buffer = (short *)&dma_buffer[DMA_BUF_SIZE];
	zn.tx_buffer = (short *)&dma_buffer[2*DMA_BUF_SIZE];
    }

    zn.rx_cur = zn.rx_buffer;
    zn.tx_cur = zn.tx_buffer;

    set_dma_mode(zn.rx_dma, DMA_RX_MODE);
    set_dma_mode(zn.tx_dma, DMA_TX_MODE);
    cli();
    clear_dma_ff(zn.rx_dma);
    set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_buffer);
    set_dma_count(zn.rx_dma, DMA_BUF_SIZE);
    set_dma_addr(zn.rx_dma, (unsigned int) zn.tx_buffer);
    set_dma_count(zn.rx_dma, DMA_BUF_SIZE);
    sti();
    
    /* Enable both DMA channels. */
    enable_dma(zn.rx_dma);
    enable_dma(zn.tx_dma);

    /* Reset the chip, and start it up. */
    outb(CMD0_RESET, ioaddr);
    
    /* This follows the packet driver's lead, and checks for success. */
    if (inb(ioaddr) != 0x0010 || inb(ioaddr) != 0x0000)
	printk("%s: Problem turning on the power.\n", dev->name);

    dev->tbusy = 0;
    dev->interrupt = 0;
    dev->start = 1;

    return 0;
}

static int
znet_start_xmit(struct sk_buff *skb, struct device *dev)
{
    int ioaddr = dev->base_addr;

    /* Transmitter timeout, serious problems. */
    if (dev->tbusy) {
	int tickssofar = jiffies - dev->trans_start;
	if (tickssofar < 5)
	    return 1;
	printk("%s: transmit timed out, bummer.\n", dev->name);
    }

    if (skb == NULL) {
	dev_tint(dev);
	return 0;
    }

    /* Fill in the ethernet header. */
    if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
	skb->dev = dev;
	arp_queue (skb);
	return 0;
    }

    if (skb->len <= 0)
	return 0;

    printk("%s: znet_start_xmit() called.\n", dev->name);

    /* Trigger a packet send here. */
    dev->tbusy=1;
    {
	int length = skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN;
	char *data = (char *)(skb+1);

	*zn.tx_cur++ = length;
	*zn.tx_cur++ = length>>8;
	memcpy(zn.tx_cur, data,skb->len);
	zn.tx_cur += length;
	*zn.tx_cur++ = 0;
	*zn.tx_cur++ = 0;
	outb(0x14, ioaddr);	/* Trigger transmit */
    }
    return 0;
}

/* The ZNET interrupt handler. */
static void
znet_interrupt(int reg_ptr)
{
    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
    struct device *dev = irq2dev_map[irq];
    int status, ioaddr;

    if (dev == NULL) {
	printk ("znet_interrupt(): irq %d for unknown device.\n", irq);
	return;
    }
    dev->interrupt = 1;
    ioaddr = dev->base_addr;
    status = inb(ioaddr);
    if (znet_debug > 3)
	printk("%s: interrupt, status %2.2x.\n", dev->name, status);

    znet_rx(dev);

    /* Clear the interrupts we've handled. */

    dev->interrupt = 0;
    return;
}

static int
znet_rx(struct device *dev)
{
	
#ifdef sleazy_znet_rx
    /* Copy the packet to the upper layers. */
    if (dev_rint(zn.rx_cur, msg_length, 0, dev))
	break;
#endif
    return 0;
}

static int
znet_close(struct device *dev)
{
    int ioaddr = dev->base_addr;

    dev->tbusy = 1;
    dev->start = 0;

    outb(CMD0_RESET, ioaddr);		/* CMD0_RESET */

    disable_dma(zn.rx_dma);
    free_dma(zn.rx_dma);
    disable_dma(zn.tx_dma);
    free_dma(zn.tx_dma);

    free_irq(dev->irq);

    irq2dev_map[dev->irq] = 0;

    if (znet_debug > 1)
	printk("%s: Shutting down ethercard.\n", dev->name);
    /* Turn off transceiver power. */
    outb(0x10, 0xe6);			/* Select LAN control register */
    outb(inb(0xe7) & ~0x84, 0xe7); 	/* Turn on LAN power (bit 2). */

    return 0;
}

/*
 * Local variables:
 *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -c znote.c"
 * End:
 */
