16df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden/* ====================================================================== 26df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 36df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * A PCMCIA ethernet driver for the 3com 3c589 card. 46df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 56df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net 66df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 76df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 3c589_cs.c 1.162 2001/10/13 00:08:50 86df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 96df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * The network driver code is based on Donald Becker's 3c589 code: 106df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Written 1994 by Donald Becker. 126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Copyright 1993 United States Government as represented by the 136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Director, National Security Agency. This software may be used and 146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * distributed according to the terms of the GNU General Public License, 156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * incorporated herein by reference. 166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Donald Becker may be reached at becker@scyld.com 176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> 196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * ====================================================================== 216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 24636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME "3c589_cs" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_VERSION "1.162-ac" 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 44ff5688ae1cedfb175b5ed0f319d03ad2e5ee005dMarcelo Feitoza Parisi#include <linux/jiffies.h> 456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden#include <linux/uaccess.h> 466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden#include <linux/io.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ciscode.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* To minimize the size of the driver source I only define operating 556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * constants if they are used several times. You'll need the manual 566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * if you want to understand driver details. 576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Offsets from base I/O address. */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_DATA 0x00 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_TIMER 0x0a 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_CMD 0x0e 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_STATUS 0x0e 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_READ 0x0080 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_BUSY 0x8000 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The top five bits written to EL3_CMD are a command, the lower 716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * 11 bits are the parameter, if applicable. 726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum c509cmd { 75f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TotalReset = 0<<11, 76f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SelectWindow = 1<<11, 77f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz StartCoax = 2<<11, 78f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxDisable = 3<<11, 79f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxEnable = 4<<11, 80f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxReset = 5<<11, 81f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxDiscard = 8<<11, 82f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TxEnable = 9<<11, 83f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TxDisable = 10<<11, 84f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TxReset = 11<<11, 85f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz FakeIntr = 12<<11, 86f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz AckIntr = 13<<11, 87f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetIntrEnb = 14<<11, 88f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetStatusEnb = 15<<11, 89f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetRxFilter = 16<<11, 90f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetRxThreshold = 17<<11, 91f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetTxThreshold = 18<<11, 92f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz SetTxStart = 19<<11, 93f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz StatsEnable = 21<<11, 94f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz StatsDisable = 22<<11, 95f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz StopCoax = 23<<11 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum c509status { 99f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz IntLatch = 0x0001, 100f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz AdapterFailure = 0x0002, 101f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TxComplete = 0x0004, 102f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz TxAvailable = 0x0008, 103f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxComplete = 0x0010, 104f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxEarly = 0x0020, 105f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz IntReq = 0x0040, 106f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz StatsFull = 0x0080, 107f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz CmdBusy = 0x1000 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The SetRxFilter command accepts the following classes: */ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum RxFilter { 112f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxStation = 1, 113f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxMulticast = 2, 114f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxBroadcast = 4, 115f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz RxProm = 8 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register window 1 offsets, the window used in normal operation. */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_FIFO 0x00 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_FIFO 0x00 121f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz#define RX_STATUS 0x08 122f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz#define TX_STATUS 0x0B 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Time in jiffies before concluding Tx hung */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT ((400*HZ)/1000) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct el3_private { 134fd238232cd0ff4840ae6946bb338502154096d88Dominik Brodowski struct pcmcia_device *p_dev; 135f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz /* For transceiver monitoring */ 136f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz struct timer_list media; 137f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz u16 media_status; 138f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz u16 fast_poll; 139f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz unsigned long last_irq; 140f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz spinlock_t lock; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14321c0f275085e5b884a409d75a7deb73ece6477fbJeff Garzikstatic const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" }; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Module parameters */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver"); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Special hook for setting if_port when module is loaded */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsINT_MODULE_PARM(if_port, 0); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16115b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int tc589_config(struct pcmcia_device *link); 162fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void tc589_release(struct pcmcia_device *link); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 164906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johanssonstatic u16 read_eeprom(unsigned int ioaddr, int index); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tc589_reset(struct net_device *dev); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void media_check(unsigned long arg); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_config(struct net_device *dev, struct ifmap *map); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_open(struct net_device *dev); 169dbf02fae406daf4d583a279743869c686024c341Stephen Hemmingerstatic netdev_tx_t el3_start_xmit(struct sk_buff *skb, 170dbf02fae406daf4d583a279743869c686024c341Stephen Hemminger struct net_device *dev); 1717d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t el3_interrupt(int irq, void *dev_id); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stats(struct net_device *dev); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *el3_get_stats(struct net_device *dev); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_rx(struct net_device *dev); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_close(struct net_device *dev); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_tx_timeout(struct net_device *dev); 177e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasakistatic void set_rx_mode(struct net_device *dev); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev); 1797282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops netdev_ethtool_ops; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void tc589_detach(struct pcmcia_device *p_dev); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18397161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemmingerstatic const struct net_device_ops el3_netdev_ops = { 184f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz .ndo_open = el3_open, 185f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz .ndo_stop = el3_close, 18697161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger .ndo_start_xmit = el3_start_xmit, 187f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz .ndo_tx_timeout = el3_tx_timeout, 18897161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger .ndo_set_config = el3_config, 18997161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger .ndo_get_stats = el3_get_stats, 190afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 19197161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger .ndo_change_mtu = eth_change_mtu, 192f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz .ndo_set_mac_address = eth_mac_addr, 19397161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger .ndo_validate_addr = eth_validate_addr, 19497161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger}; 19597161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger 19615b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int tc589_probe(struct pcmcia_device *link) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1986df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp; 1996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct net_device *dev; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_dbg(&link->dev, "3c589_attach()\n"); 202f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski 2036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Create new ethernet device */ 2046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev = alloc_etherdev(sizeof(struct el3_private)); 2056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!dev) 2066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return -ENOMEM; 2076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp = netdev_priv(dev); 2086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->priv = dev; 2096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->p_dev = link; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_lock_init(&lp->lock); 2126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->resource[0]->end = 16; 2136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; 214eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski 2156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->config_flags |= CONF_ENABLE_IRQ; 2166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->config_index = 1; 217f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski 2186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->netdev_ops = &el3_netdev_ops; 2196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->watchdog_timeo = TX_TIMEOUT; 22097161d4b2a28857f217b2035b2141cbb36f22f8bStephen Hemminger 2217ad24ea4bf620a32631d7b3069c3e30c078b0c3eWilfried Klaebe dev->ethtool_ops = &netdev_ethtool_ops; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return tc589_config(link); 2242262054e74b4b26ed56a8535c1259f6c6c2862a4Dominik Brodowski} 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 226fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void tc589_detach(struct pcmcia_device *link) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2286df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct net_device *dev = link->priv; 229b463581154f3f3eecda27cae60df813fefcd84d3Dominik Brodowski 2306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_dbg(&link->dev, "3c589_detach\n"); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unregister_netdev(dev); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_release(link); 235cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski 2366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden free_netdev(dev); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* tc589_detach */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23915b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int tc589_config(struct pcmcia_device *link) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct net_device *dev = link->priv; 2426df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden __be16 *phys_addr; 2436df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int ret, i, j, multi = 0, fifo; 2446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr; 2456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; 2466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden u8 *buf; 2476df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden size_t len; 2486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_dbg(&link->dev, "3c589_config\n"); 2506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2516df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden phys_addr = (__be16 *)dev->dev_addr; 2526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Is this a 3c562? */ 2536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (link->manf_id != MANFID_3COM) 2546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); 2556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden multi = (link->card_id == PRODID_3COM_3C562); 2566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->io_lines = 16; 2586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* For the 3c562, the base address must be xx00-xx7f */ 2606df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = j = 0; j < 0x400; j += 0x10) { 2616df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (multi && (j & 0x80)) 2626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden continue; 2636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->resource[0]->start = j ^ 0x300; 2646df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden i = pcmcia_request_io(link); 2656df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (i == 0) 2666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2686df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (i != 0) 2696df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto failed; 2706df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden ret = pcmcia_request_irq(link, el3_interrupt); 2726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (ret) 2736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto failed; 2746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2756df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden ret = pcmcia_enable_device(link); 2766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (ret) 2776df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto failed; 2786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->irq = link->irq; 2806df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->base_addr = link->resource[0]->start; 2816df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden ioaddr = dev->base_addr; 2826df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(0); 2836df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 2846df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* The 3c589 has an extra EEPROM for configuration info, including 2856df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * the hardware address. The 3c562 puts the address in the CIS. 2866df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 2876df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden len = pcmcia_get_tuple(link, 0x88, &buf); 2886df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (buf && len >= 6) { 2896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 0; i < 3; i++) 2906df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden phys_addr[i] = htons(le16_to_cpu(buf[i*2])); 2916df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden kfree(buf); 2926df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else { 2936df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden kfree(buf); /* 0 < len < 6 */ 2946df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 0; i < 3; i++) 2956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden phys_addr[i] = htons(read_eeprom(ioaddr, i)); 2966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (phys_addr[0] == htons(0x6060)) { 2976df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", 2986df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->base_addr, dev->base_addr+15); 2996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto failed; 3006df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 3016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 3026df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* The address and resource configuration register aren't loaded from 3046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. 3056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 3066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0x3f00, ioaddr + 8); 3086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden fifo = inl(ioaddr); 3096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3106df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* The if_port symbol can be set when the module is loaded */ 3116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((if_port >= 0) && (if_port <= 3)) 3126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->if_port = if_port; 3136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else 3146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_err(&link->dev, "invalid if_port requested\n"); 3156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden SET_NETDEV_DEV(dev, &link->dev); 3176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (register_netdev(dev) != 0) { 3196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_err(&link->dev, "register_netdev() failed\n"); 3206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto failed; 3216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 3226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", 3246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden (multi ? "562" : "589"), dev->base_addr, dev->irq, 3256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->dev_addr); 3266df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", 3276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], 3286df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if_names[dev->if_port]); 3296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return 0; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed: 3326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_release(link); 3336df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return -ENODEV; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* tc589_config */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 336fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void tc589_release(struct pcmcia_device *link) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 338fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski pcmcia_disable_device(link); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic int tc589_suspend(struct pcmcia_device *link) 34298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 34398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski struct net_device *dev = link->priv; 34498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 345e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski if (link->open) 3468661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski netif_device_detach(dev); 34798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 34898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 34998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 35098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 351fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic int tc589_resume(struct pcmcia_device *link) 35298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{ 35398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski struct net_device *dev = link->priv; 35498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 355f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz if (link->open) { 3568661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski tc589_reset(dev); 3578661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski netif_device_attach(dev); 35898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski } 35998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 36098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski return 0; 36198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski} 36298e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3656df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden/* Use this for commands that may take time to finish */ 3666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tc589_wait_for_completion(struct net_device *dev, int cmd) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3696df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int i = 100; 3706df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(cmd, dev->base_addr + EL3_CMD); 3716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden while (--i > 0) 3726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) 3736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 3746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (i == 0) 3756df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden/* Read a word from the EEPROM using the regular EEPROM access register. 3796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * Assume that we are in register window zero. 3806df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 3816df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 382906da809c5be30b4c7f32bb6a489fb25ad794878Olof Johanssonstatic u16 read_eeprom(unsigned int ioaddr, int index) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3846df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int i; 3856df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(EEPROM_READ + index, ioaddr + 10); 3866df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Reading the eeprom takes 162 us */ 3876df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 1620; i >= 0; i--) 3886df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) 3896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 3906df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return inw(ioaddr + 12); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3936df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden/* Set transceiver type, perhaps to something other than what the user 3946df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * specified in dev->if_port. 3956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 3966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tc589_set_xcvr(struct net_device *dev, int if_port) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 4006df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 4016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4026df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(0); 4036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden switch (if_port) { 4046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0: 4056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 1: 4066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0, ioaddr + 6); 4076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 4086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 2: 4096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(3<<14, ioaddr + 6); 4106df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 4116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 3: 4126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(1<<14, ioaddr + 6); 4136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 4146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 4156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* On PCMCIA, this just turns on the LED */ 4166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); 4176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* 10baseT interface, enable link beat and jabber check. */ 4186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(4); 4196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); 4206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 4216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (if_port == 2) 4226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); 4236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else 4246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_status(struct net_device *dev) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 4306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 4316df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", 4326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), 4336df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); 4346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(4); 4356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", 4366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), 4376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr+0x0a)); 4386df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Reset and restore all of the 3c589 registers. */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tc589_reset(struct net_device *dev) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 4456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int i; 4466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4476df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(0); 4486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0x0001, ioaddr + 4); /* Activate board. */ 4496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ 4506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4516df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Set the station address in window 2. */ 4526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(2); 4536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 0; i < 6; i++) 4546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outb(dev->dev_addr[i], ioaddr + i); 4556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_set_xcvr(dev, dev->if_port); 4576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Switch to the stats window, and clear all stats by reading. */ 4596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsDisable, ioaddr + EL3_CMD); 4606df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(6); 4616df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 0; i < 9; i++) 4626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inb(ioaddr+i); 4636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr + 10); 4646df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr + 12); 4656df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Switch to register set 1 for normal use. */ 4676df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 4686df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 4696df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden set_rx_mode(dev); 4706df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ 4716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ 4726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ 4736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Allow status bits to be seen. */ 4746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); 4756df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Ack all pending events, and set active indicator mask. */ 4766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 4786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | AdapterFailure, ioaddr + EL3_CMD); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netdev_get_drvinfo(struct net_device *dev, 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ethtool_drvinfo *info) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 48568aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 48668aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 48768aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones snprintf(info->bus_info, sizeof(info->bus_info), 48868aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones "PCMCIA 0x%lx", dev->base_addr); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4917282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops netdev_ethtool_ops = { 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_drvinfo = netdev_get_drvinfo, 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_config(struct net_device *dev, struct ifmap *map) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4976df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { 4986df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (map->port <= 3) { 4996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->if_port = map->port; 5006df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); 5016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_set_xcvr(dev, dev->if_port); 5026df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else { 5036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return -EINVAL; 5046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 5056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 5066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return 0; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_open(struct net_device *dev) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 5126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct pcmcia_device *link = lp->p_dev; 513f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 5146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!pcmcia_dev_present(link)) 5156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return -ENODEV; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->open++; 5186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_start_queue(dev); 519f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 5206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_reset(dev); 5216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden init_timer(&lp->media); 5226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media.function = media_check; 5236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media.data = (unsigned long) dev; 5246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media.expires = jiffies + HZ; 5256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden add_timer(&lp->media); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, inw(dev->base_addr + EL3_STATUS)); 529f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 5306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return 0; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_tx_timeout(struct net_device *dev) 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 5366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 5376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_warn(dev, "Transmit timed out!\n"); 5386df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dump_status(dev); 5396df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_errors++; 5406df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->trans_start = jiffies; /* prevent tx timeout */ 5416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Issue TX_RESET and TX_START commands. */ 5426df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_wait_for_completion(dev, TxReset); 5436df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(TxEnable, ioaddr + EL3_CMD); 5446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_wake_queue(dev); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pop_tx_status(struct net_device *dev) 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 5506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int i; 5516df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 5526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Clear the Tx status stack. */ 5536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden for (i = 32; i > 0; i--) { 5546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden u_char tx_status = inb(ioaddr + TX_STATUS); 5556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!(tx_status & 0x84)) 5566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 5576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* reset transmitter on jabber error or underrun */ 5586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (tx_status & 0x30) 5596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_wait_for_completion(dev, TxReset); 5606df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (tx_status & 0x38) { 5616df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); 5626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(TxEnable, ioaddr + EL3_CMD); 5636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_aborted_errors++; 5646df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 5656df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 569dbf02fae406daf4d583a279743869c686024c341Stephen Hemmingerstatic netdev_tx_t el3_start_xmit(struct sk_buff *skb, 570dbf02fae406daf4d583a279743869c686024c341Stephen Hemminger struct net_device *dev) 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 5736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *priv = netdev_priv(dev); 5746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned long flags; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", 577f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz (long)skb->len, inw(ioaddr + EL3_STATUS)); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_lock_irqsave(&priv->lock, flags); 580d08d283974f96cb30d78ba24282a0a7d6709af32Komuro 5816df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_bytes += skb->len; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5836df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Put out the doubleword header... */ 5846df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(skb->len, ioaddr + TX_FIFO); 5856df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0x00, ioaddr + TX_FIFO); 5866df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* ... and the packet rounded to a doubleword. */ 5876df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (inw(ioaddr + TX_FREE) <= 1536) { 5906df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_stop_queue(dev); 5916df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Interrupt us when the FIFO has room for max-sized packet. */ 5926df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); 5936df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden pop_tx_status(dev); 5966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_unlock_irqrestore(&priv->lock, flags); 5976df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_kfree_skb(skb); 598f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 5996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return NETDEV_TX_OK; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The EL3 interrupt handler. */ 6037d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t el3_interrupt(int irq, void *dev_id) 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct net_device *dev = (struct net_device *) dev_id; 6066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 6076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr; 6086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden __u16 status; 6096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int i = 0, handled = 1; 610f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 6116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!netif_device_present(dev)) 6126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return IRQ_NONE; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden ioaddr = dev->base_addr; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_lock(&lp->lock); 6196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden while ((status = inw(ioaddr + EL3_STATUS)) & 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (IntLatch | RxComplete | StatsFull)) { 6216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((status & 0xe000) != 0x2000) { 6226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "interrupt from dead card\n"); 6236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden handled = 0; 6246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 6256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6266df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & RxComplete) 6276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden el3_rx(dev); 6286df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & TxAvailable) { 6296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, " TX room bit was handled.\n"); 6306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* There's room in the FIFO for a full-sized packet. */ 6316df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); 6326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_wake_queue(dev); 6336df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & TxComplete) 6356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden pop_tx_status(dev); 6366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & (AdapterFailure | RxEarly | StatsFull)) { 6376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Handle all uncommon interrupts. */ 6386df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & StatsFull) /* Empty statistics. */ 6396df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden update_stats(dev); 6406df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & RxEarly) { 6416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Rx early is unused. */ 6426df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden el3_rx(dev); 6436df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | RxEarly, ioaddr + EL3_CMD); 6446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (status & AdapterFailure) { 6466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden u16 fifo_diag; 6476df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(4); 6486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden fifo_diag = inw(ioaddr + 4); 6496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 6506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", 651f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz fifo_diag); 6526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (fifo_diag & 0x0400) { 6536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Tx overrun */ 6546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_wait_for_completion(dev, TxReset); 6556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(TxEnable, ioaddr + EL3_CMD); 6566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (fifo_diag & 0x2000) { 6586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Rx underrun */ 6596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_wait_for_completion(dev, RxReset); 6606df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden set_rx_mode(dev); 6616df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(RxEnable, ioaddr + EL3_CMD); 6626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); 6646df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (++i > 10) { 6676df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", 6686df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden status); 6696df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Clear all interrupts */ 6706df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | 0xFF, ioaddr + EL3_CMD); 6716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Acknowledge the IRQ. */ 6746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->last_irq = jiffies; 6776df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_unlock(&lp->lock); 6786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", 6796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr + EL3_STATUS)); 6806df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return IRQ_RETVAL(handled); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void media_check(unsigned long arg) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6856df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct net_device *dev = (struct net_device *)(arg); 6866df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 6876df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 6886df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden u16 media, errs; 6896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned long flags; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6916df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!netif_device_present(dev)) 6926df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden goto reschedule; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6946df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Check for pending interrupt with expired latency timer: with 6956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * this, we can limp along even if the interrupt is blocked 6966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 6976df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((inw(ioaddr + EL3_STATUS) & IntLatch) && 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (inb(ioaddr + EL3_TIMER) == 0xff)) { 6996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (!lp->fast_poll) 7006df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_warn(dev, "interrupt(s) dropped!\n"); 7016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7026df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden local_irq_save(flags); 7036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden el3_interrupt(dev->irq, dev); 7046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden local_irq_restore(flags); 7056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->fast_poll = HZ; 7076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (lp->fast_poll) { 7096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->fast_poll--; 7106df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media.expires = jiffies + HZ/100; 7116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden add_timer(&lp->media); 7126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return; 7136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* lp->lock guards the EL3 window. Window should always be 1 except 7166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden * when the lock is held 7176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden */ 7186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_lock_irqsave(&lp->lock, flags); 7206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(4); 7216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden media = inw(ioaddr+WN4_MEDIA) & 0xc810; 7226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Ignore collisions unless we've had no irq's recently */ 7246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (time_before(jiffies, lp->last_irq + HZ)) { 7256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden media &= ~0x0010; 7266df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else { 7276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Try harder to detect carrier errors */ 7286df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(6); 7296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsDisable, ioaddr + EL3_CMD); 7306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden errs = inb(ioaddr + 0); 7316df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsEnable, ioaddr + EL3_CMD); 7326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_carrier_errors += errs; 7336df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (errs || (lp->media_status & 0x0010)) 7346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden media |= 0x0010; 7356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (media != lp->media_status) { 7386df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((media & lp->media_status & 0x8000) && 7396df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden ((lp->media_status ^ media) & 0x0800)) 740f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz netdev_info(dev, "%s link beat\n", 7416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden (lp->media_status & 0x0800 ? "lost" : "found")); 7426df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else if ((media & lp->media_status & 0x4000) && 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((lp->media_status ^ media) & 0x0010)) 744f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz netdev_info(dev, "coax cable %s\n", 7456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden (lp->media_status & 0x0010 ? "ok" : "problem")); 7466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (dev->if_port == 0) { 7476df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (media & 0x8000) { 7486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (media & 0x0800) 7496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, "flipped to 10baseT\n"); 7506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else 751f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz tc589_set_xcvr(dev, 2); 7526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else if (media & 0x4000) { 7536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (media & 0x0010) 7546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_set_xcvr(dev, 1); 7556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else 7566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_info(dev, "flipped to 10base2\n"); 7576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media_status = media; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 761f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 7626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 7636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_unlock_irqrestore(&lp->lock, flags); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreschedule: 7666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden lp->media.expires = jiffies + HZ; 7676df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden add_timer(&lp->media); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *el3_get_stats(struct net_device *dev) 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 7736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned long flags; 7746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct pcmcia_device *link = lp->p_dev; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (pcmcia_dev_present(link)) { 7776df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_lock_irqsave(&lp->lock, flags); 7786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden update_stats(dev); 7796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden spin_unlock_irqrestore(&lp->lock, flags); 7806df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 7816df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return &dev->stats; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7846df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden/* Update statistics. We change to register window 6, so this should be run 7856df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden* single-threaded if the device is active. This is expected to be a rare 7866df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden* operation, and it's simpler for the rest of the driver to assume that 7876df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden* window 1 is always valid rather than use a special window-state variable. 7886df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden* 7896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden* Caller must hold the lock for this 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 7916df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stats(struct net_device *dev) 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7946df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 7956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 7966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "updating the statistics.\n"); 7976df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Turn off statistics updates while reading. */ 7986df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsDisable, ioaddr + EL3_CMD); 7996df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Switch to the stats window, and read everything. */ 8006df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(6); 8016df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_carrier_errors += inb(ioaddr + 0); 8026df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); 8036df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Multiple collisions. */ 8046df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inb(ioaddr + 2); 8056df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.collisions += inb(ioaddr + 3); 8066df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_window_errors += inb(ioaddr + 4); 8076df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_fifo_errors += inb(ioaddr + 5); 8086df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.tx_packets += inb(ioaddr + 6); 8096df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Rx packets */ 8106df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inb(ioaddr + 7); 8116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Tx deferrals */ 8126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inb(ioaddr + 8); 8136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Rx octets */ 8146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr + 10); 8156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Tx octets */ 8166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden inw(ioaddr + 12); 8176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 8186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Back to window 1, and turn statistics back on. */ 8196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(1); 8206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsEnable, ioaddr + EL3_CMD); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_rx(struct net_device *dev) 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 8266df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden int worklimit = 32; 8276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden short rx_status; 828f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 8296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", 830f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); 8316df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && 832b9bdcd9bd78d253dcc8e13c29f0acd67e080e7c1Roel Kluin worklimit > 0) { 8336df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden worklimit--; 8346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (rx_status & 0x4000) { /* Error, update stats. */ 8356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden short error = rx_status & 0x3800; 8366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_errors++; 8376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden switch (error) { 8386df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x0000: 8396df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_over_errors++; 8406df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x0800: 8426df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_length_errors++; 8436df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x1000: 8456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_frame_errors++; 8466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8476df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x1800: 8486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_length_errors++; 8496df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8506df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x2000: 8516df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_frame_errors++; 8526df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8536df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden case 0x2800: 8546df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_crc_errors++; 8556df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden break; 8566df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 8576df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else { 8586df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden short pkt_len = rx_status & 0x7ff; 8596df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct sk_buff *skb; 8606df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 8616df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden skb = netdev_alloc_skb(dev, pkt_len + 5); 8626df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 8636df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", 864f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz pkt_len, rx_status); 8656df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (skb != NULL) { 8666df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden skb_reserve(skb, 2); 8676df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (pkt_len+3)>>2); 8696df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden skb->protocol = eth_type_trans(skb, dev); 8706df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_rx(skb); 8716df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_packets++; 8726df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_bytes += pkt_len; 8736df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } else { 8746df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", 875f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz pkt_len); 8766df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev->stats.rx_dropped++; 8776df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 8786df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 8796df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Pop the top of the Rx FIFO */ 8806df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden tc589_wait_for_completion(dev, RxDiscard); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8826df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (worklimit == 0) 8836df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netdev_warn(dev, "too much work in el3_rx!\n"); 8846df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return 0; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 887e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasakistatic void set_rx_mode(struct net_device *dev) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8896df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 8906df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden u16 opts = SetRxFilter | RxStation | RxBroadcast; 8916df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 8926df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (dev->flags & IFF_PROMISC) 8936df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden opts |= RxMulticast | RxProm; 8946df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) 8956df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden opts |= RxMulticast; 8966df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(opts, ioaddr + EL3_CMD); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 899e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasakistatic void set_multicast_list(struct net_device *dev) 900e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki{ 901e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki struct el3_private *priv = netdev_priv(dev); 902e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki unsigned long flags; 903e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki 904e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki spin_lock_irqsave(&priv->lock, flags); 905e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki set_rx_mode(dev); 906e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki spin_unlock_irqrestore(&priv->lock, flags); 907e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki} 908e445bb4ed677f8df0d4f8c1abc15c668bd182f28Ken Kawasaki 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_close(struct net_device *dev) 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9116df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct el3_private *lp = netdev_priv(dev); 9126df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden struct pcmcia_device *link = lp->p_dev; 9136df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden unsigned int ioaddr = dev->base_addr; 9146df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 9156df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); 9166df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 9176df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (pcmcia_dev_present(link)) { 9186df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Turn off statistics ASAP. We update dev->stats below. */ 9196df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StatsDisable, ioaddr + EL3_CMD); 9206df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 9216df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Disable the receiver and transmitter. */ 9226df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(RxDisable, ioaddr + EL3_CMD); 9236df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(TxDisable, ioaddr + EL3_CMD); 9246df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden 9256df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if (dev->if_port == 2) 9266df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Turn off thinnet power. Green! */ 9276df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(StopCoax, ioaddr + EL3_CMD); 9286df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden else if (dev->if_port == 1) { 9296df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Disable link beat and jabber */ 9306df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(4); 9316df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0, ioaddr + WN4_MEDIA); 9326df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden } 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9346df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Switching back to window 0 disables the IRQ. */ 9356df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden EL3WINDOW(0); 9366df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* But we explicitly zero the IRQ line select anyway. */ 9376df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden outw(0x0f00, ioaddr + WN0_IRQ); 938f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 9396df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden /* Check if the card still exists */ 9406df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) 9416df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden update_stats(dev); 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 943f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 9446df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden link->open--; 9456df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden netif_stop_queue(dev); 9466df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden del_timer_sync(&lp->media); 947f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz 9486df3efccee5f56f08e5e6a398462dfbb7fcb3a6cJustin van Wijngaarden return 0; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95125f8f54f6e178acfd503a95441b0ea05c525f751Joe Perchesstatic const struct pcmcia_device_id tc589_ids[] = { 9527ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562), 9537ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), 9547ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), 9557ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202), 956f0a3a1538d57dfb51c73d012cbb72f985cd419aaKen Kawasaki PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"), 957f0a3a1538d57dfb51c73d012cbb72f985cd419aaKen Kawasaki PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"), 9587ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski PCMCIA_DEVICE_NULL, 9597ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski}; 9607ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, tc589_ids); 9617ffec58c1e35c1e8f716c64e4860dbb00be4b221Dominik Brodowski 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver tc589_driver = { 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 9642e9b981a7c63ee8278df6823f8389d69dad1a499Dominik Brodowski .name = "3c589_cs", 96515b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski .probe = tc589_probe, 966cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski .remove = tc589_detach, 967f64e96973a1fa885ce6e4f7e3fdbae83de98fcabAlexander Kurz .id_table = tc589_ids, 96898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .suspend = tc589_suspend, 96998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski .resume = tc589_resume, 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 971fdd3f29eddd1b7c26b3b42e3633afcb22a28fcb3H Hartley Sweetenmodule_pcmcia_driver(tc589_driver); 972