patch-2.1.111 linux/drivers/net/apricot.c
Next file: linux/drivers/net/hamradio/mkiss.c
Previous file: linux/drivers/net/Makefile
Back to the patch index
Back to the overall index
- Lines: 1032
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.1.110/linux/drivers/net/apricot.c
- Orig date:
Thu Feb 12 20:56:07 1998
diff -u --recursive --new-file v2.1.110/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
@@ -1,1031 +0,0 @@
-/* apricot.c: An Apricot 82596 ethernet driver for linux. */
-/*
- Apricot
- Written 1994 by Mark Evans.
- This driver is for the Apricot 82596 bus-master interface
-
- Modularised 12/94 Mark Evans
-
- Driver skeleton
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU Public License as modified by SRC,
- incorporated herein by reference.
-
- The author may be reached as becker@super.org or
- C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-
-
-*/
-
-static const char *version = "apricot.c:v0.2 05/12/94\n";
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#ifndef HAVE_PORTRESERVE
-#define check_region(addr, size) 0
-#define request_region(addr, size,name) do ; while(0)
-#endif
-
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff,size)
-#endif
-
-#define APRICOT_DEBUG 1
-
-#ifdef APRICOT_DEBUG
-int i596_debug = APRICOT_DEBUG;
-#else
-int i596_debug = 1;
-#endif
-
-#define APRICOT_TOTAL_SIZE 17
-
-#define I596_NULL -1
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
-
-#define STAT_C 0x8000 /* Set to 0 after execution */
-#define STAT_B 0x4000 /* Command being executed */
-#define STAT_OK 0x2000 /* Command executed ok */
-#define STAT_A 0x1000 /* Command aborted */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-struct i596_cmd {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *next;
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- struct i596_tbd *next;
- char *data;
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- struct i596_tbd *tbd;
- unsigned short size;
- unsigned short pad;
-};
-
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- struct i596_rfd *next;
- long rbd;
- unsigned short count;
- unsigned short size;
- char data[1532];
-};
-
-#define RX_RING_SIZE 8
-
-struct i596_scb {
- unsigned short status;
- unsigned short command;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- unsigned long crc_err;
- unsigned long align_err;
- unsigned long resource_err;
- unsigned long over_err;
- unsigned long rcvdt_err;
- unsigned long short_err;
- unsigned short t_on;
- unsigned short t_off;
-};
-
-struct i596_iscp {
- unsigned long stat;
- struct i596_scb *scb;
-};
-
-struct i596_scp {
- unsigned long sysbus;
- unsigned long pad;
- struct i596_iscp *iscp;
-};
-
-struct i596_private {
- struct i596_scp scp;
- struct i596_iscp iscp;
- struct i596_scb scb;
- struct i596_cmd set_add;
- char eth_addr[8];
- struct i596_cmd set_conf;
- char i596_config[16];
- struct i596_cmd tdr;
- unsigned long stat;
- int last_restart;
- struct i596_rfd *rx_tail;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- unsigned long last_cmd;
- struct net_device_stats stats;
-};
-
-char init_setup[] = {
- 0x8E, /* length, prefetch on */
- 0xC8, /* fifo to 8, monitor off */
- 0x80, /* don't save bad frames */
- 0x2E, /* No source address insertion, 8 byte preamble */
- 0x00, /* priority and backoff defaults */
- 0x60, /* interframe spacing */
- 0x00, /* slot time LSB */
- 0xf2, /* slot time and retries */
- 0x00, /* promiscuous mode */
- 0x00, /* collision detect */
- 0x40, /* minimum frame length */
- 0xff,
- 0x00,
- 0x7f /* *multi IA */ };
-
-static int i596_open(struct device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
-static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int i596_close(struct device *dev);
-static struct net_device_stats *i596_get_stats(struct device *dev);
-static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
-static void print_eth(char *);
-static void set_multicast_list(struct device *dev);
-
-
-static inline int
-init_rx_bufs(struct device *dev, int num)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int i;
- struct i596_rfd *rfd;
-
- lp->scb.rfd = (struct i596_rfd *)I596_NULL;
-
- if (i596_debug > 1) printk ("%s: init_rx_bufs %d.\n", dev->name, num);
-
- for (i = 0; i < num; i++)
- {
- if (!(rfd = (struct i596_rfd *)kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
- break;
-
- rfd->stat = 0x0000;
- rfd->rbd = I596_NULL;
- rfd->count = 0;
- rfd->size = 1532;
- if (i == 0)
- {
- rfd->cmd = CMD_EOL;
- lp->rx_tail = rfd;
- }
- else
- rfd->cmd = 0x0000;
-
- rfd->next = lp->scb.rfd;
- lp->scb.rfd = rfd;
- }
-
- if (i != 0)
- lp->rx_tail->next = lp->scb.rfd;
-
- return (i);
-}
-
-static inline void
-remove_rx_bufs(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- struct i596_rfd *rfd = lp->scb.rfd;
-
- lp->rx_tail->next = (struct i596_rfd *)I596_NULL;
-
- do
- {
- lp->scb.rfd = rfd->next;
- kfree(rfd);
- rfd = lp->scb.rfd;
- }
- while (rfd != lp->rx_tail);
-}
-
-static inline void
-init_i596_mem(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- short ioaddr = dev->base_addr;
- int boguscnt = 100;
-
- /* change the scp address */
- outw(0, ioaddr);
- outw(0, ioaddr);
- outb(4, ioaddr+0xf);
- outw(((((int)&lp->scp) & 0xffff) | 2), ioaddr);
- outw((((int)&lp->scp)>>16) & 0xffff, ioaddr);
-
- lp->last_cmd = jiffies;
-
- lp->scp.sysbus = 0x00440000;
- lp->scp.iscp = &(lp->iscp);
- lp->iscp.scb = &(lp->scb);
- lp->iscp.stat = 0x0001;
- lp->cmd_backlog = 0;
-
- lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
-
- if (i596_debug > 2) printk("%s: starting i82596.\n", dev->name);
-
- (void) inb (ioaddr+0x10);
- outb(4, ioaddr+0xf);
- outw(0, ioaddr+4);
-
- while (lp->iscp.stat)
- if (--boguscnt == 0)
- {
- printk("%s: i82596 initialization timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.command = 0;
-
- memcpy (lp->i596_config, init_setup, 14);
- lp->set_conf.command = CmdConfigure;
- i596_add_cmd(dev, &lp->set_conf);
-
- memcpy (lp->eth_addr, dev->dev_addr, 6);
- lp->set_add.command = CmdSASetup;
- i596_add_cmd(dev, &lp->set_add);
-
- lp->tdr.command = CmdTDR;
- i596_add_cmd(dev, &lp->tdr);
-
- boguscnt = 200;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: receive unit start timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.command = RX_START;
- outw(0, ioaddr+4);
-
- boguscnt = 200;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i82596 init timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- return;
-}
-
-static inline int
-i596_rx(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int frames = 0;
-
- if (i596_debug > 3) printk ("i596_rx()\n");
-
- while ((lp->scb.rfd->stat) & STAT_C)
- {
- if (i596_debug >2) print_eth(lp->scb.rfd->data);
-
- if ((lp->scb.rfd->stat) & STAT_OK)
- {
- /* a good frame */
- int pkt_len = lp->scb.rfd->count & 0x3fff;
- struct sk_buff *skb = dev_alloc_skb(pkt_len);
-
- frames++;
-
- if (skb == NULL)
- {
- printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
- break;
- }
-
- skb->dev = dev;
- memcpy(skb_put(skb,pkt_len), lp->scb.rfd->data, pkt_len);
-
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
-
- if (i596_debug > 4) print_eth(skb->data);
- }
- else
- {
- lp->stats.rx_errors++;
- if ((lp->scb.rfd->stat) & 0x0001) lp->stats.collisions++;
- if ((lp->scb.rfd->stat) & 0x0080) lp->stats.rx_length_errors++;
- if ((lp->scb.rfd->stat) & 0x0100) lp->stats.rx_over_errors++;
- if ((lp->scb.rfd->stat) & 0x0200) lp->stats.rx_fifo_errors++;
- if ((lp->scb.rfd->stat) & 0x0400) lp->stats.rx_frame_errors++;
- if ((lp->scb.rfd->stat) & 0x0800) lp->stats.rx_crc_errors++;
- if ((lp->scb.rfd->stat) & 0x1000) lp->stats.rx_length_errors++;
- }
-
- lp->scb.rfd->stat = 0;
- lp->rx_tail->cmd = 0;
- lp->rx_tail = lp->scb.rfd;
- lp->scb.rfd = lp->scb.rfd->next;
- lp->rx_tail->count = 0;
- lp->rx_tail->cmd = CMD_EOL;
-
- }
-
- if (i596_debug > 3) printk ("frames %d\n", frames);
-
- return 0;
-}
-
-static inline void
-i596_cleanup_cmd(struct i596_private *lp)
-{
- struct i596_cmd *ptr;
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_cleanup_cmd\n");
-
- while (lp->cmd_head != (struct i596_cmd *) I596_NULL)
- {
- ptr = lp->cmd_head;
-
- lp->cmd_head = lp->cmd_head->next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7)
- {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
-
- dev_kfree_skb(skb);
-
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
-
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(tx_cmd);
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(ptr);
- break;
- }
- default:
- ptr->next = (struct i596_cmd * ) I596_NULL;
- }
- }
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_cleanup_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.cmd = lp->cmd_head;
-}
-
-static inline void
-i596_reset(struct device *dev, struct i596_private *lp, int ioaddr)
-{
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_reset\n");
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_reset timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- dev->start = 0;
- dev->tbusy = 1;
-
- lp->scb.command = CUC_ABORT|RX_ABORT;
- outw(0, ioaddr+4);
-
- /* wait for shutdown */
- boguscnt = 400;
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_reset 2 timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- i596_cleanup_cmd(lp);
- i596_rx(dev);
-
- dev->start = 1;
- dev->tbusy = 0;
- dev->interrupt = 0;
- init_i596_mem(dev);
-}
-
-static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int ioaddr = dev->base_addr;
- unsigned long flags;
- int boguscnt = 100;
-
- if (i596_debug > 4) printk ("i596_add_cmd\n");
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL|CMD_INTR);
- cmd->next = (struct i596_cmd *) I596_NULL;
-
- save_flags(flags);
- cli();
- if (lp->cmd_head != (struct i596_cmd *) I596_NULL)
- lp->cmd_tail->next = cmd;
- else
- {
- lp->cmd_head = cmd;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("i596_add_cmd timed out with status %4.4x, cmd %4.4x.\n",
- lp->scb.status, lp->scb.command);
- break;
- }
-
- lp->scb.cmd = cmd;
- lp->scb.command = CUC_START;
- outw (0, ioaddr+4);
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- lp->cmd_head = lp->scb.cmd;
- restore_flags(flags);
-
- if (lp->cmd_backlog > 16)
- {
- int tickssofar = jiffies - lp->last_cmd;
-
- if (tickssofar < 25) return;
-
- printk("%s: command unit timed out, status resetting.\n", dev->name);
-
- i596_reset(dev, lp, ioaddr);
- }
-}
-
-static int
-i596_open(struct device *dev)
-{
- int i;
-
- if (i596_debug > 1)
- printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
-
- if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev))
- return -EAGAIN;
-
- i = init_rx_bufs(dev, RX_RING_SIZE);
-
- if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
- printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
-
- if (i < 4)
- {
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
-
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
- MOD_INC_USE_COUNT;
-
- /* Initialize the 82596 memory */
- init_i596_mem(dev);
-
- return 0; /* Always succeed */
-}
-
-static int
-i596_start_xmit(struct sk_buff *skb, struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int ioaddr = dev->base_addr;
- struct tx_cmd *tx_cmd;
-
- if (i596_debug > 2) printk ("%s: Apricot start xmit\n", dev->name);
-
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, status resetting.\n",
- dev->name);
- lp->stats.tx_errors++;
- /* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
- if (i596_debug > 1) printk ("Resetting board.\n");
-
- /* Shutdown and restart */
- i596_reset(dev,lp, ioaddr);
- } else {
- /* Issue a channel attention signal */
- if (i596_debug > 1) printk ("Kicking board.\n");
-
- lp->scb.command = CUC_START|RX_START;
- outw(0, ioaddr+4);
-
- lp->last_restart = lp->stats.tx_packets;
- }
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
-
- if (i596_debug > 3) printk("%s: i596_start_xmit() called\n", dev->name);
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else
- {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- dev->trans_start = jiffies;
-
- tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
- if (tx_cmd == NULL)
- {
- printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.tx_dropped++;
-
- dev_kfree_skb(skb);
- }
- else
- {
- tx_cmd->tbd = (struct i596_tbd *) (tx_cmd + 1);
- tx_cmd->tbd->next = (struct i596_tbd *) I596_NULL;
-
- tx_cmd->cmd.command = CMD_FLEX|CmdTx;
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tx_cmd->tbd->pad = 0;
- tx_cmd->tbd->size = EOF | length;
-
- tx_cmd->tbd->data = skb->data;
-
- if (i596_debug > 3) print_eth(skb->data);
-
- i596_add_cmd(dev, (struct i596_cmd *)tx_cmd);
-
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=length;
- }
- }
-
- dev->tbusy = 0;
-
- return 0;
-}
-
-
-static void print_eth(char *add)
-{
- int i;
-
- printk ("Dest ");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char)add[i]);
- printk ("\n");
-
- printk ("Source");
- for (i = 0; i < 6; i++)
- printk(" %2.2X", (unsigned char)add[i+6]);
- printk ("\n");
- printk ("type %2.2X%2.2X\n", (unsigned char)add[12], (unsigned char)add[13]);
-}
-
-__initfunc(int apricot_probe(struct device *dev))
-{
- int i;
- struct i596_private *lp;
- int checksum = 0;
- int ioaddr = 0x300;
- char eth_addr[6];
-
- /* this is easy the ethernet interface can only be at 0x300 */
- /* first check nothing is already registered here */
-
- if (check_region(ioaddr, APRICOT_TOTAL_SIZE))
- return ENODEV;
-
- for (i = 0; i < 8; i++)
- {
- eth_addr[i] = inb(ioaddr+8+i);
- checksum += eth_addr[i];
- }
-
- /* checksum is a multiple of 0x100, got this wrong first time
- some machines have 0x100, some 0x200. The DOS driver doesn't
- even bother with the checksum */
-
- if (checksum % 0x100) return ENODEV;
-
- /* Some other boards trip the checksum.. but then appear as ether
- address 0. Trap these - AC */
-
- if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0)
- return ENODEV;
-
- request_region(ioaddr, APRICOT_TOTAL_SIZE, "apricot");
-
- dev->base_addr = ioaddr;
- ether_setup(dev);
- printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr);
-
- for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
-
- dev->base_addr = ioaddr;
- dev->irq = 10;
- printk(" IRQ %d.\n", dev->irq);
-
- if (i596_debug > 0) printk(version);
-
- /* The APRICOT-specific entries in the device structure. */
- dev->open = &i596_open;
- dev->stop = &i596_close;
- dev->hard_start_xmit = &i596_start_xmit;
- dev->get_stats = &i596_get_stats;
- dev->set_multicast_list = &set_multicast_list;
-
- dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL);
- /* align for scp */
- dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
-
- lp = (struct i596_private *)dev->priv;
- memset((void *)lp, 0, sizeof(struct i596_private));
- lp->scb.command = 0;
- lp->scb.cmd = (struct i596_cmd *) I596_NULL;
- lp->scb.rfd = (struct i596_rfd *)I596_NULL;
-
- return 0;
-}
-
-static void
-i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct device *dev = dev_id;
- struct i596_private *lp;
- short ioaddr;
- int boguscnt = 200;
- unsigned short status, ack_cmd = 0;
-
- if (dev == NULL) {
- printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- if (i596_debug > 3) printk ("%s: i596_interrupt(): irq %d\n",dev->name, irq);
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = 1;
-
- ioaddr = dev->base_addr;
-
- lp = (struct i596_private *)dev->priv;
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- status = lp->scb.status;
-
- if (i596_debug > 4)
- printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status);
-
- ack_cmd = status & 0xf000;
-
- if ((status & 0x8000) || (status & 0x2000))
- {
- struct i596_cmd *ptr;
-
- if ((i596_debug > 4) && (status & 0x8000))
- printk("%s: i596 interrupt completed command.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x2000))
- printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
-
- while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C))
- {
- ptr = lp->cmd_head;
-
- lp->cmd_head = lp->cmd_head->next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7)
- {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1;
-
- dev_kfree_skb(skb);
-
- if ((ptr->status) & STAT_OK)
- {
- if (i596_debug >2) print_eth(skb->data);
- }
- else
- {
- lp->stats.tx_errors++;
- if ((ptr->status) & 0x0020) lp->stats.collisions++;
- if (!((ptr->status) & 0x0040)) lp->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400) lp->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800) lp->stats.collisions++;
- if ((ptr->status) & 0x1000) lp->stats.tx_aborted_errors++;
- }
-
-
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(tx_cmd);
- break;
- }
- case CmdMulticastList:
- {
- ptr->next = (struct i596_cmd * ) I596_NULL;
- kfree(ptr);
- break;
- }
- case CmdTDR:
- {
- unsigned long status = *((unsigned long *) (ptr + 1));
-
- if (status & 0x8000)
- {
- if (i596_debug > 3)
- printk("%s: link ok.\n", dev->name);
- }
- else
- {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n", dev->name);
-
- printk("%s: Time %ld.\n", dev->name, status & 0x07ff);
- }
- }
- default:
- ptr->next = (struct i596_cmd * ) I596_NULL;
-
- lp->last_cmd = jiffies;
- }
- }
-
- ptr = lp->cmd_head;
- while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail))
- {
- ptr->command &= 0x1fff;
- ptr = ptr->next;
- }
-
- if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd |= CUC_START;
- lp->scb.cmd = lp->cmd_head;
- }
-
- if ((status & 0x1000) || (status & 0x4000))
- {
- if ((i596_debug > 4) && (status & 0x4000))
- printk("%s: i596 interrupt received a frame.\n", dev->name);
- if ((i596_debug > 4) && (status & 0x1000))
- printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x0070);
-
- i596_rx(dev);
-
- if (dev->start) ack_cmd |= RX_START;
- }
-
- /* acknowledge the interrupt */
-
-/*
- if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START;
-*/
- boguscnt = 100;
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- lp->scb.command = ack_cmd;
-
- (void) inb (ioaddr+0x10);
- outb (4, ioaddr+0xf);
- outw (0, ioaddr+4);
-
- if (i596_debug > 4)
- printk("%s: exiting interrupt.\n", dev->name);
-
- dev->interrupt = 0;
- return;
-}
-
-static int
-i596_close(struct device *dev)
-{
- int ioaddr = dev->base_addr;
- struct i596_private *lp = (struct i596_private *)dev->priv;
- int boguscnt = 200;
-
- dev->start = 0;
- dev->tbusy = 1;
-
- if (i596_debug > 1)
- printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status);
-
- lp->scb.command = CUC_ABORT|RX_ABORT;
- outw(0, ioaddr+4);
-
- i596_cleanup_cmd(lp);
-
- while (lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: close timed timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-static struct net_device_stats *
-i596_get_stats(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
-
- return &lp->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct device *dev)
-{
- struct i596_private *lp = (struct i596_private *)dev->priv;
- struct i596_cmd *cmd;
-
- if (i596_debug > 1)
- printk ("%s: set multicast list %d\n", dev->name, dev->mc_count);
-
- if (dev->mc_count > 0)
- {
- struct dev_mc_list *dmi;
- char *cp;
- cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC);
- if (cmd == NULL)
- {
- printk ("%s: set_multicast Memory squeeze.\n", dev->name);
- return;
- }
- cmd->command = CmdMulticastList;
- *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
- cp=((char *)(cmd + 1))+2;
- for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
- {
- memcpy(cp, dmi,6);
- cp+=6;
- }
- print_eth (((char *)(cmd + 1)) + 2);
- i596_add_cmd(dev, cmd);
- }
- else
- {
- if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL)
- return;
- if (dev->mc_count == 0 && !(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
- {
- if(dev->flags&IFF_ALLMULTI)
- dev->flags|=IFF_PROMISC;
- lp->i596_config[8] &= ~0x01;
- }
- else
- lp->i596_config[8] |= 0x01;
-
- i596_add_cmd(dev, &lp->set_conf);
- }
-}
-
-#ifdef HAVE_DEVLIST
-static unsigned int apricot_portlist[] __initdata = {0x300, 0};
-struct netdev_entry apricot_drv =
-{"apricot", apricot_probe, APRICOT_TOTAL_SIZE, apricot_portlist};
-#endif
-
-#ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_apricot = {
- devicename, /* device name inserted by /linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0x300, 10,
- 0, 0, 0, NULL, apricot_probe };
-
-static int io = 0x300;
-static int irq = 10;
-MODULE_PARM(irq, "i");
-
-int
-init_module(void)
-{
- dev_apricot.base_addr = io;
- dev_apricot.irq = irq;
- if (register_netdev(&dev_apricot) != 0)
- return -EIO;
- return 0;
-}
-
-void
-cleanup_module(void)
-{
- unregister_netdev(&dev_apricot);
- kfree((void*)dev_apricot.mem_start);
- dev_apricot.priv = NULL;
-
- /* If we don't do this, we can't re-insmod it later. */
- release_region(dev_apricot.base_addr, APRICOT_TOTAL_SIZE);
-}
-#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c apricot.c"
- * End:
- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov