📄 3c527.c
字号:
/* 3c527.c: 3Com Etherlink/MC32 driver for Linux * * (c) Copyright 1998 Red Hat Software Inc * Written by Alan Cox. * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. * * Thanks to 3Com for making this possible by providing me with the * documentation. * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * */static const char *version = "3c527.c:v0.04 1999/03/16 Alan Cox (alan@redhat.com)\n";/* * Things you need * o The databook. * * Traps for the unwary * * The diagram (Figure 1-1) and the POS summary disagree with the * "Interrupt Level" section in the manual. * * The documentation in places seems to miss things. In actual fact * I've always eventually found everything is documented, it just * requires careful study. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/mca.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include "3c527.h"/* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels */static const char* cardname = "3c527";/* use 0 for production, 1 for verification, >2 for debug */#ifndef NET_DEBUG#define NET_DEBUG 2#endifstatic unsigned int mc32_debug = NET_DEBUG;/* The number of low I/O ports used by the ethercard. */#define NETCARD_IO_EXTENT 8struct mc32_mailbox{ u16 mbox __attribute((packed)); u16 data[1] __attribute((packed));};/* Information that need to be kept for each board. */#define TX_RING_MAX 16 /* Typically the card supports 37 */#define RX_RING_MAX 32 /* " " " */struct mc32_local { struct net_device_stats net_stats; int slot; volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; volatile u16 *stats; u16 tx_chain; u16 rx_chain; u16 tx_len; u16 rx_len; u32 base; u16 rx_halted; u16 tx_halted; u16 exec_pending; u16 mc_reload_wait; /* a multicast load request is pending */ atomic_t tx_count; /* buffers left */ struct wait_queue *event; struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ u16 tx_skb_top; u16 tx_skb_end; struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ void *rx_ptr[RX_RING_MAX]; /* Data pointers */};/* The station (ethernet) address prefix, used for a sanity check. */#define SA_ADDR0 0x02#define SA_ADDR1 0x60#define SA_ADDR2 0xACstruct mca_adapters_t { unsigned int id; char *name;};const struct mca_adapters_t mc32_adapters[] = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL }};/* Index to functions, as function prototypes. */extern int mc32_probe(struct device *dev);static int mc32_probe1(struct device *dev, int ioaddr);static int mc32_open(struct device *dev);static int mc32_send_packet(struct sk_buff *skb, struct device *dev);static void mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int mc32_close(struct device *dev);static struct net_device_stats *mc32_get_stats(struct device *dev);static void mc32_set_multicast_list(struct device *dev);/* * Check for a network adaptor of this type, and return '0' iff one exists. * If dev->base_addr == 0, probe all likely locations. * If dev->base_addr == 1, always return failure. * If dev->base_addr == 2, allocate space for the device and return success * (detachable devices only). */__initfunc(int mc32_probe(struct device *dev)){ static int current_mca_slot = -1; int i; int adapter_found = 0; /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ /* MCA cards have POS registers. Autodetecting MCA cards is extremely simple. Just search for the card. */ for(i = 0; (mc32_adapters[i].name != NULL) && !adapter_found; i++) { current_mca_slot = mca_find_unused_adapter(mc32_adapters[i].id, 0); if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) { if(!mc32_probe1(dev, current_mca_slot)) { mca_set_adapter_name(current_mca_slot, mc32_adapters[i].name); mca_mark_as_used(current_mca_slot); return 0; } } } return -ENODEV;}/* * This is the real probe routine. Linux has a history of friendly device * probes on the ISA bus. A good device probes avoids doing writes, and * verifies that the correct device exists and functions. */__initfunc(static int mc32_probe1(struct device *dev, int slot)){ static unsigned version_printed = 0; int i; u8 POS; u32 base; struct mc32_local *lp; static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, 0x7A80,0x7A90, 0x7E80,0x7E90 }; static u32 mca_mem_bases[]={ 0x00C0000, 0x00C4000, 0x00C8000, 0x00CC000, 0x00D0000, 0x00D4000, 0x00D8000, 0x00DC000 }; static char *failures[]={ "Processor instruction", "Processor data bus", "Processor data bus", "Processor data bus", "Adapter bus", "ROM checksum", "Base RAM", "Extended RAM", "82586 internal loopback", "82586 initialisation failure", "Adapter list configuration error" }; /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot); POS = mca_read_stored_pos(slot, 2); if(!(POS&1)) { printk(" disabled.\n"); return -ENODEV; } /* Allocate a new 'dev' if needed. */ if (dev == NULL) { /* * Don't allocate the private data here, it is done later * This makes it easier to free the memory when this driver * is used as a module. */ dev = init_etherdev(0, 0); if (dev == NULL) return -ENOMEM; } /* Fill in the 'dev' fields. */ dev->base_addr = mca_io_bases[(POS>>1)&7]; dev->mem_start = mca_mem_bases[(POS>>4)&7]; POS = mca_read_stored_pos(slot, 4); if(!(POS&1)) { printk("memory window disabled.\n"); return -ENODEV; } POS = mca_read_stored_pos(slot, 5); i=(POS>>4)&3; if(i==3) { printk("invalid memory window.\n"); return -ENODEV; } i*=16384; i+=16384; dev->mem_end=dev->mem_start + i; dev->irq = ((POS>>2)&3)+9; printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); /* We ought to set the cache line size here.. */ /* * Go PROM browsing */ printk("%s: Address ", dev->name); /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) { mca_write_pos(slot, 6, i+12); mca_write_pos(slot, 7, 0); printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3)); } mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); POS = mca_read_stored_pos(slot, 4); if(POS&2) printk(" : BNC port selected.\n"); else printk(" : AUI port selected.\n"); POS=inb(dev->base_addr+HOST_CTRL); POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; POS&=~HOST_CTRL_INTE; outb(POS, dev->base_addr+HOST_CTRL); /* Reset adapter */ udelay(100); /* Reset off */ POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET); outb(POS, dev->base_addr+HOST_CTRL); udelay(300); /* * Grab the IRQ */ if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev)) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); if (dev->priv == NULL) { free_irq(dev->irq, dev); return -ENOMEM; } } memset(dev->priv, 0, sizeof(struct mc32_local)); lp = (struct mc32_local *)dev->priv; lp->slot = slot; i=0; base = inb(dev->base_addr); while(base==0xFF) { i++; if(i==1000) { printk("%s: failed to boot adapter.\n", dev->name); free_irq(dev->irq, dev); return -ENODEV; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) base = inb(dev->base_addr); } if(base>0) { if(base < 0x0C) printk("%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else printk("%s: unknown failure %d.\n", dev->name, base); free_irq(dev->irq, dev); return -ENODEV; } base=0; for(i=0;i<4;i++) { int n=0; while(!(inb(dev->base_addr+2)&(1<<5))) { n++; udelay(50); if(n>100) { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); free_irq(dev->irq, dev); return -ENODEV; } } base|=(inb(dev->base_addr)<<(8*i)); } lp->exec_box=bus_to_virt(dev->mem_start+base); base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; lp->base = dev->mem_start+base; lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]); lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]); /* * Descriptor chains (card relative) */ lp->tx_chain = lp->exec_box->data[8]; lp->rx_chain = lp->exec_box->data[10]; lp->tx_len = lp->exec_box->data[9]; lp->rx_len = lp->exec_box->data[11]; printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->rx_len, lp->tx_len, lp->base); dev->open = mc32_open; dev->stop = mc32_close; dev->hard_start_xmit = mc32_send_packet; dev->get_stats = mc32_get_stats; dev->set_multicast_list = mc32_set_multicast_list; lp->rx_halted = 1; lp->tx_halted = 1; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); return 0;}/* * Polled command stuff */ static void mc32_ring_poll(struct device *dev){ int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));}/* * Send exec commands */ static int mc32_command(struct device *dev, u16 cmd, void *data, int len){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; while(lp->exec_pending) sleep_on(&lp->event); lp->exec_pending=1; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); save_flags(flags); cli(); while(lp->exec_pending!=2) sleep_on(&lp->event); lp->exec_pending=0; restore_flags(flags); /* * A multicast set got blocked - do it now */ if(lp->mc_reload_wait) mc32_set_multicast_list(dev); if(lp->exec_box->data[0]&(1<<13)) return -1; return 0;}/* * RX abort */ static void mc32_rx_abort(struct device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */} /* * RX enable */ static void mc32_rx_begin(struct device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; outb(1<<3, ioaddr+HOST_CMD); /* GO */ mc32_ring_poll(dev); lp->rx_halted=0;}static void mc32_tx_abort(struct device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0; outb(3, ioaddr+HOST_CMD); /* Suspend */ /* Ring empty */ atomic_set(&lp->tx_count, lp->tx_len); /* Flush */ if(lp->tx_skb_top!=lp->tx_skb_end) { int i; if(lp->tx_skb_top<=lp->tx_skb_end) { for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } } else { for(i=lp->tx_skb_end;i<TX_RING_MAX;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } for(i=0;i<lp->tx_skb_top;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } } } lp->tx_skb_top=lp->tx_skb_end=0;}/* * TX enable */ static void mc32_tx_begin(struct device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0;#if 0 outb(5, ioaddr+HOST_CMD); /* GO */ printk("TX=>5\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -