/drivers/net/pcmcia/3c589_cs.c
C | 943 lines | 704 code | 138 blank | 101 comment | 109 complexity | 8d6a126f703bd9f1634aff2c6d59897d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*======================================================================
- A PCMCIA ethernet driver for the 3com 3c589 card.
- Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
- 3c589_cs.c 1.162 2001/10/13 00:08:50
- The network driver code is based on Donald Becker's 3c589 code:
- Written 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU General Public License,
- incorporated herein by reference.
- Donald Becker may be reached at becker@scyld.com
- Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
- ======================================================================*/
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #define DRV_NAME "3c589_cs"
- #define DRV_VERSION "1.162-ac"
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/ptrace.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include <linux/timer.h>
- #include <linux/interrupt.h>
- #include <linux/in.h>
- #include <linux/delay.h>
- #include <linux/ethtool.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/skbuff.h>
- #include <linux/if_arp.h>
- #include <linux/ioport.h>
- #include <linux/bitops.h>
- #include <linux/jiffies.h>
- #include <pcmcia/cistpl.h>
- #include <pcmcia/cisreg.h>
- #include <pcmcia/ciscode.h>
- #include <pcmcia/ds.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/system.h>
- /* To minimize the size of the driver source I only define operating
- constants if they are used several times. You'll need the manual
- if you want to understand driver details. */
- /* Offsets from base I/O address. */
- #define EL3_DATA 0x00
- #define EL3_TIMER 0x0a
- #define EL3_CMD 0x0e
- #define EL3_STATUS 0x0e
- #define EEPROM_READ 0x0080
- #define EEPROM_BUSY 0x8000
- #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
- /* The top five bits written to EL3_CMD are a command, the lower
- 11 bits are the parameter, if applicable. */
- enum c509cmd {
- TotalReset = 0<<11,
- SelectWindow = 1<<11,
- StartCoax = 2<<11,
- RxDisable = 3<<11,
- RxEnable = 4<<11,
- RxReset = 5<<11,
- RxDiscard = 8<<11,
- TxEnable = 9<<11,
- TxDisable = 10<<11,
- TxReset = 11<<11,
- FakeIntr = 12<<11,
- AckIntr = 13<<11,
- SetIntrEnb = 14<<11,
- SetStatusEnb = 15<<11,
- SetRxFilter = 16<<11,
- SetRxThreshold = 17<<11,
- SetTxThreshold = 18<<11,
- SetTxStart = 19<<11,
- StatsEnable = 21<<11,
- StatsDisable = 22<<11,
- StopCoax = 23<<11
- };
- enum c509status {
- IntLatch = 0x0001,
- AdapterFailure = 0x0002,
- TxComplete = 0x0004,
- TxAvailable = 0x0008,
- RxComplete = 0x0010,
- RxEarly = 0x0020,
- IntReq = 0x0040,
- StatsFull = 0x0080,
- CmdBusy = 0x1000
- };
- /* The SetRxFilter command accepts the following classes: */
- enum RxFilter {
- RxStation = 1,
- RxMulticast = 2,
- RxBroadcast = 4,
- RxProm = 8
- };
- /* Register window 1 offsets, the window used in normal operation. */
- #define TX_FIFO 0x00
- #define RX_FIFO 0x00
- #define RX_STATUS 0x08
- #define TX_STATUS 0x0B
- #define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
- #define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
- #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
- #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
- #define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */
- /* Time in jiffies before concluding Tx hung */
- #define TX_TIMEOUT ((400*HZ)/1000)
- struct el3_private {
- struct pcmcia_device *p_dev;
- /* For transceiver monitoring */
- struct timer_list media;
- u16 media_status;
- u16 fast_poll;
- unsigned long last_irq;
- spinlock_t lock;
- };
- static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
- /*====================================================================*/
- /* Module parameters */
- MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
- MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
- MODULE_LICENSE("GPL");
- #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
- /* Special hook for setting if_port when module is loaded */
- INT_MODULE_PARM(if_port, 0);
- /*====================================================================*/
- static int tc589_config(struct pcmcia_device *link);
- static void tc589_release(struct pcmcia_device *link);
- static u16 read_eeprom(unsigned int ioaddr, int index);
- static void tc589_reset(struct net_device *dev);
- static void media_check(unsigned long arg);
- static int el3_config(struct net_device *dev, struct ifmap *map);
- static int el3_open(struct net_device *dev);
- static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
- static irqreturn_t el3_interrupt(int irq, void *dev_id);
- static void update_stats(struct net_device *dev);
- static struct net_device_stats *el3_get_stats(struct net_device *dev);
- static int el3_rx(struct net_device *dev);
- static int el3_close(struct net_device *dev);
- static void el3_tx_timeout(struct net_device *dev);
- static void set_rx_mode(struct net_device *dev);
- static void set_multicast_list(struct net_device *dev);
- static const struct ethtool_ops netdev_ethtool_ops;
- static void tc589_detach(struct pcmcia_device *p_dev);
- static const struct net_device_ops el3_netdev_ops = {
- .ndo_open = el3_open,
- .ndo_stop = el3_close,
- .ndo_start_xmit = el3_start_xmit,
- .ndo_tx_timeout = el3_tx_timeout,
- .ndo_set_config = el3_config,
- .ndo_get_stats = el3_get_stats,
- .ndo_set_multicast_list = set_multicast_list,
- .ndo_change_mtu = eth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- };
- static int tc589_probe(struct pcmcia_device *link)
- {
- struct el3_private *lp;
- struct net_device *dev;
- dev_dbg(&link->dev, "3c589_attach()\n");
- /* Create new ethernet device */
- dev = alloc_etherdev(sizeof(struct el3_private));
- if (!dev)
- return -ENOMEM;
- lp = netdev_priv(dev);
- link->priv = dev;
- lp->p_dev = link;
- spin_lock_init(&lp->lock);
- link->resource[0]->end = 16;
- link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
- link->config_flags |= CONF_ENABLE_IRQ;
- link->config_index = 1;
- dev->netdev_ops = &el3_netdev_ops;
- dev->watchdog_timeo = TX_TIMEOUT;
- SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
- return tc589_config(link);
- }
- static void tc589_detach(struct pcmcia_device *link)
- {
- struct net_device *dev = link->priv;
- dev_dbg(&link->dev, "3c589_detach\n");
- unregister_netdev(dev);
- tc589_release(link);
- free_netdev(dev);
- } /* tc589_detach */
- static int tc589_config(struct pcmcia_device *link)
- {
- struct net_device *dev = link->priv;
- __be16 *phys_addr;
- int ret, i, j, multi = 0, fifo;
- unsigned int ioaddr;
- static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
- u8 *buf;
- size_t len;
- dev_dbg(&link->dev, "3c589_config\n");
-