Vereinheitlichte Schnittstellen, Include-Verzeichnis und Module getrennt.
--- a/Makefile Fri Jan 13 15:47:44 2006 +0000
+++ b/Makefile Tue Jan 17 18:28:15 2006 +0000
@@ -13,7 +13,7 @@
#------------------------------------------------------------------------------
# Kbuild-Abschnitt
-obj-m := drivers/ rt/ mini/
+obj-m := master/ devices/ rt/ mini/
#------------------------------------------------------------------------------
@@ -38,10 +38,6 @@
@echo "# EtherCAT Konfigurationsdatei Kernel 2.6" > $(CONFIG_FILE)
@echo >> $(CONFIG_FILE)
@echo "KERNELDIR = /usr/src/linux" >> $(CONFIG_FILE)
- @echo "RTAIDIR =" >> $(CONFIG_FILE)
- @echo "RTLIBDIR =" >> $(CONFIG_FILE)
- @echo >> $(CONFIG_FILE)
- @echo "MAKE_RT = yes" >> $(CONFIG_FILE)
@echo >> $(CONFIG_FILE)
@echo "$(CONFIG_FILE) erstellt."
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devices/8139too.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,3016 @@
+/******************************************************************************
+ *
+ * drv_8139too.c
+ *
+ * EtherCAT-Treiber für RTL8139-kompatible Netzwerkkarten.
+ *
+ * Autoren: Wilhelm Hagemeister, Florian Pose
+ *
+ * $Date$
+ * $Author$
+ *
+ * (C) Copyright IgH 2005
+ * Ingenieurgemeinschaft IgH
+ * Heinz-Bäcker Str. 34
+ * D-45356 Essen
+ * Tel.: +49 201/61 99 31
+ * Fax.: +49 201/61 98 36
+ * E-mail: sp@igh-essen.com
+ *
+ ******************************************************************************/
+
+/*
+ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+ Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Copyright 2000-2002 Jeff Garzik
+
+ Much code comes from Donald Becker's rtl8139.c driver,
+ versions 1.13 and older. This driver was originally based
+ on rtl8139.c version 1.07. Header of rtl8139.c version 1.13:
+
+ -----<snip>-----
+
+ Written 1997-2001 by Donald Becker.
+ This software may be used and distributed according to the
+ terms of the GNU General Public License (GPL), incorporated
+ herein by reference. Drivers based on or derived from this
+ code fall under the GPL and must retain the authorship,
+ copyright and license notice. This file is not a complete
+ program and may only be used when the entire operating
+ system is licensed under the GPL.
+
+ This driver is for boards based on the RTL8129 and RTL8139
+ PCI ethernet chips.
+
+ The author may be reached as becker@scyld.com, or C/O Scyld
+ Computing Corporation 410 Severn Ave., Suite 210 Annapolis
+ MD 21403
+
+ Support and updates available at
+ http://www.scyld.com/network/rtl8139.html
+
+ Twister-tuning table provided by Kinston
+ <shangh@realtek.com.tw>.
+
+ -----<snip>-----
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ Contributors:
+
+ Donald Becker - he wrote the original driver, kudos to him!
+ (but please don't e-mail him for support, this isn't his driver)
+
+ Tigran Aivazian - bug fixes, skbuff free cleanup
+
+ Martin Mares - suggestions for PCI cleanup
+
+ David S. Miller - PCI DMA and softnet updates
+
+ Ernst Gill - fixes ported from BSD driver
+
+ Daniel Kobras - identified specific locations of
+ posted MMIO write bugginess
+
+ Gerard Sharp - bug fix, testing and feedback
+
+ David Ford - Rx ring wrap fix
+
+ Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
+ to find and fix a crucial bug on older chipsets.
+
+ Donald Becker/Chris Butterworth/Marcus Westergren -
+ Noticed various Rx packet size-related buglets.
+
+ Santiago Garcia Mantinan - testing and feedback
+
+ Jens David - 2.2.x kernel backports
+
+ Martin Dennett - incredibly helpful insight on undocumented
+ features of the 8139 chips
+
+ Jean-Jacques Michel - bug fix
+
+ Tobias Ringström - Rx interrupt status checking suggestion
+
+ Andrew Morton - Clear blocked signals, avoid
+ buffer overrun setting current->comm.
+
+ Kalle Olavi Niemitalo - Wake-on-LAN ioctls
+
+ Robert Kuebel - Save kernel thread from dying on any signal.
+
+ Submitting bug reports:
+
+ "rtl8139-diag -mmmaaavvveefN" output
+ enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
+
+*/
+
+#define DRV_NAME "8139too_ec"
+#define DRV_VERSION "0.9.27"
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/completion.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#include "../include/EtherCAT_dev.h"
+
+#define LIT(X) #X
+#define STR(X) LIT(X)
+
+#define COMPILE_INFO "Revision " STR(EC_REV) \
+ ", compiled by " STR(EC_USER) \
+ " at " STR(EC_DATE)
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
+
+/* Default Message level */
+#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+
+
+/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
+#ifdef CONFIG_8139TOO_PIO
+#define USE_IO_OPS 1
+#endif
+
+/* define to 1, 2 or 3 to enable copious debugging info */
+#define RTL8139_DEBUG 0
+
+/* define to 1 to disable lightweight runtime debugging checks */
+#undef RTL8139_NDEBUG
+
+
+#if RTL8139_DEBUG
+/* note: prints function name for you */
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+# define DPRINTK(fmt, args...)
+#endif
+
+#ifdef RTL8139_NDEBUG
+# define assert(expr) do {} while (0)
+#else
+# define assert(expr) \
+ if(unlikely(!(expr))) { \
+ printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+
+/* A few user-configurable values. */
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ The RTL chips use a 64 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+
+/* bitmapped message enable number */
+static int debug = -1;
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+// Uncomment for debugging
+//#define EC_DEBUG
+
+// Device index for EtherCAT device selection
+static int ec_device_index = -1;
+static int ec_device_master_index = 0;
+
+static ec_device_t *rtl_ec_dev;
+int rtl_ec_dev_registered = 0;
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/*
+ * Receive ring size
+ * Warning: 64K ring has hardware issues and may lock up.
+ */
+#if defined(CONFIG_SH_DREAMCAST)
+#define RX_BUF_IDX 1 /* 16K ring */
+#else
+#define RX_BUF_IDX 2 /* 32K ring */
+#endif
+#define RX_BUF_LEN (8192 << RX_BUF_IDX)
+#define RX_BUF_PAD 16
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+
+#if RX_BUF_LEN == 65536
+#define RX_BUF_TOT_LEN RX_BUF_LEN
+#else
+#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+#endif
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* PCI Tuning Parameters
+ Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (6*HZ)
+
+
+enum {
+ HAS_MII_XCVR = 0x010000,
+ HAS_CHIP_XCVR = 0x020000,
+ HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_NUM_STATS 4 /* number of ETHTOOL_GSTATS u64's */
+#define RTL_REGS_VER 1 /* version of reg. data in ETHTOOL_GREGS */
+#define RTL_MIN_IO_SIZE 0x80
+#define RTL8139B_IO_SIZE 256
+
+#define RTL8129_CAPS HAS_MII_XCVR
+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+ RTL8139 = 0,
+ RTL8129,
+} board_t;
+
+
+/* indexed by board_t, above */
+static struct {
+ const char *name;
+ u32 hw_flags;
+} board_info[] __devinitdata = {
+ { "RealTek RTL8139", RTL8139_CAPS },
+ { "RealTek RTL8129", RTL8129_CAPS },
+};
+
+
+static struct pci_device_id rtl8139_pci_tbl[] = {
+ {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1259, 0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+ /* Bogus 8139 silicon reports 8129 without external PROM :-( */
+ {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+#endif
+#ifdef CONFIG_8139TOO_8129
+ {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
+#endif
+
+ /* some crazy cards report invalid vendor ids like
+ * 0x0001 here. The other ids are valid and constant,
+ * so we simply don't match on the main vendor id.
+ */
+ {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
+ {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
+ {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
+
+ {0,}
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+static struct {
+ const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "early_rx" },
+ { "tx_buf_mapped" },
+ { "tx_timeouts" },
+ { "rx_lost_in_ring" },
+};
+
+/* The rest of these values should never change. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf = 0x30,
+ ChipCmd = 0x37,
+ RxBufPtr = 0x38,
+ RxBufAddr = 0x3A,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ Timer = 0x48, /* A general-purpose counter. */
+ RxMissed = 0x4C, /* 24 bits valid, write clears. */
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ FlashReg = 0x54,
+ MediaStatus = 0x58,
+ Config3 = 0x59,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
+ /* Undocumented registers, but required for proper operation. */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ CSCR = 0x74, /* Chip Status and Configuration Register. */
+ PARA78 = 0x78,
+ PARA7c = 0x7c, /* Magic transceiver parameter register. */
+ Config5 = 0xD8, /* absent on RTL-8139A */
+};
+
+enum ClearBitMasks {
+ MultiIntrClear = 0xF000,
+ ChipCmdClear = 0xE2,
+ Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+};
+
+enum ChipCmdBits {
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+ PCIErr = 0x8000,
+ PCSTimeout = 0x4000,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+
+ RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+};
+
+enum TxStatusBits {
+ TxHostOwns = 0x2000,
+ TxUnderrun = 0x4000,
+ TxStatOK = 0x8000,
+ TxOutOfWindow = 0x20000000,
+ TxAborted = 0x40000000,
+ TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+ RxMulticast = 0x8000,
+ RxPhysical = 0x4000,
+ RxBroadcast = 0x2000,
+ RxBadSymbol = 0x0020,
+ RxRunt = 0x0010,
+ RxTooLong = 0x0008,
+ RxCRCErr = 0x0004,
+ RxBadAlign = 0x0002,
+ RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits {
+
+ /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+ TxIFGShift = 24,
+ TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+ TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+ TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+ TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
+
+ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
+ TxClearAbt = (1 << 0), /* Clear abort (WO) */
+ TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
+ TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
+
+ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ LWAKE = 0x10, /* not on 8139, 8139A */
+ Cfg1_Driver_Load = 0x20,
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+ SLEEP = (1 << 1), /* only on 8139, 8139A */
+ PWRDN = (1 << 0), /* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum Config3Bits {
+ Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
+ Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+ Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+ Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
+ Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
+ Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+ Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
+ Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum Config4Bits {
+ LWPTN = (1 << 2), /* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum Config5Bits {
+ Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
+ Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
+ Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
+ Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
+ Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
+ Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
+ Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum RxConfigBits {
+ /* rx fifo threshold */
+ RxCfgFIFOShift = 13,
+ RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+ /* Max DMA burst */
+ RxCfgDMAShift = 8,
+ RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+ /* rx ring buffer length */
+ RxCfgRcv8K = 0,
+ RxCfgRcv16K = (1 << 11),
+ RxCfgRcv32K = (1 << 12),
+ RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+ /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+ RxNoWrap = (1 << 7),
+};
+
+/* Twister tuning parameters from RealTek.
+ Completely undocumented, but required to tune bad links on some boards. */
+enum CSCRBits {
+ CSCR_LinkOKBit = 0x0400,
+ CSCR_LinkChangeBit = 0x0800,
+ CSCR_LinkStatusBits = 0x0f000,
+ CSCR_LinkDownOffCmd = 0x003c0,
+ CSCR_LinkDownCmd = 0x0f3c0,
+};
+
+enum Cfg9346Bits {
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
+};
+
+typedef enum {
+ CH_8139 = 0,
+ CH_8139_K,
+ CH_8139A,
+ CH_8139A_G,
+ CH_8139B,
+ CH_8130,
+ CH_8139C,
+ CH_8100,
+ CH_8100B_8139D,
+ CH_8101,
+} chip_t;
+
+enum chip_flags {
+ HasHltClk = (1 << 0),
+ HasLWake = (1 << 1),
+};
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+ (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
+
+/* directly indexed by chip_t, above */
+const static struct {
+ const char *name;
+ u32 version; /* from RTL8139C/RTL8139D docs */
+ u32 flags;
+} rtl_chip_info[] = {
+ { "RTL-8139",
+ HW_REVID(1, 0, 0, 0, 0, 0, 0),
+ HasHltClk,
+ },
+
+ { "RTL-8139 rev K",
+ HW_REVID(1, 1, 0, 0, 0, 0, 0),
+ HasHltClk,
+ },
+
+ { "RTL-8139A",
+ HW_REVID(1, 1, 1, 0, 0, 0, 0),
+ HasHltClk, /* XXX undocumented? */
+ },
+
+ { "RTL-8139A rev G",
+ HW_REVID(1, 1, 1, 0, 0, 1, 0),
+ HasHltClk, /* XXX undocumented? */
+ },
+
+ { "RTL-8139B",
+ HW_REVID(1, 1, 1, 1, 0, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8130",
+ HW_REVID(1, 1, 1, 1, 1, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8139C",
+ HW_REVID(1, 1, 1, 0, 1, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8100",
+ HW_REVID(1, 1, 1, 1, 0, 1, 0),
+ HasLWake,
+ },
+
+ { "RTL-8100B/8139D",
+ HW_REVID(1, 1, 1, 0, 1, 0, 1),
+ HasLWake,
+ },
+
+ { "RTL-8101",
+ HW_REVID(1, 1, 1, 0, 1, 1, 1),
+ HasLWake,
+ },
+};
+
+struct rtl_extra_stats {
+ unsigned long early_rx;
+ unsigned long tx_buf_mapped;
+ unsigned long tx_timeouts;
+ unsigned long rx_lost_in_ring;
+};
+
+struct rtl8139_private {
+ void __iomem *mmio_addr;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ u32 msg_enable;
+ struct net_device_stats stats;
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
+ unsigned int tx_flag;
+ unsigned long cur_tx;
+ unsigned long dirty_tx;
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_bufs_dma;
+ signed char phys[4]; /* MII device addresses. */
+ char twistie, twist_row, twist_col; /* Twister tune state. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ spinlock_t lock;
+ spinlock_t rx_lock;
+ chip_t chipset;
+ pid_t thr_pid;
+ wait_queue_head_t thr_wait;
+ struct completion thr_exited;
+ u32 rx_config;
+ struct rtl_extra_stats xstats;
+ int time_to_die;
+ struct mii_if_info mii;
+ unsigned int regs_len;
+ unsigned long fifo_copy_timeout;
+};
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>, Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver with EtherCAT functionality");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(COMPILE_INFO);
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+module_param(multicast_filter_limit, int, 0);
+module_param_array(media, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+module_param(debug, int, 0);
+MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
+MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
+
+/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+module_param(ec_device_index, int, -1);
+module_param(ec_device_master_index, int, 0);
+MODULE_PARM_DESC(ec_device_index, "Index of the device reserved for EtherCAT.");
+MODULE_PARM_DESC(ec_device_master_index, "Index of the EtherCAT master to register the device.");
+
+/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static int read_eeprom (void __iomem *ioaddr, int location, int addr_len);
+static int rtl8139_open (struct net_device *dev);
+static int mdio_read (struct net_device *dev, int phy_id, int location);
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int val);
+static void rtl8139_start_thread(struct net_device *dev);
+static void rtl8139_tx_timeout (struct net_device *dev);
+static void rtl8139_init_ring (struct net_device *dev);
+static int rtl8139_start_xmit (struct sk_buff *skb,
+ struct net_device *dev);
+int rtl8139_poll(struct net_device *dev, int *budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void rtl8139_poll_controller(struct net_device *dev);
+#endif
+irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs);
+static int rtl8139_close (struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static void rtl8139_set_rx_mode (struct net_device *dev);
+static void __set_rx_mode (struct net_device *dev);
+static void rtl8139_hw_start (struct net_device *dev);
+static struct ethtool_ops rtl8139_ethtool_ops;
+
+/* write MMIO register, with flush */
+/* Flush avoids rtl8139 bug w/ posted MMIO writes */
+#define RTL_W8_F(reg, val8) do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)
+#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
+#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
+
+
+#define MMIO_FLUSH_AUDIT_COMPLETE 1
+#if MMIO_FLUSH_AUDIT_COMPLETE
+
+/* write MMIO register */
+#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
+
+#else
+
+/* write MMIO register, then flush */
+#define RTL_W8 RTL_W8_F
+#define RTL_W16 RTL_W16_F
+#define RTL_W32 RTL_W32_F
+
+#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
+
+/* read MMIO register */
+#define RTL_R8(reg) ioread8 (ioaddr + (reg))
+#define RTL_R16(reg) ioread16 (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
+
+
+static const u16 rtl8139_intr_mask =
+ PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
+ TxErr | TxOK | RxErr | RxOK;
+
+static const u16 rtl8139_norx_intr_mask =
+ PCIErr | PCSTimeout | RxUnderrun |
+ TxErr | TxOK | RxErr ;
+
+#if RX_BUF_IDX == 0
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv8K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 1
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv16K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 2
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv32K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 3
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv64K |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#else
+#error "Invalid configuration for 8139_RXBUF_IDX"
+#endif
+
+static const unsigned int rtl8139_tx_config =
+ TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+
+static void __rtl8139_cleanup_dev (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ struct pci_dev *pdev;
+
+ assert (dev != NULL);
+ assert (tp->pci_dev != NULL);
+ pdev = tp->pci_dev;
+
+#ifdef USE_IO_OPS
+ if (tp->mmio_addr)
+ ioport_unmap (tp->mmio_addr);
+#else
+ if (tp->mmio_addr)
+ pci_iounmap (pdev, tp->mmio_addr);
+#endif /* USE_IO_OPS */
+
+ /* it's ok to call this even if we have no regions to free */
+ pci_release_regions (pdev);
+
+ free_netdev(dev);
+ pci_set_drvdata (pdev, NULL);
+}
+
+
+static void rtl8139_chip_reset (void __iomem *ioaddr)
+{
+ int i;
+
+ /* Soft reset the chip. */
+ RTL_W8 (ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--) {
+ barrier();
+ if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+ break;
+ udelay (10);
+ }
+}
+
+
+static int __devinit rtl8139_init_board (struct pci_dev *pdev,
+ struct net_device **dev_out)
+{
+ void __iomem *ioaddr;
+ struct net_device *dev;
+ struct rtl8139_private *tp;
+ u8 tmp8;
+ int rc, disable_dev_on_err = 0;
+ unsigned int i;
+ unsigned long pio_start, pio_end, pio_flags, pio_len;
+ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+ u32 version;
+
+ assert (pdev != NULL);
+
+ *dev_out = NULL;
+
+ /* dev and priv zeroed in alloc_etherdev */
+ dev = alloc_etherdev (sizeof (*tp));
+ if (dev == NULL) {
+ printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+ return -ENOMEM;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ tp = netdev_priv(dev);
+ tp->pci_dev = pdev;
+
+ /* enable device (incl. PCI PM wakeup and hotplug setup) */
+ rc = pci_enable_device (pdev);
+ if (rc)
+ goto err_out;
+
+ pio_start = pci_resource_start (pdev, 0);
+ pio_end = pci_resource_end (pdev, 0);
+ pio_flags = pci_resource_flags (pdev, 0);
+ pio_len = pci_resource_len (pdev, 0);
+
+ mmio_start = pci_resource_start (pdev, 1);
+ mmio_end = pci_resource_end (pdev, 1);
+ mmio_flags = pci_resource_flags (pdev, 1);
+ mmio_len = pci_resource_len (pdev, 1);
+
+ /* set this immediately, we need to know before
+ * we talk to the chip directly */
+ DPRINTK("PIO region size == 0x%02X\n", pio_len);
+ DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
+
+#ifdef USE_IO_OPS
+ /* make sure PCI base addr 0 is PIO */
+ if (!(pio_flags & IORESOURCE_IO)) {
+ printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+ /* check for weird/broken PCI region reporting */
+ if (pio_len < RTL_MIN_IO_SIZE) {
+ printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+#else
+ /* make sure PCI base addr 1 is MMIO */
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+ if (mmio_len < RTL_MIN_IO_SIZE) {
+ printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+#endif
+
+ rc = pci_request_regions (pdev, "8139too");
+ if (rc)
+ goto err_out;
+ disable_dev_on_err = 1;
+
+ /* enable PCI bus-mastering */
+ pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+ ioaddr = ioport_map(pio_start, pio_len);
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+ dev->base_addr = pio_start;
+ tp->mmio_addr = ioaddr;
+ tp->regs_len = pio_len;
+#else
+ /* ioremap MMIO region */
+ ioaddr = pci_iomap(pdev, 1, 0);
+ if (ioaddr == NULL) {
+ printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+ dev->base_addr = (long) ioaddr;
+ tp->mmio_addr = ioaddr;
+ tp->regs_len = mmio_len;
+#endif /* USE_IO_OPS */
+
+ /* Bring old chips out of low-power mode. */
+ RTL_W8 (HltClk, 'R');
+
+ /* check for missing/broken hardware */
+ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
+ printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
+ pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+
+ /* identify chip attached to board */
+ version = RTL_R32 (TxConfig) & HW_REVID_MASK;
+ for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
+ if (version == rtl_chip_info[i].version) {
+ tp->chipset = i;
+ goto match;
+ }
+
+ /* if unknown chip, assume array element #0, original RTL-8139 in this case */
+ printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
+ pci_name(pdev));
+ printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+ tp->chipset = 0;
+
+match:
+ DPRINTK ("chipset id (%d) == index %d, '%s'\n",
+ version, i, rtl_chip_info[i].name);
+
+ if (tp->chipset >= CH_8139B) {
+ u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
+ DPRINTK("PCI PM wakeup\n");
+ if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
+ (tmp8 & LWAKE))
+ new_tmp8 &= ~LWAKE;
+ new_tmp8 |= Cfg1_PM_Enable;
+ if (new_tmp8 != tmp8) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config1, tmp8);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ }
+ if (rtl_chip_info[tp->chipset].flags & HasLWake) {
+ tmp8 = RTL_R8 (Config4);
+ if (tmp8 & LWPTN) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config4, tmp8 & ~LWPTN);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ }
+ }
+ } else {
+ DPRINTK("Old chip wakeup\n");
+ tmp8 = RTL_R8 (Config1);
+ tmp8 &= ~(SLEEP | PWRDN);
+ RTL_W8 (Config1, tmp8);
+ }
+
+ rtl8139_chip_reset (ioaddr);
+
+ *dev_out = dev;
+ return 0;
+
+err_out:
+ __rtl8139_cleanup_dev (dev);
+ if (disable_dev_on_err)
+ pci_disable_device (pdev);
+ return rc;
+}
+
+
+static int __devinit rtl8139_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev = NULL;
+ struct rtl8139_private *tp;
+ int i, addr_len, option;
+ void __iomem *ioaddr;
+ static int board_idx = -1;
+ u8 pci_rev;
+
+ assert (pdev != NULL);
+ assert (ent != NULL);
+
+ board_idx++;
+
+ /* when we're built into the kernel, the driver version message
+ * is only printed if at least one 8139 board has been found
+ */
+#ifndef MODULE
+ {
+ static int printed_version;
+ if (!printed_version++)
+ printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+ }
+#endif
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+ if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+ printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
+ printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ }
+
+ i = rtl8139_init_board (pdev, &dev);
+ if (i < 0)
+ return i;
+
+ assert (dev != NULL);
+ tp = netdev_priv(dev);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (board_idx == ec_device_index)
+ {
+ printk(KERN_INFO "Registering EtherCAT device...\n");
+ rtl_ec_dev = EtherCAT_dev_register(ec_device_master_index, dev,
+ rtl8139_interrupt, THIS_MODULE);
+
+ if (rtl_ec_dev) strcpy(dev->name, "ec0");
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ ioaddr = tp->mmio_addr;
+ assert (ioaddr != NULL);
+
+ addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ ((u16 *) (dev->dev_addr))[i] =
+ le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+
+ /* The Rtl8139-specific entries in the device structure. */
+ dev->open = rtl8139_open;
+ dev->hard_start_xmit = rtl8139_start_xmit;
+ dev->poll = rtl8139_poll;
+ dev->weight = 64;
+ dev->stop = rtl8139_close;
+ dev->get_stats = rtl8139_get_stats;
+ dev->set_multicast_list = rtl8139_set_rx_mode;
+ dev->do_ioctl = netdev_ioctl;
+ dev->ethtool_ops = &rtl8139_ethtool_ops;
+ dev->tx_timeout = rtl8139_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = rtl8139_poll_controller;
+#endif
+
+ /* note: the hardware is not capable of sg/csum/highdma, however
+ * through the use of skb_copy_and_csum_dev we enable these
+ * features
+ */
+ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+ dev->irq = pdev->irq;
+
+ /* tp zeroed and aligned in alloc_etherdev */
+ tp = netdev_priv(dev);
+
+ /* note: tp->chipset set in rtl8139_init_board */
+ tp->drv_flags = board_info[ent->driver_data].hw_flags;
+ tp->mmio_addr = ioaddr;
+ tp->msg_enable =
+ (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
+ spin_lock_init (&tp->lock);
+ spin_lock_init (&tp->rx_lock);
+
+ init_waitqueue_head (&tp->thr_wait);
+ init_completion (&tp->thr_exited);
+ tp->mii.dev = dev;
+ tp->mii.mdio_read = mdio_read;
+ tp->mii.mdio_write = mdio_write;
+ tp->mii.phy_id_mask = 0x3f;
+ tp->mii.reg_num_mask = 0x1f;
+
+ /* dev is fully set up and ready to use now */
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ /* EtherCAT-Karten nicht beim Stack anmelden. */
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ DPRINTK("About to register device named %s (%p)...\n", dev->name, dev);
+ i = register_netdev (dev);
+ if (i) goto err_out;
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ pci_set_drvdata (pdev, dev);
+
+ printk (KERN_INFO "%s: %s at 0x%lx, "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+ "IRQ %d\n",
+ dev->name,
+ board_info[ent->driver_data].name,
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ dev->irq);
+
+ printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
+ dev->name, rtl_chip_info[tp->chipset].name);
+
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later, but
+ takes too much time. */
+#ifdef CONFIG_8139TOO_8129
+ if (tp->drv_flags & HAS_MII_XCVR) {
+ int phy, phy_idx = 0;
+ for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+ int mii_status = mdio_read(dev, phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ u16 advertising = mdio_read(dev, phy, 4);
+ tp->phys[phy_idx++] = phy;
+ printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+ "advertising %4.4x.\n",
+ dev->name, phy, mii_status, advertising);
+ }
+ }
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
+ "transceiver.\n",
+ dev->name);
+ tp->phys[0] = 32;
+ }
+ } else
+#endif
+ tp->phys[0] = 32;
+ tp->mii.phy_id = tp->phys[0];
+
+ /* The lower four bits are the media type. */
+ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+ if (option > 0) {
+ tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
+ tp->default_port = option & 0xFF;
+ if (tp->default_port)
+ tp->mii.force_media = 1;
+ }
+ if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
+ tp->mii.full_duplex = full_duplex[board_idx];
+ if (tp->mii.full_duplex) {
+ printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ /* Changing the MII-advertised media because might prevent
+ re-connection. */
+ tp->mii.force_media = 1;
+ }
+ if (tp->default_port) {
+ printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
+ (option & 0x20 ? 100 : 10),
+ (option & 0x10 ? "full" : "half"));
+ mdio_write(dev, tp->phys[0], 0,
+ ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */
+ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+ }
+
+ /* Put the chip into low-power mode. */
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ return 0;
+
+err_out:
+ __rtl8139_cleanup_dev (dev);
+ pci_disable_device (pdev);
+ return i;
+}
+
+
+static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ assert (dev != NULL);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ unregister_netdev (dev);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ __rtl8139_cleanup_dev (dev);
+ pci_disable_device (pdev);
+}
+
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay() RTL_R32(Cfg9346)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ RTL_W8 (Cfg9346, EE_ENB & ~EE_CS);
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ RTL_W8 (Cfg9346, EE_ENB | dataval);
+ eeprom_delay ();
+ RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK);
+ eeprom_delay ();
+ }
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+
+ for (i = 16; i > 0; i--) {
+ RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK);
+ eeprom_delay ();
+ retval =
+ (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 :
+ 0);
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+ }
+
+ /* Terminate the EEPROM access. */
+ RTL_W8 (Cfg9346, ~EE_CS);
+ eeprom_delay ();
+
+ return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+ serial MDIO protocol.
+ The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues. */
+#define MDIO_DIR 0x80
+#define MDIO_DATA_OUT 0x04
+#define MDIO_DATA_IN 0x02
+#define MDIO_CLK 0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay() RTL_R8(Config4)
+
+
+static char mii_2_8139_map[8] = {
+ BasicModeCtrl,
+ BasicModeStatus,
+ 0,
+ 0,
+ NWayAdvert,
+ NWayLPAR,
+ NWayExpansion,
+ 0
+};
+
+
+#ifdef CONFIG_8139TOO_8129
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync (void __iomem *ioaddr)
+{
+ int i;
+
+ for (i = 32; i >= 0; i--) {
+ RTL_W8 (Config4, MDIO_WRITE1);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK);
+ mdio_delay ();
+ }
+}
+#endif
+
+static int mdio_read (struct net_device *dev, int phy_id, int location)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int retval = 0;
+#ifdef CONFIG_8139TOO_8129
+ void __iomem *ioaddr = tp->mmio_addr;
+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int i;
+#endif
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ void __iomem *ioaddr = tp->mmio_addr;
+ return location < 8 && mii_2_8139_map[location] ?
+ RTL_R16 (mii_2_8139_map[location]) : 0;
+ }
+
+#ifdef CONFIG_8139TOO_8129
+ mdio_sync (ioaddr);
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+ RTL_W8 (Config4, MDIO_DIR | dataval);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK);
+ mdio_delay ();
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ RTL_W8 (Config4, 0);
+ mdio_delay ();
+ retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0);
+ RTL_W8 (Config4, MDIO_CLK);
+ mdio_delay ();
+ }
+#endif
+
+ return (retval >> 1) & 0xffff;
+}
+
+
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int value)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+#ifdef CONFIG_8139TOO_8129
+ void __iomem *ioaddr = tp->mmio_addr;
+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+ int i;
+#endif
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ void __iomem *ioaddr = tp->mmio_addr;
+ if (location == 0) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W16 (BasicModeCtrl, value);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ } else if (location < 8 && mii_2_8139_map[location])
+ RTL_W16 (mii_2_8139_map[location], value);
+ return;
+ }
+
+#ifdef CONFIG_8139TOO_8129
+ mdio_sync (ioaddr);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval =
+ (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+ RTL_W8 (Config4, dataval);
+ mdio_delay ();
+ RTL_W8 (Config4, dataval | MDIO_CLK);
+ mdio_delay ();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ RTL_W8 (Config4, 0);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_CLK);
+ mdio_delay ();
+ }
+#endif
+}
+
+
+static int rtl8139_open (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int retval;
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#ifdef EC_DEBUG
+ printk(KERN_DEBUG "%s: open\n", dev->name);
+#endif
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ retval = request_irq(dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
+ if (retval)
+ return retval;
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ &tp->tx_bufs_dma);
+ tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ &tp->rx_ring_dma);
+ if (tp->tx_bufs == NULL || tp->rx_ring == NULL)
+ {
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ free_irq(dev->irq, dev);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ if (tp->tx_bufs)
+ pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ if (tp->rx_ring)
+ pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+
+ return -ENOMEM;
+ }
+
+ tp->mii.full_duplex = tp->mii.force_media;
+ tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+
+ rtl8139_init_ring (dev);
+ rtl8139_hw_start (dev);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ netif_start_queue (dev);
+
+ if (netif_msg_ifup(tp))
+ {
+ printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
+ " GP Pins %2.2x %s-duplex.\n",
+ dev->name, pci_resource_start (tp->pci_dev, 1),
+ dev->irq, RTL_R8 (MediaStatus),
+ tp->mii.full_duplex ? "full" : "half");
+ }
+
+ rtl8139_start_thread(dev);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ return 0;
+}
+
+
+static void rtl_check_media (struct net_device *dev, unsigned int init_media)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ if (tp->phys[0] >= 0) {
+ mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
+ }
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 i;
+ u8 tmp;
+
+ /* Bring old chips out of low-power mode. */
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'R');
+
+ rtl8139_chip_reset (ioaddr);
+
+ /* unlock Config[01234] and BMCR register writes */
+ RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+ /* Restore our idea of the MAC address. */
+ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+ RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+ RTL_W32 (RxConfig, tp->rx_config);
+ RTL_W32 (TxConfig, rtl8139_tx_config);
+
+ tp->cur_rx = 0;
+
+ rtl_check_media (dev, 1);
+
+ if (tp->chipset >= CH_8139B) {
+ /* Disable magic packet scanning, which is enabled
+ * when PM is enabled in Config1. It can be reenabled
+ * via ETHTOOL_SWOL if desired. */
+ RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
+ }
+
+ DPRINTK("init buffer addresses\n");
+
+ /* Lock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ /* init Rx ring buffer DMA address */
+ RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+ /* init Tx buffer DMA addresses */
+ for (i = 0; i < NUM_TX_DESC; i++)
+ RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
+
+ RTL_W32 (RxMissed, 0);
+
+ rtl8139_set_rx_mode (dev);
+
+ /* no early-rx interrupts */
+ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
+
+ /* make sure RxTx has started */
+ tmp = RTL_R8 (ChipCmd);
+ if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ /* Enable all known interrupts by setting the interrupt mask. */
+ RTL_W16 (IntrMask, rtl8139_intr_mask);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int i;
+
+ tp->cur_rx = 0;
+ tp->cur_tx = 0;
+ tp->dirty_tx = 0;
+
+ for (i = 0; i < NUM_TX_DESC; i++)
+ tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+}
+
+
+/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
+static int next_tick = 3 * HZ;
+
+#ifndef CONFIG_8139TOO_TUNE_TWISTER
+static inline void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp) {}
+#else
+enum TwisterParamVals {
+ PARA78_default = 0x78fa8388,
+ PARA7c_default = 0xcb38de43, /* param[0][3] */
+ PARA7c_xxx = 0xcb38de43,
+};
+
+static const unsigned long param[4][4] = {
+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+static void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp)
+{
+ int linkcase;
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ /* This is a complicated state machine to configure the "twister" for
+ impedance/echos based on the cable length.
+ All of this is magic and undocumented.
+ */
+ switch (tp->twistie) {
+ case 1:
+ if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
+ /* We have link beat, let us tune the twister. */
+ RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
+ tp->twistie = 2; /* Change to state 2. */
+ next_tick = HZ / 10;
+ } else {
+ /* Just put in some reasonable defaults for when beat returns. */
+ RTL_W16 (CSCR, CSCR_LinkDownCmd);
+ RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ tp->twistie = 0; /* Bail from future actions. */
+ }
+ break;
+ case 2:
+ /* Read how long it took to hear the echo. */
+ linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
+ if (linkcase == 0x7000)
+ tp->twist_row = 3;
+ else if (linkcase == 0x3000)
+ tp->twist_row = 2;
+ else if (linkcase == 0x1000)
+ tp->twist_row = 1;
+ else
+ tp->twist_row = 0;
+ tp->twist_col = 0;
+ tp->twistie = 3; /* Change to state 2. */
+ next_tick = HZ / 10;
+ break;
+ case 3:
+ /* Put out four tuning parameters, one per 100msec. */
+ if (tp->twist_col == 0)
+ RTL_W16 (FIFOTMS, 0);
+ RTL_W32 (PARA7c, param[(int) tp->twist_row]
+ [(int) tp->twist_col]);
+ next_tick = HZ / 10;
+ if (++tp->twist_col >= 4) {
+ /* For short cables we are done.
+ For long cables (row == 3) check for mistune. */
+ tp->twistie =
+ (tp->twist_row == 3) ? 4 : 0;
+ }
+ break;
+ case 4:
+ /* Special case for long cables: check for mistune. */
+ if ((RTL_R16 (CSCR) &
+ CSCR_LinkStatusBits) == 0x7000) {
+ tp->twistie = 0;
+ break;
+ } else {
+ RTL_W32 (PARA7c, 0xfb38de03);
+ tp->twistie = 5;
+ next_tick = HZ / 10;
+ }
+ break;
+ case 5:
+ /* Retune for shorter cable (column 2). */
+ RTL_W32 (FIFOTMS, 0x20);
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ RTL_W32 (FIFOTMS, 0x00);
+ tp->twist_row = 2;
+ tp->twist_col = 0;
+ tp->twistie = 3;
+ next_tick = HZ / 10;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
+static inline void rtl8139_thread_iter (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr)
+{
+ int mii_lpa;
+
+ mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
+
+ if (!tp->mii.force_media && mii_lpa != 0xffff) {
+ int duplex = (mii_lpa & LPA_100FULL)
+ || (mii_lpa & 0x01C0) == 0x0040;
+ if (tp->mii.full_duplex != duplex) {
+ tp->mii.full_duplex = duplex;
+
+ if (mii_lpa) {
+ printk (KERN_INFO
+ "%s: Setting %s-duplex based on MII #%d link"
+ " partner ability of %4.4x.\n",
+ dev->name,
+ tp->mii.full_duplex ? "full" : "half",
+ tp->phys[0], mii_lpa);
+ } else {
+ printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+ dev->name);
+ }
+#if 0
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+#endif
+ }
+ }
+
+ next_tick = HZ * 60;
+
+ rtl8139_tune_twister (dev, tp);
+
+ DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+ dev->name, RTL_R16 (NWayLPAR));
+ DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n",
+ dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
+ DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
+ dev->name, RTL_R8 (Config0),
+ RTL_R8 (Config1));
+}
+
+static int rtl8139_thread (void *data)
+{
+ struct net_device *dev = data;
+ struct rtl8139_private *tp = netdev_priv(dev);
+ unsigned long timeout;
+
+ daemonize("%s", dev->name);
+ allow_signal(SIGTERM);
+
+ while (1) {
+ timeout = next_tick;
+ do {
+ timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
+ /* make swsusp happy with our thread */
+ try_to_freeze();
+ } while (!signal_pending (current) && (timeout > 0));
+
+ if (signal_pending (current)) {
+ flush_signals(current);
+ }
+
+ if (tp->time_to_die)
+ break;
+
+ if (rtnl_lock_interruptible ())
+ break;
+ rtl8139_thread_iter (dev, tp, tp->mmio_addr);
+ rtnl_unlock ();
+ }
+
+ complete_and_exit (&tp->thr_exited, 0);
+}
+
+static void rtl8139_start_thread(struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ tp->thr_pid = -1;
+ tp->twistie = 0;
+ tp->time_to_die = 0;
+ if (tp->chipset == CH_8139_K)
+ tp->twistie = 1;
+ else if (tp->drv_flags & HAS_LNK_CHNG)
+ return;
+
+ tp->thr_pid = kernel_thread(rtl8139_thread, dev, CLONE_FS|CLONE_FILES);
+ if (tp->thr_pid < 0) {
+ printk (KERN_WARNING "%s: unable to start kernel thread\n",
+ dev->name);
+ }
+}
+
+static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
+{
+ tp->cur_tx = 0;
+ tp->dirty_tx = 0;
+
+ /* XXX account for unsent Tx packets in tp->stats.tx_dropped */
+}
+
+
+static void rtl8139_tx_timeout (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+ u8 tmp8;
+ unsigned long flags;
+
+ printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
+ "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
+ RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
+ /* Emit info to figure out what went wrong. */
+ printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
+ for (i = 0; i < NUM_TX_DESC; i++)
+ printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n",
+ dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
+ i == tp->dirty_tx % NUM_TX_DESC ?
+ " (queue head)" : "");
+
+ tp->xstats.tx_timeouts++;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_TIMEOUT);
+ }
+
+ /* disable Tx ASAP, if not already */
+ tmp8 = RTL_R8 (ChipCmd);
+ if (tmp8 & CmdTxEnb)
+ RTL_W8 (ChipCmd, CmdRxEnb);
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ spin_lock(&tp->rx_lock);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0x0000);
+
+ /* Stop a shared interrupt from scavenging while we are. */
+ spin_lock_irqsave (&tp->lock, flags);
+ rtl8139_tx_clear (tp);
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ /* ...and finally, reset everything */
+
+ if (netif_running(dev))
+ {
+ rtl8139_hw_start (dev);
+ netif_wake_queue (dev);
+ }
+
+ spin_unlock(&tp->rx_lock);
+ }
+ else
+ {
+ rtl8139_tx_clear (tp);
+ rtl8139_hw_start(dev);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+}
+
+static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned int entry;
+ unsigned int len = skb->len;
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % NUM_TX_DESC;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ /* Note: the chip doesn't have auto-pad! */
+ if (likely(len < TX_BUF_SIZE))
+ {
+ if (len < ETH_ZLEN)
+ memset(tp->tx_buf[entry], 0, ETH_ZLEN);
+
+ skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev)) dev_kfree_skb(skb);
+ }
+ else
+ {
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev)) dev_kfree_skb(skb);
+ tp->stats.tx_dropped++;
+ return 0;
+ }
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ spin_lock_irq(&tp->lock);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
+ tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
+
+ dev->trans_start = jiffies;
+
+ tp->cur_tx++;
+ wmb();
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
+ netif_stop_queue (dev);
+
+ spin_unlock_irq(&tp->lock);
+
+ if (netif_msg_tx_queued(tp))
+ printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
+ dev->name, len, entry);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ return 0;
+}
+
+
+static void rtl8139_tx_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr)
+{
+ unsigned long dirty_tx, tx_left;
+
+ assert (dev != NULL);
+ assert (ioaddr != NULL);
+
+ dirty_tx = tp->dirty_tx;
+ tx_left = tp->cur_tx - dirty_tx;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#if 0
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ rtl_ec_dev.tx_intr_cnt++;
+ rdtscl(rtl_ec_dev.tx_time); // Get CPU cycles
+ }
+#endif
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ while (tx_left > 0) {
+ int entry = dirty_tx % NUM_TX_DESC;
+ int txstatus;
+
+ txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
+
+ if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+ break; /* It still hasn't been Txed */
+
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ if (txstatus & (TxOutOfWindow | TxAborted)) {
+ /* There was an major error, log it. */
+ if (netif_msg_tx_err(tp))
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, txstatus);
+ tp->stats.tx_errors++;
+ if (txstatus & TxAborted) {
+ tp->stats.tx_aborted_errors++;
+ RTL_W32 (TxConfig, TxClearAbt);
+ RTL_W16 (IntrStatus, TxErr);
+ wmb();
+ }
+ if (txstatus & TxCarrierLost)
+ tp->stats.tx_carrier_errors++;
+ if (txstatus & TxOutOfWindow)
+ tp->stats.tx_window_errors++;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ } else {
+ if (txstatus & TxUnderrun) {
+ /* Add 64 to the Tx FIFO threshold. */
+ if (tp->tx_flag < 0x00300000)
+ tp->tx_flag += 0x00020000;
+ tp->stats.tx_fifo_errors++;
+ }
+ tp->stats.collisions += (txstatus >> 24) & 15;
+ tp->stats.tx_bytes += txstatus & 0x7ff;
+ tp->stats.tx_packets++;
+ }
+
+ dirty_tx++;
+ tx_left--;
+ }
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+#ifndef RTL8139_NDEBUG
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev) && tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+ printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+ dev->name, dirty_tx, tp->cur_tx);
+ dirty_tx += NUM_TX_DESC;
+ }
+#endif /* RTL8139_NDEBUG */
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ /* only wake the queue if we did work, and the queue is stopped */
+ if (tp->dirty_tx != dirty_tx) {
+ tp->dirty_tx = dirty_tx;
+ mb();
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ netif_wake_queue (dev);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+ }
+}
+
+
+/* TODO: clean this up! Rx reset need not be this intensive */
+static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
+ struct rtl8139_private *tp, void __iomem *ioaddr)
+{
+ u8 tmp8;
+#ifdef CONFIG_8139_OLD_RX_RESET
+ int tmp_work;
+#endif
+
+ if (netif_msg_rx_err (tp))
+ printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
+ dev->name, rx_status);
+ tp->stats.rx_errors++;
+ if (!(rx_status & RxStatusOK)) {
+ if (rx_status & RxTooLong) {
+ DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+ dev->name, rx_status);
+ /* A.C.: The chip hangs here. */
+ }
+ if (rx_status & (RxBadSymbol | RxBadAlign))
+ tp->stats.rx_frame_errors++;
+ if (rx_status & (RxRunt | RxTooLong))
+ tp->stats.rx_length_errors++;
+ if (rx_status & RxCRCErr)
+ tp->stats.rx_crc_errors++;
+ } else {
+ tp->xstats.rx_lost_in_ring++;
+ }
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ EtherCAT_dev_state(rtl_ec_dev, EC_DEVICE_STATE_ERROR);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+#ifndef CONFIG_8139_OLD_RX_RESET
+ tmp8 = RTL_R8 (ChipCmd);
+ RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
+ RTL_W8 (ChipCmd, tmp8);
+ RTL_W32 (RxConfig, tp->rx_config);
+ tp->cur_rx = 0;
+#else
+ /* Reset the receiver, based on RealTek recommendation. (Bug?) */
+
+ /* disable receive */
+ RTL_W8_F (ChipCmd, CmdTxEnb);
+ tmp_work = 200;
+ while (--tmp_work > 0) {
+ udelay(1);
+ tmp8 = RTL_R8 (ChipCmd);
+ if (!(tmp8 & CmdRxEnb))
+ break;
+ }
+ if (tmp_work <= 0)
+ printk (KERN_WARNING PFX "rx stop wait too long\n");
+ /* restart receive */
+ tmp_work = 200;
+ while (--tmp_work > 0) {
+ RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
+ udelay(1);
+ tmp8 = RTL_R8 (ChipCmd);
+ if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
+ break;
+ }
+ if (tmp_work <= 0)
+ printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
+
+ /* and reinitialize all rx related registers */
+ RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+ RTL_W32 (RxConfig, tp->rx_config);
+ tp->cur_rx = 0;
+
+ DPRINTK("init buffer addresses\n");
+
+ /* Lock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ /* init Rx ring buffer DMA address */
+ RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+ /* A.C.: Reset the multicast list. */
+ __set_rx_mode (dev);
+#endif
+}
+
+#if RX_BUF_IDX == 3
+static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
+ u32 offset, unsigned int size)
+{
+ u32 left = RX_BUF_LEN - offset;
+
+ if (size > left) {
+ memcpy(skb->data, ring + offset, left);
+ memcpy(skb->data+left, ring, size - left);
+ } else
+ memcpy(skb->data, ring + offset, size);
+}
+#endif
+
+static void rtl8139_isr_ack(struct rtl8139_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ u16 status;
+
+ status = RTL_R16 (IntrStatus) & RxAckBits;
+
+ /* Clear out errors and receive interrupts */
+ if (likely(status != 0)) {
+ if (unlikely(status & (RxFIFOOver | RxOverflow))) {
+ tp->stats.rx_errors++;
+ if (status & RxFIFOOver)
+ tp->stats.rx_fifo_errors++;
+ }
+ RTL_W16_F (IntrStatus, RxAckBits);
+ }
+}
+
+static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
+ int budget)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int received = 0;
+ unsigned char *rx_ring = tp->rx_ring;
+ unsigned int cur_rx = tp->cur_rx;
+ unsigned int rx_size = 0;
+
+ DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+#if 0
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ rtl_ec_dev.rx_intr_cnt++;
+ rdtscl(rtl_ec_dev.rx_time); // Get CPU cycles
+ }
+#endif
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ while ((EtherCAT_dev_is_ec(rtl_ec_dev, dev) || netif_running(dev))
+ && received < budget
+ && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
+ u32 ring_offset = cur_rx % RX_BUF_LEN;
+ u32 rx_status;
+ unsigned int pkt_size;
+ struct sk_buff *skb;
+
+ rmb();
+
+ /* read size+status of next frame from DMA ring buffer */
+ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+ rx_size = rx_status >> 16;
+ pkt_size = rx_size - 4;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev) && netif_msg_rx_status(tp))
+ printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x,"
+ " cur %4.4x.\n", dev->name, rx_status,
+ rx_size, cur_rx);
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+#if RTL8139_DEBUG > 2
+ {
+ int i;
+ DPRINTK ("%s: Frame contents ", dev->name);
+ for (i = 0; i < 70; i++)
+ printk (" %2.2x",
+ rx_ring[ring_offset + i]);
+ printk (".\n");
+ }
+#endif
+
+ /* Packet copy from FIFO still in progress.
+ * Theoretically, this should never happen
+ * since EarlyRx is disabled.
+ */
+ if (unlikely(rx_size == 0xfff0)) {
+ if (!tp->fifo_copy_timeout)
+ tp->fifo_copy_timeout = jiffies + 2;
+ else if (time_after(jiffies, tp->fifo_copy_timeout)) {
+ DPRINTK ("%s: hung FIFO. Reset.", dev->name);
+ rx_size = 0;
+ goto no_early_rx;
+ }
+ if (netif_msg_intr(tp)) {
+ printk(KERN_DEBUG "%s: fifo copy in progress.",
+ dev->name);
+ }
+ tp->xstats.early_rx++;
+ break;
+ }
+
+no_early_rx:
+ tp->fifo_copy_timeout = 0;
+
+ /* If Rx err or invalid rx_size/rx_status received
+ * (which happens if we get lost in the ring),
+ * Rx process gets reset, so we abort any further
+ * Rx processing.
+ */
+ if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+ (rx_size < 8) ||
+ (!(rx_status & RxStatusOK)))) {
+ rtl8139_rx_err (rx_status, dev, tp, ioaddr);
+ received = -1;
+ goto out;
+ }
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ /* Malloc up new buffer, compatible with net-2e. */
+ /* Omit the four octet CRC from the length. */
+ skb = dev_alloc_skb(pkt_size + 2);
+
+ if (likely(skb)) {
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align the IP fields. */
+#if RX_BUF_IDX == 3
+ wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
+#else
+ eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+#endif
+ skb_put (skb, pkt_size);
+
+ skb->protocol = eth_type_trans (skb, dev);
+
+ dev->last_rx = jiffies;
+ tp->stats.rx_bytes += pkt_size;
+ tp->stats.rx_packets++;
+
+ netif_receive_skb (skb);
+ } else {
+ if (net_ratelimit())
+ printk (KERN_WARNING
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ tp->stats.rx_dropped++;
+ }
+ }
+ else
+ {
+ if (EtherCAT_dev_receive(rtl_ec_dev,
+ &rx_ring[ring_offset + 4] + ETH_HLEN,
+ pkt_size - ETH_HLEN) == 0)
+ {
+ dev->last_rx = jiffies;
+ tp->stats.rx_bytes += pkt_size;
+ tp->stats.rx_packets++;
+ }
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ received++;
+
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+ RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
+
+ rtl8139_isr_ack(tp);
+ }
+
+ if (unlikely(!received || rx_size == 0xfff0))
+ rtl8139_isr_ack(tp);
+
+#if RTL8139_DEBUG > 1
+ DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+#endif
+
+ tp->cur_rx = cur_rx;
+
+ /*
+ * The receive buffer should be mostly empty.
+ * Tell NAPI to reenable the Rx irq.
+ */
+ if (tp->fifo_copy_timeout)
+ received = budget;
+
+out:
+ return received;
+}
+
+
+static void rtl8139_weird_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr,
+ int status, int link_changed)
+{
+ DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+ dev->name, status);
+
+ assert (dev != NULL);
+ assert (tp != NULL);
+ assert (ioaddr != NULL);
+
+ /* Update the error count. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ if ((status & RxUnderrun) && link_changed &&
+ (tp->drv_flags & HAS_LNK_CHNG)) {
+ rtl_check_media(dev, 0);
+ status &= ~RxUnderrun;
+ }
+
+ if (status & (RxUnderrun | RxErr))
+ tp->stats.rx_errors++;
+
+ if (status & PCSTimeout)
+ tp->stats.rx_length_errors++;
+ if (status & RxUnderrun)
+ tp->stats.rx_fifo_errors++;
+ if (status & PCIErr) {
+ u16 pci_cmd_status;
+ pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+ pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
+
+ printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+ dev->name, pci_cmd_status);
+ }
+}
+
+int rtl8139_poll(struct net_device *dev, int *budget)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int orig_budget = min(*budget, dev->quota);
+ int done = 1;
+
+ spin_lock(&tp->rx_lock);
+ if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
+ int work_done;
+
+ work_done = rtl8139_rx(dev, tp, orig_budget);
+ if (likely(work_done > 0)) {
+ *budget -= work_done;
+ dev->quota -= work_done;
+ done = (work_done < orig_budget);
+ }
+ }
+
+ if (done) {
+ /*
+ * Order is important since data can get interrupted
+ * again when we think we are done.
+ */
+
+ local_irq_disable();
+ RTL_W16_F(IntrMask, rtl8139_intr_mask);
+ __netif_rx_complete(dev);
+ local_irq_enable();
+ }
+ spin_unlock(&tp->rx_lock);
+
+ return !done;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u16 status, ackstat;
+ int link_changed = 0; /* avoid bogus "uninit" warning */
+ int handled = 0;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+#if 0 // FIXME
+ rtl_ec_dev.intr_cnt++;
+#endif
+ status = RTL_R16 (IntrStatus);
+ }
+ else
+ {
+ spin_lock(&tp->lock);
+
+ status = RTL_R16 (IntrStatus);
+
+ if (unlikely((status & rtl8139_intr_mask) == 0))
+ goto out;
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ handled = 1;
+
+ /* h/w no longer present (hotplug?) or major error, bail */
+ if (unlikely(status == 0xFFFF))
+ goto out;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ /* close possible race's with dev_close */
+ if (unlikely(!netif_running(dev))) {
+ RTL_W16 (IntrMask, 0);
+ goto out;
+ }
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ /* Acknowledge all of the current interrupt sources ASAP, but
+ an first get an additional status bit from CSCR. */
+ if (unlikely(status & RxUnderrun))
+ link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+
+ ackstat = status & ~(RxAckBits | TxErr);
+ if (ackstat) {
+ RTL_W16 (IntrStatus, ackstat);
+ }
+
+ /* Receive packets are processed by poll routine.
+ If not running start it now. */
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (status & RxAckBits)
+ {
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ /* Polling vormerken */
+ if (netif_rx_schedule_prep(dev)) {
+ RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
+ __netif_rx_schedule (dev);
+ }
+ }
+ else
+ {
+ /* Beim EtherCAT-Device einfach alle Frames empfangen */
+ rtl8139_rx(dev, tp, 100); // FIXME Das ist echt dirty...
+ }
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ /* Check uncommon events with one test. */
+ if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr)))
+ rtl8139_weird_interrupt (dev, tp, ioaddr,
+ status, link_changed);
+
+ if (status & (TxOK | TxErr)) {
+ rtl8139_tx_interrupt (dev, tp, ioaddr);
+ if (status & TxErr)
+ RTL_W16 (IntrStatus, TxErr);
+ }
+ out:
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ spin_unlock (&tp->lock);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+ return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void rtl8139_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ rtl8139_interrupt(dev->irq, dev, NULL);
+ enable_irq(dev->irq);
+}
+#endif
+
+static int rtl8139_close (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int ret = 0;
+ unsigned long flags;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (!EtherCAT_dev_is_ec(rtl_ec_dev, dev))
+ {
+ netif_stop_queue(dev);
+ if (tp->thr_pid >= 0) {
+ tp->time_to_die = 1;
+ wmb();
+ ret = kill_proc (tp->thr_pid, SIGTERM, 1);
+ if (ret) {
+ printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
+ return ret;
+ }
+ wait_for_completion (&tp->thr_exited);
+ }
+
+ if (netif_msg_ifdown(tp))
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ /* Stop the chip's Tx and Rx DMA processes. */
+ RTL_W8 (ChipCmd, 0);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ synchronize_irq (dev->irq); /* racy, but that's ok here */
+ free_irq (dev->irq, dev);
+ }
+ else
+ {
+ /* Stop the chip's Tx and Rx DMA processes. */
+ RTL_W8 (ChipCmd, 0);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ rtl8139_tx_clear (tp);
+
+ pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+ pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ tp->rx_ring = NULL;
+ tp->tx_bufs = NULL;
+
+ /* Green! Put the chip in low-power mode. */
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ return 0;
+}
+
+
+/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to
+ kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
+ other threads or interrupts aren't messing with the 8139. */
+static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->mmio_addr;
+
+ spin_lock_irq(&np->lock);
+ if (rtl_chip_info[np->chipset].flags & HasLWake) {
+ u8 cfg3 = RTL_R8 (Config3);
+ u8 cfg5 = RTL_R8 (Config5);
+
+ wol->supported = WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+
+ wol->wolopts = 0;
+ if (cfg3 & Cfg3_LinkUp)
+ wol->wolopts |= WAKE_PHY;
+ if (cfg3 & Cfg3_Magic)
+ wol->wolopts |= WAKE_MAGIC;
+ /* (KON)FIXME: See how netdev_set_wol() handles the
+ following constants. */
+ if (cfg5 & Cfg5_UWF)
+ wol->wolopts |= WAKE_UCAST;
+ if (cfg5 & Cfg5_MWF)
+ wol->wolopts |= WAKE_MCAST;
+ if (cfg5 & Cfg5_BWF)
+ wol->wolopts |= WAKE_BCAST;
+ }
+ spin_unlock_irq(&np->lock);
+}
+
+
+/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes
+ that wol points to kernel memory and other threads or interrupts
+ aren't messing with the 8139. */
+static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->mmio_addr;
+ u32 support;
+ u8 cfg3, cfg5;
+
+ support = ((rtl_chip_info[np->chipset].flags & HasLWake)
+ ? (WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)
+ : 0);
+ if (wol->wolopts & ~support)
+ return -EINVAL;
+
+ spin_lock_irq(&np->lock);
+ cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
+ if (wol->wolopts & WAKE_PHY)
+ cfg3 |= Cfg3_LinkUp;
+ if (wol->wolopts & WAKE_MAGIC)
+ cfg3 |= Cfg3_Magic;
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config3, cfg3);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF);
+ /* (KON)FIXME: These are untested. We may have to set the
+ CRC0, Wakeup0 and LSBCRC0 registers too, but I have no
+ documentation. */
+ if (wol->wolopts & WAKE_UCAST)
+ cfg5 |= Cfg5_UWF;
+ if (wol->wolopts & WAKE_MCAST)
+ cfg5 |= Cfg5_MWF;
+ if (wol->wolopts & WAKE_BCAST)
+ cfg5 |= Cfg5_BWF;
+ RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(np->pci_dev));
+ info->regdump_len = np->regs_len;
+}
+
+static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&np->mii, cmd);
+ spin_unlock_irq(&np->lock);
+ return 0;
+}
+
+static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ int rc;
+ spin_lock_irq(&np->lock);
+ rc = mii_ethtool_sset(&np->mii, cmd);
+ spin_unlock_irq(&np->lock);
+ return rc;
+}
+
+static int rtl8139_nway_reset(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return mii_nway_restart(&np->mii);
+}
+
+static u32 rtl8139_get_link(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return mii_link_ok(&np->mii);
+}
+
+static u32 rtl8139_get_msglevel(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return np->msg_enable;
+}
+
+static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ np->msg_enable = datum;
+}
+
+/* TODO: we are too slack to do reg dumping for pio, for now */
+#ifdef CONFIG_8139TOO_PIO
+#define rtl8139_get_regs_len NULL
+#define rtl8139_get_regs NULL
+#else
+static int rtl8139_get_regs_len(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return np->regs_len;
+}
+
+static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+
+ regs->version = RTL_REGS_VER;
+
+ spin_lock_irq(&np->lock);
+ memcpy_fromio(regbuf, np->mmio_addr, regs->len);
+ spin_unlock_irq(&np->lock);
+}
+#endif /* CONFIG_8139TOO_MMIO */
+
+static int rtl8139_get_stats_count(struct net_device *dev)
+{
+ return RTL_NUM_STATS;
+}
+
+static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+
+ data[0] = np->xstats.early_rx;
+ data[1] = np->xstats.tx_buf_mapped;
+ data[2] = np->xstats.tx_timeouts;
+ data[3] = np->xstats.rx_lost_in_ring;
+}
+
+static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static struct ethtool_ops rtl8139_ethtool_ops = {
+ .get_drvinfo = rtl8139_get_drvinfo,
+ .get_settings = rtl8139_get_settings,
+ .set_settings = rtl8139_set_settings,
+ .get_regs_len = rtl8139_get_regs_len,
+ .get_regs = rtl8139_get_regs,
+ .nway_reset = rtl8139_nway_reset,
+ .get_link = rtl8139_get_link,
+ .get_msglevel = rtl8139_get_msglevel,
+ .set_msglevel = rtl8139_set_msglevel,
+ .get_wol = rtl8139_get_wol,
+ .set_wol = rtl8139_set_wol,
+ .get_strings = rtl8139_get_strings,
+ .get_stats_count = rtl8139_get_stats_count,
+ .get_ethtool_stats = rtl8139_get_ethtool_stats,
+};
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ int rc;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev) || !netif_running(dev))
+ return -EINVAL;
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ spin_lock_irq(&np->lock);
+ rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL);
+ spin_unlock_irq(&np->lock);
+
+ return rc;
+}
+
+
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned long flags;
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev) || netif_running(dev))
+ {
+ spin_lock_irqsave (&tp->lock, flags);
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+ spin_unlock_irqrestore (&tp->lock, flags);
+ }
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ This routine is not state sensitive and need not be SMP locked. */
+
+static void __set_rx_mode (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ int i, rx_mode;
+ u32 tmp;
+
+ DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
+ dev->name, dev->flags, RTL_R32 (RxConfig));
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+ dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else {
+ struct dev_mc_list *mclist;
+ rx_mode = AcceptBroadcast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ rx_mode |= AcceptMulticast;
+ }
+ }
+
+ /* We can safely update without stopping the chip. */
+ tmp = rtl8139_rx_config | rx_mode;
+ if (tp->rx_config != tmp) {
+ RTL_W32_F (RxConfig, tmp);
+ tp->rx_config = tmp;
+ }
+ RTL_W32_F (MAR0 + 0, mc_filter[0]);
+ RTL_W32_F (MAR0 + 4, mc_filter[1]);
+}
+
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+ unsigned long flags;
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ spin_lock_irqsave (&tp->lock, flags);
+ __set_rx_mode(dev);
+ spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+#ifdef CONFIG_PM
+
+static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned long flags;
+
+ pci_save_state (pdev);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev) || !netif_running (dev))
+ return 0;
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ netif_device_detach (dev);
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ RTL_W16 (IntrMask, 0);
+ RTL_W8 (ChipCmd, 0);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ pci_set_power_state (pdev, PCI_D3hot);
+
+ return 0;
+}
+
+
+static int rtl8139_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ pci_restore_state (pdev);
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ if (EtherCAT_dev_is_ec(rtl_ec_dev, dev) || !netif_running (dev))
+ return 0;
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+ pci_set_power_state (pdev, PCI_D0);
+ rtl8139_init_ring (dev);
+ rtl8139_hw_start (dev);
+ netif_device_attach (dev);
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+static struct pci_driver rtl8139_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rtl8139_pci_tbl,
+ .probe = rtl8139_init_one,
+ .remove = __devexit_p(rtl8139_remove_one),
+#ifdef CONFIG_PM
+ .suspend = rtl8139_suspend,
+ .resume = rtl8139_resume,
+#endif /* CONFIG_PM */
+};
+
+
+static int __init rtl8139_init_module (void)
+{
+ /* when we're a module, we always print a version message,
+ * even if no 8139 board is found.
+ */
+#ifdef MODULE
+ printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+#endif
+
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ printk(KERN_INFO "Initializing RTL8139-EtherCAT module. %s\n", COMPILE_INFO);
+ printk(KERN_INFO "EtherCAT device index is %i.\n", ec_device_index);
+
+ if (pci_module_init(&rtl8139_pci_driver) < 0)
+ {
+ printk(KERN_ERR "Could not init PCI module.\n");
+ goto out_ec_dev;
+ }
+
+ if (!rtl_ec_dev)
+ {
+ printk(KERN_WARNING "NO EtherCAT device registered!\n");
+ }
+
+ return 0;
+
+ out_ec_dev:
+ if (rtl_ec_dev) {
+ printk(KERN_INFO "Unregistering RTL8139-EtherCAT device...\n");
+ EtherCAT_dev_unregister(ec_device_master_index);
+ rtl_ec_dev = NULL;
+ }
+
+ return -1;
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+}
+
+
+static void __exit rtl8139_cleanup_module (void)
+{
+ /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+
+ printk(KERN_INFO "Cleaning up RTL8139-EtherCAT module...\n");
+
+ if (rtl_ec_dev) {
+ printk(KERN_INFO "Unregistering RTL8139-EtherCAT device...\n");
+ EtherCAT_dev_unregister(ec_device_master_index);
+ rtl_ec_dev = NULL;
+ }
+
+ pci_unregister_driver(&rtl8139_pci_driver);
+
+ printk(KERN_INFO "RTL8139-EtherCAT module cleaned up.\n");
+
+ /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+}
+
+
+module_init(rtl8139_init_module);
+module_exit(rtl8139_cleanup_module);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devices/Makefile Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,46 @@
+#------------------------------------------------------------------------------
+#
+# Makefile
+#
+# IgH EtherCAT-Treiber - EtherCAT Geraete
+#
+# $Id$
+#
+#------------------------------------------------------------------------------
+
+ifneq ($(KERNELRELEASE),)
+
+#------------------------------------------------------------------------------
+# Kbuild-Abschnitt
+
+obj-m := ec_8139too.o
+
+ec_8139too-objs := 8139too.o
+
+REV = `svnversion $(src)`
+DATE = `date`
+
+EXTRA_CFLAGS = -DEC_REV="$(REV)" -DEC_USER="$(USER)" -DEC_DATE="$(DATE)"
+
+#------------------------------------------------------------------------------
+
+else
+
+#------------------------------------------------------------------------------
+# Default-Abschnitt
+
+ifneq ($(wildcard ethercat.conf),)
+include ethercat.conf
+else
+KERNELDIR = /lib/modules/`uname -r`/build
+endif
+
+modules:
+ $(MAKE) -C $(KERNELDIR) M=`pwd` modules
+
+clean:
+ $(MAKE) -C $(KERNELDIR) M=`pwd` clean
+
+#------------------------------------------------------------------------------
+
+endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devices/original_8139too.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,2646 @@
+/*
+
+ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+ Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Copyright 2000-2002 Jeff Garzik
+
+ Much code comes from Donald Becker's rtl8139.c driver,
+ versions 1.13 and older. This driver was originally based
+ on rtl8139.c version 1.07. Header of rtl8139.c version 1.13:
+
+ -----<snip>-----
+
+ Written 1997-2001 by Donald Becker.
+ This software may be used and distributed according to the
+ terms of the GNU General Public License (GPL), incorporated
+ herein by reference. Drivers based on or derived from this
+ code fall under the GPL and must retain the authorship,
+ copyright and license notice. This file is not a complete
+ program and may only be used when the entire operating
+ system is licensed under the GPL.
+
+ This driver is for boards based on the RTL8129 and RTL8139
+ PCI ethernet chips.
+
+ The author may be reached as becker@scyld.com, or C/O Scyld
+ Computing Corporation 410 Severn Ave., Suite 210 Annapolis
+ MD 21403
+
+ Support and updates available at
+ http://www.scyld.com/network/rtl8139.html
+
+ Twister-tuning table provided by Kinston
+ <shangh@realtek.com.tw>.
+
+ -----<snip>-----
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ Contributors:
+
+ Donald Becker - he wrote the original driver, kudos to him!
+ (but please don't e-mail him for support, this isn't his driver)
+
+ Tigran Aivazian - bug fixes, skbuff free cleanup
+
+ Martin Mares - suggestions for PCI cleanup
+
+ David S. Miller - PCI DMA and softnet updates
+
+ Ernst Gill - fixes ported from BSD driver
+
+ Daniel Kobras - identified specific locations of
+ posted MMIO write bugginess
+
+ Gerard Sharp - bug fix, testing and feedback
+
+ David Ford - Rx ring wrap fix
+
+ Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
+ to find and fix a crucial bug on older chipsets.
+
+ Donald Becker/Chris Butterworth/Marcus Westergren -
+ Noticed various Rx packet size-related buglets.
+
+ Santiago Garcia Mantinan - testing and feedback
+
+ Jens David - 2.2.x kernel backports
+
+ Martin Dennett - incredibly helpful insight on undocumented
+ features of the 8139 chips
+
+ Jean-Jacques Michel - bug fix
+
+ Tobias Ringström - Rx interrupt status checking suggestion
+
+ Andrew Morton - Clear blocked signals, avoid
+ buffer overrun setting current->comm.
+
+ Kalle Olavi Niemitalo - Wake-on-LAN ioctls
+
+ Robert Kuebel - Save kernel thread from dying on any signal.
+
+ Submitting bug reports:
+
+ "rtl8139-diag -mmmaaavvveefN" output
+ enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
+
+*/
+
+#define DRV_NAME "8139too"
+#define DRV_VERSION "0.9.27"
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/completion.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
+#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
+#define PFX DRV_NAME ": "
+
+/* Default Message level */
+#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+
+
+/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
+#ifdef CONFIG_8139TOO_PIO
+#define USE_IO_OPS 1
+#endif
+
+/* define to 1, 2 or 3 to enable copious debugging info */
+#define RTL8139_DEBUG 0
+
+/* define to 1 to disable lightweight runtime debugging checks */
+#undef RTL8139_NDEBUG
+
+
+#if RTL8139_DEBUG
+/* note: prints function name for you */
+# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+# define DPRINTK(fmt, args...)
+#endif
+
+#ifdef RTL8139_NDEBUG
+# define assert(expr) do {} while (0)
+#else
+# define assert(expr) \
+ if(unlikely(!(expr))) { \
+ printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+
+/* A few user-configurable values. */
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ The RTL chips use a 64 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+
+/* bitmapped message enable number */
+static int debug = -1;
+
+/*
+ * Receive ring size
+ * Warning: 64K ring has hardware issues and may lock up.
+ */
+#if defined(CONFIG_SH_DREAMCAST)
+#define RX_BUF_IDX 1 /* 16K ring */
+#else
+#define RX_BUF_IDX 2 /* 32K ring */
+#endif
+#define RX_BUF_LEN (8192 << RX_BUF_IDX)
+#define RX_BUF_PAD 16
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+
+#if RX_BUF_LEN == 65536
+#define RX_BUF_TOT_LEN RX_BUF_LEN
+#else
+#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+#endif
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* PCI Tuning Parameters
+ Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (6*HZ)
+
+
+enum {
+ HAS_MII_XCVR = 0x010000,
+ HAS_CHIP_XCVR = 0x020000,
+ HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_NUM_STATS 4 /* number of ETHTOOL_GSTATS u64's */
+#define RTL_REGS_VER 1 /* version of reg. data in ETHTOOL_GREGS */
+#define RTL_MIN_IO_SIZE 0x80
+#define RTL8139B_IO_SIZE 256
+
+#define RTL8129_CAPS HAS_MII_XCVR
+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+ RTL8139 = 0,
+ RTL8129,
+} board_t;
+
+
+/* indexed by board_t, above */
+static struct {
+ const char *name;
+ u32 hw_flags;
+} board_info[] __devinitdata = {
+ { "RealTek RTL8139", RTL8139_CAPS },
+ { "RealTek RTL8129", RTL8129_CAPS },
+};
+
+
+static struct pci_device_id rtl8139_pci_tbl[] = {
+ {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1259, 0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+ /* Bogus 8139 silicon reports 8129 without external PROM :-( */
+ {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+#endif
+#ifdef CONFIG_8139TOO_8129
+ {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
+#endif
+
+ /* some crazy cards report invalid vendor ids like
+ * 0x0001 here. The other ids are valid and constant,
+ * so we simply don't match on the main vendor id.
+ */
+ {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
+ {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
+ {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
+
+ {0,}
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+static struct {
+ const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "early_rx" },
+ { "tx_buf_mapped" },
+ { "tx_timeouts" },
+ { "rx_lost_in_ring" },
+};
+
+/* The rest of these values should never change. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf = 0x30,
+ ChipCmd = 0x37,
+ RxBufPtr = 0x38,
+ RxBufAddr = 0x3A,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ Timer = 0x48, /* A general-purpose counter. */
+ RxMissed = 0x4C, /* 24 bits valid, write clears. */
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ FlashReg = 0x54,
+ MediaStatus = 0x58,
+ Config3 = 0x59,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
+ /* Undocumented registers, but required for proper operation. */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ CSCR = 0x74, /* Chip Status and Configuration Register. */
+ PARA78 = 0x78,
+ PARA7c = 0x7c, /* Magic transceiver parameter register. */
+ Config5 = 0xD8, /* absent on RTL-8139A */
+};
+
+enum ClearBitMasks {
+ MultiIntrClear = 0xF000,
+ ChipCmdClear = 0xE2,
+ Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+};
+
+enum ChipCmdBits {
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+ PCIErr = 0x8000,
+ PCSTimeout = 0x4000,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+
+ RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+};
+
+enum TxStatusBits {
+ TxHostOwns = 0x2000,
+ TxUnderrun = 0x4000,
+ TxStatOK = 0x8000,
+ TxOutOfWindow = 0x20000000,
+ TxAborted = 0x40000000,
+ TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+ RxMulticast = 0x8000,
+ RxPhysical = 0x4000,
+ RxBroadcast = 0x2000,
+ RxBadSymbol = 0x0020,
+ RxRunt = 0x0010,
+ RxTooLong = 0x0008,
+ RxCRCErr = 0x0004,
+ RxBadAlign = 0x0002,
+ RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits {
+
+ /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+ TxIFGShift = 24,
+ TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+ TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+ TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+ TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
+
+ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
+ TxClearAbt = (1 << 0), /* Clear abort (WO) */
+ TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
+ TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
+
+ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ LWAKE = 0x10, /* not on 8139, 8139A */
+ Cfg1_Driver_Load = 0x20,
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+ SLEEP = (1 << 1), /* only on 8139, 8139A */
+ PWRDN = (1 << 0), /* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum Config3Bits {
+ Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
+ Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+ Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+ Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
+ Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
+ Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+ Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
+ Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum Config4Bits {
+ LWPTN = (1 << 2), /* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum Config5Bits {
+ Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
+ Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
+ Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
+ Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
+ Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
+ Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
+ Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum RxConfigBits {
+ /* rx fifo threshold */
+ RxCfgFIFOShift = 13,
+ RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+ /* Max DMA burst */
+ RxCfgDMAShift = 8,
+ RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+ /* rx ring buffer length */
+ RxCfgRcv8K = 0,
+ RxCfgRcv16K = (1 << 11),
+ RxCfgRcv32K = (1 << 12),
+ RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+ /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+ RxNoWrap = (1 << 7),
+};
+
+/* Twister tuning parameters from RealTek.
+ Completely undocumented, but required to tune bad links on some boards. */
+enum CSCRBits {
+ CSCR_LinkOKBit = 0x0400,
+ CSCR_LinkChangeBit = 0x0800,
+ CSCR_LinkStatusBits = 0x0f000,
+ CSCR_LinkDownOffCmd = 0x003c0,
+ CSCR_LinkDownCmd = 0x0f3c0,
+};
+
+enum Cfg9346Bits {
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
+};
+
+typedef enum {
+ CH_8139 = 0,
+ CH_8139_K,
+ CH_8139A,
+ CH_8139A_G,
+ CH_8139B,
+ CH_8130,
+ CH_8139C,
+ CH_8100,
+ CH_8100B_8139D,
+ CH_8101,
+} chip_t;
+
+enum chip_flags {
+ HasHltClk = (1 << 0),
+ HasLWake = (1 << 1),
+};
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+ (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
+
+/* directly indexed by chip_t, above */
+const static struct {
+ const char *name;
+ u32 version; /* from RTL8139C/RTL8139D docs */
+ u32 flags;
+} rtl_chip_info[] = {
+ { "RTL-8139",
+ HW_REVID(1, 0, 0, 0, 0, 0, 0),
+ HasHltClk,
+ },
+
+ { "RTL-8139 rev K",
+ HW_REVID(1, 1, 0, 0, 0, 0, 0),
+ HasHltClk,
+ },
+
+ { "RTL-8139A",
+ HW_REVID(1, 1, 1, 0, 0, 0, 0),
+ HasHltClk, /* XXX undocumented? */
+ },
+
+ { "RTL-8139A rev G",
+ HW_REVID(1, 1, 1, 0, 0, 1, 0),
+ HasHltClk, /* XXX undocumented? */
+ },
+
+ { "RTL-8139B",
+ HW_REVID(1, 1, 1, 1, 0, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8130",
+ HW_REVID(1, 1, 1, 1, 1, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8139C",
+ HW_REVID(1, 1, 1, 0, 1, 0, 0),
+ HasLWake,
+ },
+
+ { "RTL-8100",
+ HW_REVID(1, 1, 1, 1, 0, 1, 0),
+ HasLWake,
+ },
+
+ { "RTL-8100B/8139D",
+ HW_REVID(1, 1, 1, 0, 1, 0, 1),
+ HasLWake,
+ },
+
+ { "RTL-8101",
+ HW_REVID(1, 1, 1, 0, 1, 1, 1),
+ HasLWake,
+ },
+};
+
+struct rtl_extra_stats {
+ unsigned long early_rx;
+ unsigned long tx_buf_mapped;
+ unsigned long tx_timeouts;
+ unsigned long rx_lost_in_ring;
+};
+
+struct rtl8139_private {
+ void __iomem *mmio_addr;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ u32 msg_enable;
+ struct net_device_stats stats;
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
+ unsigned int tx_flag;
+ unsigned long cur_tx;
+ unsigned long dirty_tx;
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_bufs_dma;
+ signed char phys[4]; /* MII device addresses. */
+ char twistie, twist_row, twist_col; /* Twister tune state. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ spinlock_t lock;
+ spinlock_t rx_lock;
+ chip_t chipset;
+ pid_t thr_pid;
+ wait_queue_head_t thr_wait;
+ struct completion thr_exited;
+ u32 rx_config;
+ struct rtl_extra_stats xstats;
+ int time_to_die;
+ struct mii_if_info mii;
+ unsigned int regs_len;
+ unsigned long fifo_copy_timeout;
+};
+
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
+MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(multicast_filter_limit, int, 0);
+module_param_array(media, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+module_param(debug, int, 0);
+MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
+MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
+MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
+
+static int read_eeprom (void __iomem *ioaddr, int location, int addr_len);
+static int rtl8139_open (struct net_device *dev);
+static int mdio_read (struct net_device *dev, int phy_id, int location);
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int val);
+static void rtl8139_start_thread(struct net_device *dev);
+static void rtl8139_tx_timeout (struct net_device *dev);
+static void rtl8139_init_ring (struct net_device *dev);
+static int rtl8139_start_xmit (struct sk_buff *skb,
+ struct net_device *dev);
+static int rtl8139_poll(struct net_device *dev, int *budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void rtl8139_poll_controller(struct net_device *dev);
+#endif
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs);
+static int rtl8139_close (struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static void rtl8139_set_rx_mode (struct net_device *dev);
+static void __set_rx_mode (struct net_device *dev);
+static void rtl8139_hw_start (struct net_device *dev);
+static struct ethtool_ops rtl8139_ethtool_ops;
+
+/* write MMIO register, with flush */
+/* Flush avoids rtl8139 bug w/ posted MMIO writes */
+#define RTL_W8_F(reg, val8) do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)
+#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
+#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
+
+
+#define MMIO_FLUSH_AUDIT_COMPLETE 1
+#if MMIO_FLUSH_AUDIT_COMPLETE
+
+/* write MMIO register */
+#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
+
+#else
+
+/* write MMIO register, then flush */
+#define RTL_W8 RTL_W8_F
+#define RTL_W16 RTL_W16_F
+#define RTL_W32 RTL_W32_F
+
+#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
+
+/* read MMIO register */
+#define RTL_R8(reg) ioread8 (ioaddr + (reg))
+#define RTL_R16(reg) ioread16 (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
+
+
+static const u16 rtl8139_intr_mask =
+ PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
+ TxErr | TxOK | RxErr | RxOK;
+
+static const u16 rtl8139_norx_intr_mask =
+ PCIErr | PCSTimeout | RxUnderrun |
+ TxErr | TxOK | RxErr ;
+
+#if RX_BUF_IDX == 0
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv8K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 1
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv16K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 2
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv32K | RxNoWrap |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#elif RX_BUF_IDX == 3
+static const unsigned int rtl8139_rx_config =
+ RxCfgRcv64K |
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+#else
+#error "Invalid configuration for 8139_RXBUF_IDX"
+#endif
+
+static const unsigned int rtl8139_tx_config =
+ TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+
+static void __rtl8139_cleanup_dev (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ struct pci_dev *pdev;
+
+ assert (dev != NULL);
+ assert (tp->pci_dev != NULL);
+ pdev = tp->pci_dev;
+
+#ifdef USE_IO_OPS
+ if (tp->mmio_addr)
+ ioport_unmap (tp->mmio_addr);
+#else
+ if (tp->mmio_addr)
+ pci_iounmap (pdev, tp->mmio_addr);
+#endif /* USE_IO_OPS */
+
+ /* it's ok to call this even if we have no regions to free */
+ pci_release_regions (pdev);
+
+ free_netdev(dev);
+ pci_set_drvdata (pdev, NULL);
+}
+
+
+static void rtl8139_chip_reset (void __iomem *ioaddr)
+{
+ int i;
+
+ /* Soft reset the chip. */
+ RTL_W8 (ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 1000; i > 0; i--) {
+ barrier();
+ if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+ break;
+ udelay (10);
+ }
+}
+
+
+static int __devinit rtl8139_init_board (struct pci_dev *pdev,
+ struct net_device **dev_out)
+{
+ void __iomem *ioaddr;
+ struct net_device *dev;
+ struct rtl8139_private *tp;
+ u8 tmp8;
+ int rc, disable_dev_on_err = 0;
+ unsigned int i;
+ unsigned long pio_start, pio_end, pio_flags, pio_len;
+ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+ u32 version;
+
+ assert (pdev != NULL);
+
+ *dev_out = NULL;
+
+ /* dev and priv zeroed in alloc_etherdev */
+ dev = alloc_etherdev (sizeof (*tp));
+ if (dev == NULL) {
+ printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+ return -ENOMEM;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ tp = netdev_priv(dev);
+ tp->pci_dev = pdev;
+
+ /* enable device (incl. PCI PM wakeup and hotplug setup) */
+ rc = pci_enable_device (pdev);
+ if (rc)
+ goto err_out;
+
+ pio_start = pci_resource_start (pdev, 0);
+ pio_end = pci_resource_end (pdev, 0);
+ pio_flags = pci_resource_flags (pdev, 0);
+ pio_len = pci_resource_len (pdev, 0);
+
+ mmio_start = pci_resource_start (pdev, 1);
+ mmio_end = pci_resource_end (pdev, 1);
+ mmio_flags = pci_resource_flags (pdev, 1);
+ mmio_len = pci_resource_len (pdev, 1);
+
+ /* set this immediately, we need to know before
+ * we talk to the chip directly */
+ DPRINTK("PIO region size == 0x%02X\n", pio_len);
+ DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
+
+#ifdef USE_IO_OPS
+ /* make sure PCI base addr 0 is PIO */
+ if (!(pio_flags & IORESOURCE_IO)) {
+ printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+ /* check for weird/broken PCI region reporting */
+ if (pio_len < RTL_MIN_IO_SIZE) {
+ printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+#else
+ /* make sure PCI base addr 1 is MMIO */
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+ if (mmio_len < RTL_MIN_IO_SIZE) {
+ printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+ rc = -ENODEV;
+ goto err_out;
+ }
+#endif
+
+ rc = pci_request_regions (pdev, "8139too");
+ if (rc)
+ goto err_out;
+ disable_dev_on_err = 1;
+
+ /* enable PCI bus-mastering */
+ pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+ ioaddr = ioport_map(pio_start, pio_len);
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+ dev->base_addr = pio_start;
+ tp->mmio_addr = ioaddr;
+ tp->regs_len = pio_len;
+#else
+ /* ioremap MMIO region */
+ ioaddr = pci_iomap(pdev, 1, 0);
+ if (ioaddr == NULL) {
+ printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+ dev->base_addr = (long) ioaddr;
+ tp->mmio_addr = ioaddr;
+ tp->regs_len = mmio_len;
+#endif /* USE_IO_OPS */
+
+ /* Bring old chips out of low-power mode. */
+ RTL_W8 (HltClk, 'R');
+
+ /* check for missing/broken hardware */
+ if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
+ printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
+ pci_name(pdev));
+ rc = -EIO;
+ goto err_out;
+ }
+
+ /* identify chip attached to board */
+ version = RTL_R32 (TxConfig) & HW_REVID_MASK;
+ for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
+ if (version == rtl_chip_info[i].version) {
+ tp->chipset = i;
+ goto match;
+ }
+
+ /* if unknown chip, assume array element #0, original RTL-8139 in this case */
+ printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
+ pci_name(pdev));
+ printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+ tp->chipset = 0;
+
+match:
+ DPRINTK ("chipset id (%d) == index %d, '%s'\n",
+ version, i, rtl_chip_info[i].name);
+
+ if (tp->chipset >= CH_8139B) {
+ u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
+ DPRINTK("PCI PM wakeup\n");
+ if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
+ (tmp8 & LWAKE))
+ new_tmp8 &= ~LWAKE;
+ new_tmp8 |= Cfg1_PM_Enable;
+ if (new_tmp8 != tmp8) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config1, tmp8);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ }
+ if (rtl_chip_info[tp->chipset].flags & HasLWake) {
+ tmp8 = RTL_R8 (Config4);
+ if (tmp8 & LWPTN) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config4, tmp8 & ~LWPTN);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ }
+ }
+ } else {
+ DPRINTK("Old chip wakeup\n");
+ tmp8 = RTL_R8 (Config1);
+ tmp8 &= ~(SLEEP | PWRDN);
+ RTL_W8 (Config1, tmp8);
+ }
+
+ rtl8139_chip_reset (ioaddr);
+
+ *dev_out = dev;
+ return 0;
+
+err_out:
+ __rtl8139_cleanup_dev (dev);
+ if (disable_dev_on_err)
+ pci_disable_device (pdev);
+ return rc;
+}
+
+
+static int __devinit rtl8139_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev = NULL;
+ struct rtl8139_private *tp;
+ int i, addr_len, option;
+ void __iomem *ioaddr;
+ static int board_idx = -1;
+ u8 pci_rev;
+
+ assert (pdev != NULL);
+ assert (ent != NULL);
+
+ board_idx++;
+
+ /* when we're built into the kernel, the driver version message
+ * is only printed if at least one 8139 board has been found
+ */
+#ifndef MODULE
+ {
+ static int printed_version;
+ if (!printed_version++)
+ printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+ }
+#endif
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+ if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+ printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
+ printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ }
+
+ i = rtl8139_init_board (pdev, &dev);
+ if (i < 0)
+ return i;
+
+ assert (dev != NULL);
+ tp = netdev_priv(dev);
+
+ ioaddr = tp->mmio_addr;
+ assert (ioaddr != NULL);
+
+ addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ ((u16 *) (dev->dev_addr))[i] =
+ le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+
+ /* The Rtl8139-specific entries in the device structure. */
+ dev->open = rtl8139_open;
+ dev->hard_start_xmit = rtl8139_start_xmit;
+ dev->poll = rtl8139_poll;
+ dev->weight = 64;
+ dev->stop = rtl8139_close;
+ dev->get_stats = rtl8139_get_stats;
+ dev->set_multicast_list = rtl8139_set_rx_mode;
+ dev->do_ioctl = netdev_ioctl;
+ dev->ethtool_ops = &rtl8139_ethtool_ops;
+ dev->tx_timeout = rtl8139_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = rtl8139_poll_controller;
+#endif
+
+ /* note: the hardware is not capable of sg/csum/highdma, however
+ * through the use of skb_copy_and_csum_dev we enable these
+ * features
+ */
+ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+ dev->irq = pdev->irq;
+
+ /* tp zeroed and aligned in alloc_etherdev */
+ tp = netdev_priv(dev);
+
+ /* note: tp->chipset set in rtl8139_init_board */
+ tp->drv_flags = board_info[ent->driver_data].hw_flags;
+ tp->mmio_addr = ioaddr;
+ tp->msg_enable =
+ (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
+ spin_lock_init (&tp->lock);
+ spin_lock_init (&tp->rx_lock);
+ init_waitqueue_head (&tp->thr_wait);
+ init_completion (&tp->thr_exited);
+ tp->mii.dev = dev;
+ tp->mii.mdio_read = mdio_read;
+ tp->mii.mdio_write = mdio_write;
+ tp->mii.phy_id_mask = 0x3f;
+ tp->mii.reg_num_mask = 0x1f;
+
+ /* dev is fully set up and ready to use now */
+ DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
+ i = register_netdev (dev);
+ if (i) goto err_out;
+
+ pci_set_drvdata (pdev, dev);
+
+ printk (KERN_INFO "%s: %s at 0x%lx, "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+ "IRQ %d\n",
+ dev->name,
+ board_info[ent->driver_data].name,
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ dev->irq);
+
+ printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
+ dev->name, rtl_chip_info[tp->chipset].name);
+
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later, but
+ takes too much time. */
+#ifdef CONFIG_8139TOO_8129
+ if (tp->drv_flags & HAS_MII_XCVR) {
+ int phy, phy_idx = 0;
+ for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+ int mii_status = mdio_read(dev, phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ u16 advertising = mdio_read(dev, phy, 4);
+ tp->phys[phy_idx++] = phy;
+ printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+ "advertising %4.4x.\n",
+ dev->name, phy, mii_status, advertising);
+ }
+ }
+ if (phy_idx == 0) {
+ printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
+ "transceiver.\n",
+ dev->name);
+ tp->phys[0] = 32;
+ }
+ } else
+#endif
+ tp->phys[0] = 32;
+ tp->mii.phy_id = tp->phys[0];
+
+ /* The lower four bits are the media type. */
+ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+ if (option > 0) {
+ tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
+ tp->default_port = option & 0xFF;
+ if (tp->default_port)
+ tp->mii.force_media = 1;
+ }
+ if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
+ tp->mii.full_duplex = full_duplex[board_idx];
+ if (tp->mii.full_duplex) {
+ printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ /* Changing the MII-advertised media because might prevent
+ re-connection. */
+ tp->mii.force_media = 1;
+ }
+ if (tp->default_port) {
+ printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
+ (option & 0x20 ? 100 : 10),
+ (option & 0x10 ? "full" : "half"));
+ mdio_write(dev, tp->phys[0], 0,
+ ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */
+ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+ }
+
+ /* Put the chip into low-power mode. */
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ return 0;
+
+err_out:
+ __rtl8139_cleanup_dev (dev);
+ pci_disable_device (pdev);
+ return i;
+}
+
+
+static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ assert (dev != NULL);
+
+ unregister_netdev (dev);
+
+ __rtl8139_cleanup_dev (dev);
+ pci_disable_device (pdev);
+}
+
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay() RTL_R32(Cfg9346)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ RTL_W8 (Cfg9346, EE_ENB & ~EE_CS);
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ RTL_W8 (Cfg9346, EE_ENB | dataval);
+ eeprom_delay ();
+ RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK);
+ eeprom_delay ();
+ }
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+
+ for (i = 16; i > 0; i--) {
+ RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK);
+ eeprom_delay ();
+ retval =
+ (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 :
+ 0);
+ RTL_W8 (Cfg9346, EE_ENB);
+ eeprom_delay ();
+ }
+
+ /* Terminate the EEPROM access. */
+ RTL_W8 (Cfg9346, ~EE_CS);
+ eeprom_delay ();
+
+ return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+ serial MDIO protocol.
+ The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues. */
+#define MDIO_DIR 0x80
+#define MDIO_DATA_OUT 0x04
+#define MDIO_DATA_IN 0x02
+#define MDIO_CLK 0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay() RTL_R8(Config4)
+
+
+static char mii_2_8139_map[8] = {
+ BasicModeCtrl,
+ BasicModeStatus,
+ 0,
+ 0,
+ NWayAdvert,
+ NWayLPAR,
+ NWayExpansion,
+ 0
+};
+
+
+#ifdef CONFIG_8139TOO_8129
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync (void __iomem *ioaddr)
+{
+ int i;
+
+ for (i = 32; i >= 0; i--) {
+ RTL_W8 (Config4, MDIO_WRITE1);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK);
+ mdio_delay ();
+ }
+}
+#endif
+
+static int mdio_read (struct net_device *dev, int phy_id, int location)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int retval = 0;
+#ifdef CONFIG_8139TOO_8129
+ void __iomem *ioaddr = tp->mmio_addr;
+ int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int i;
+#endif
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ void __iomem *ioaddr = tp->mmio_addr;
+ return location < 8 && mii_2_8139_map[location] ?
+ RTL_R16 (mii_2_8139_map[location]) : 0;
+ }
+
+#ifdef CONFIG_8139TOO_8129
+ mdio_sync (ioaddr);
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+ RTL_W8 (Config4, MDIO_DIR | dataval);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK);
+ mdio_delay ();
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ RTL_W8 (Config4, 0);
+ mdio_delay ();
+ retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0);
+ RTL_W8 (Config4, MDIO_CLK);
+ mdio_delay ();
+ }
+#endif
+
+ return (retval >> 1) & 0xffff;
+}
+
+
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+ int value)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+#ifdef CONFIG_8139TOO_8129
+ void __iomem *ioaddr = tp->mmio_addr;
+ int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+ int i;
+#endif
+
+ if (phy_id > 31) { /* Really a 8139. Use internal registers. */
+ void __iomem *ioaddr = tp->mmio_addr;
+ if (location == 0) {
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W16 (BasicModeCtrl, value);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+ } else if (location < 8 && mii_2_8139_map[location])
+ RTL_W16 (mii_2_8139_map[location], value);
+ return;
+ }
+
+#ifdef CONFIG_8139TOO_8129
+ mdio_sync (ioaddr);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval =
+ (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+ RTL_W8 (Config4, dataval);
+ mdio_delay ();
+ RTL_W8 (Config4, dataval | MDIO_CLK);
+ mdio_delay ();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ RTL_W8 (Config4, 0);
+ mdio_delay ();
+ RTL_W8 (Config4, MDIO_CLK);
+ mdio_delay ();
+ }
+#endif
+}
+
+
+static int rtl8139_open (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int retval;
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
+ if (retval)
+ return retval;
+
+ tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ &tp->tx_bufs_dma);
+ tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ &tp->rx_ring_dma);
+ if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
+ free_irq(dev->irq, dev);
+
+ if (tp->tx_bufs)
+ pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ if (tp->rx_ring)
+ pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+
+ return -ENOMEM;
+
+ }
+
+ tp->mii.full_duplex = tp->mii.force_media;
+ tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+
+ rtl8139_init_ring (dev);
+ rtl8139_hw_start (dev);
+ netif_start_queue (dev);
+
+ if (netif_msg_ifup(tp))
+ printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
+ " GP Pins %2.2x %s-duplex.\n",
+ dev->name, pci_resource_start (tp->pci_dev, 1),
+ dev->irq, RTL_R8 (MediaStatus),
+ tp->mii.full_duplex ? "full" : "half");
+
+ rtl8139_start_thread(dev);
+
+ return 0;
+}
+
+
+static void rtl_check_media (struct net_device *dev, unsigned int init_media)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ if (tp->phys[0] >= 0) {
+ mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
+ }
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 i;
+ u8 tmp;
+
+ /* Bring old chips out of low-power mode. */
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'R');
+
+ rtl8139_chip_reset (ioaddr);
+
+ /* unlock Config[01234] and BMCR register writes */
+ RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+ /* Restore our idea of the MAC address. */
+ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+ RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+ RTL_W32 (RxConfig, tp->rx_config);
+ RTL_W32 (TxConfig, rtl8139_tx_config);
+
+ tp->cur_rx = 0;
+
+ rtl_check_media (dev, 1);
+
+ if (tp->chipset >= CH_8139B) {
+ /* Disable magic packet scanning, which is enabled
+ * when PM is enabled in Config1. It can be reenabled
+ * via ETHTOOL_SWOL if desired. */
+ RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
+ }
+
+ DPRINTK("init buffer addresses\n");
+
+ /* Lock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ /* init Rx ring buffer DMA address */
+ RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+ /* init Tx buffer DMA addresses */
+ for (i = 0; i < NUM_TX_DESC; i++)
+ RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
+
+ RTL_W32 (RxMissed, 0);
+
+ rtl8139_set_rx_mode (dev);
+
+ /* no early-rx interrupts */
+ RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
+
+ /* make sure RxTx has started */
+ tmp = RTL_R8 (ChipCmd);
+ if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ /* Enable all known interrupts by setting the interrupt mask. */
+ RTL_W16 (IntrMask, rtl8139_intr_mask);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ int i;
+
+ tp->cur_rx = 0;
+ tp->cur_tx = 0;
+ tp->dirty_tx = 0;
+
+ for (i = 0; i < NUM_TX_DESC; i++)
+ tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+}
+
+
+/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
+static int next_tick = 3 * HZ;
+
+#ifndef CONFIG_8139TOO_TUNE_TWISTER
+static inline void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp) {}
+#else
+enum TwisterParamVals {
+ PARA78_default = 0x78fa8388,
+ PARA7c_default = 0xcb38de43, /* param[0][3] */
+ PARA7c_xxx = 0xcb38de43,
+};
+
+static const unsigned long param[4][4] = {
+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+static void rtl8139_tune_twister (struct net_device *dev,
+ struct rtl8139_private *tp)
+{
+ int linkcase;
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ /* This is a complicated state machine to configure the "twister" for
+ impedance/echos based on the cable length.
+ All of this is magic and undocumented.
+ */
+ switch (tp->twistie) {
+ case 1:
+ if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
+ /* We have link beat, let us tune the twister. */
+ RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
+ tp->twistie = 2; /* Change to state 2. */
+ next_tick = HZ / 10;
+ } else {
+ /* Just put in some reasonable defaults for when beat returns. */
+ RTL_W16 (CSCR, CSCR_LinkDownCmd);
+ RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ tp->twistie = 0; /* Bail from future actions. */
+ }
+ break;
+ case 2:
+ /* Read how long it took to hear the echo. */
+ linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
+ if (linkcase == 0x7000)
+ tp->twist_row = 3;
+ else if (linkcase == 0x3000)
+ tp->twist_row = 2;
+ else if (linkcase == 0x1000)
+ tp->twist_row = 1;
+ else
+ tp->twist_row = 0;
+ tp->twist_col = 0;
+ tp->twistie = 3; /* Change to state 2. */
+ next_tick = HZ / 10;
+ break;
+ case 3:
+ /* Put out four tuning parameters, one per 100msec. */
+ if (tp->twist_col == 0)
+ RTL_W16 (FIFOTMS, 0);
+ RTL_W32 (PARA7c, param[(int) tp->twist_row]
+ [(int) tp->twist_col]);
+ next_tick = HZ / 10;
+ if (++tp->twist_col >= 4) {
+ /* For short cables we are done.
+ For long cables (row == 3) check for mistune. */
+ tp->twistie =
+ (tp->twist_row == 3) ? 4 : 0;
+ }
+ break;
+ case 4:
+ /* Special case for long cables: check for mistune. */
+ if ((RTL_R16 (CSCR) &
+ CSCR_LinkStatusBits) == 0x7000) {
+ tp->twistie = 0;
+ break;
+ } else {
+ RTL_W32 (PARA7c, 0xfb38de03);
+ tp->twistie = 5;
+ next_tick = HZ / 10;
+ }
+ break;
+ case 5:
+ /* Retune for shorter cable (column 2). */
+ RTL_W32 (FIFOTMS, 0x20);
+ RTL_W32 (PARA78, PARA78_default);
+ RTL_W32 (PARA7c, PARA7c_default);
+ RTL_W32 (FIFOTMS, 0x00);
+ tp->twist_row = 2;
+ tp->twist_col = 0;
+ tp->twistie = 3;
+ next_tick = HZ / 10;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
+
+static inline void rtl8139_thread_iter (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr)
+{
+ int mii_lpa;
+
+ mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
+
+ if (!tp->mii.force_media && mii_lpa != 0xffff) {
+ int duplex = (mii_lpa & LPA_100FULL)
+ || (mii_lpa & 0x01C0) == 0x0040;
+ if (tp->mii.full_duplex != duplex) {
+ tp->mii.full_duplex = duplex;
+
+ if (mii_lpa) {
+ printk (KERN_INFO
+ "%s: Setting %s-duplex based on MII #%d link"
+ " partner ability of %4.4x.\n",
+ dev->name,
+ tp->mii.full_duplex ? "full" : "half",
+ tp->phys[0], mii_lpa);
+ } else {
+ printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+ dev->name);
+ }
+#if 0
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+#endif
+ }
+ }
+
+ next_tick = HZ * 60;
+
+ rtl8139_tune_twister (dev, tp);
+
+ DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+ dev->name, RTL_R16 (NWayLPAR));
+ DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n",
+ dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
+ DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
+ dev->name, RTL_R8 (Config0),
+ RTL_R8 (Config1));
+}
+
+static int rtl8139_thread (void *data)
+{
+ struct net_device *dev = data;
+ struct rtl8139_private *tp = netdev_priv(dev);
+ unsigned long timeout;
+
+ daemonize("%s", dev->name);
+ allow_signal(SIGTERM);
+
+ while (1) {
+ timeout = next_tick;
+ do {
+ timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
+ /* make swsusp happy with our thread */
+ try_to_freeze();
+ } while (!signal_pending (current) && (timeout > 0));
+
+ if (signal_pending (current)) {
+ flush_signals(current);
+ }
+
+ if (tp->time_to_die)
+ break;
+
+ if (rtnl_lock_interruptible ())
+ break;
+ rtl8139_thread_iter (dev, tp, tp->mmio_addr);
+ rtnl_unlock ();
+ }
+
+ complete_and_exit (&tp->thr_exited, 0);
+}
+
+static void rtl8139_start_thread(struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ tp->thr_pid = -1;
+ tp->twistie = 0;
+ tp->time_to_die = 0;
+ if (tp->chipset == CH_8139_K)
+ tp->twistie = 1;
+ else if (tp->drv_flags & HAS_LNK_CHNG)
+ return;
+
+ tp->thr_pid = kernel_thread(rtl8139_thread, dev, CLONE_FS|CLONE_FILES);
+ if (tp->thr_pid < 0) {
+ printk (KERN_WARNING "%s: unable to start kernel thread\n",
+ dev->name);
+ }
+}
+
+static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
+{
+ tp->cur_tx = 0;
+ tp->dirty_tx = 0;
+
+ /* XXX account for unsent Tx packets in tp->stats.tx_dropped */
+}
+
+
+static void rtl8139_tx_timeout (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+ u8 tmp8;
+ unsigned long flags;
+
+ printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
+ "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
+ RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
+ /* Emit info to figure out what went wrong. */
+ printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
+ for (i = 0; i < NUM_TX_DESC; i++)
+ printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n",
+ dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
+ i == tp->dirty_tx % NUM_TX_DESC ?
+ " (queue head)" : "");
+
+ tp->xstats.tx_timeouts++;
+
+ /* disable Tx ASAP, if not already */
+ tmp8 = RTL_R8 (ChipCmd);
+ if (tmp8 & CmdTxEnb)
+ RTL_W8 (ChipCmd, CmdRxEnb);
+
+ spin_lock(&tp->rx_lock);
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0x0000);
+
+ /* Stop a shared interrupt from scavenging while we are. */
+ spin_lock_irqsave (&tp->lock, flags);
+ rtl8139_tx_clear (tp);
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ /* ...and finally, reset everything */
+ if (netif_running(dev)) {
+ rtl8139_hw_start (dev);
+ netif_wake_queue (dev);
+ }
+ spin_unlock(&tp->rx_lock);
+}
+
+
+static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned int entry;
+ unsigned int len = skb->len;
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % NUM_TX_DESC;
+
+ /* Note: the chip doesn't have auto-pad! */
+ if (likely(len < TX_BUF_SIZE)) {
+ if (len < ETH_ZLEN)
+ memset(tp->tx_buf[entry], 0, ETH_ZLEN);
+ skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
+ dev_kfree_skb(skb);
+ } else {
+ dev_kfree_skb(skb);
+ tp->stats.tx_dropped++;
+ return 0;
+ }
+
+ spin_lock_irq(&tp->lock);
+ RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
+ tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
+
+ dev->trans_start = jiffies;
+
+ tp->cur_tx++;
+ wmb();
+
+ if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
+ netif_stop_queue (dev);
+ spin_unlock_irq(&tp->lock);
+
+ if (netif_msg_tx_queued(tp))
+ printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
+ dev->name, len, entry);
+
+ return 0;
+}
+
+
+static void rtl8139_tx_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr)
+{
+ unsigned long dirty_tx, tx_left;
+
+ assert (dev != NULL);
+ assert (ioaddr != NULL);
+
+ dirty_tx = tp->dirty_tx;
+ tx_left = tp->cur_tx - dirty_tx;
+ while (tx_left > 0) {
+ int entry = dirty_tx % NUM_TX_DESC;
+ int txstatus;
+
+ txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
+
+ if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+ break; /* It still hasn't been Txed */
+
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ if (txstatus & (TxOutOfWindow | TxAborted)) {
+ /* There was an major error, log it. */
+ if (netif_msg_tx_err(tp))
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, txstatus);
+ tp->stats.tx_errors++;
+ if (txstatus & TxAborted) {
+ tp->stats.tx_aborted_errors++;
+ RTL_W32 (TxConfig, TxClearAbt);
+ RTL_W16 (IntrStatus, TxErr);
+ wmb();
+ }
+ if (txstatus & TxCarrierLost)
+ tp->stats.tx_carrier_errors++;
+ if (txstatus & TxOutOfWindow)
+ tp->stats.tx_window_errors++;
+ } else {
+ if (txstatus & TxUnderrun) {
+ /* Add 64 to the Tx FIFO threshold. */
+ if (tp->tx_flag < 0x00300000)
+ tp->tx_flag += 0x00020000;
+ tp->stats.tx_fifo_errors++;
+ }
+ tp->stats.collisions += (txstatus >> 24) & 15;
+ tp->stats.tx_bytes += txstatus & 0x7ff;
+ tp->stats.tx_packets++;
+ }
+
+ dirty_tx++;
+ tx_left--;
+ }
+
+#ifndef RTL8139_NDEBUG
+ if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+ printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+ dev->name, dirty_tx, tp->cur_tx);
+ dirty_tx += NUM_TX_DESC;
+ }
+#endif /* RTL8139_NDEBUG */
+
+ /* only wake the queue if we did work, and the queue is stopped */
+ if (tp->dirty_tx != dirty_tx) {
+ tp->dirty_tx = dirty_tx;
+ mb();
+ netif_wake_queue (dev);
+ }
+}
+
+
+/* TODO: clean this up! Rx reset need not be this intensive */
+static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
+ struct rtl8139_private *tp, void __iomem *ioaddr)
+{
+ u8 tmp8;
+#ifdef CONFIG_8139_OLD_RX_RESET
+ int tmp_work;
+#endif
+
+ if (netif_msg_rx_err (tp))
+ printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
+ dev->name, rx_status);
+ tp->stats.rx_errors++;
+ if (!(rx_status & RxStatusOK)) {
+ if (rx_status & RxTooLong) {
+ DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+ dev->name, rx_status);
+ /* A.C.: The chip hangs here. */
+ }
+ if (rx_status & (RxBadSymbol | RxBadAlign))
+ tp->stats.rx_frame_errors++;
+ if (rx_status & (RxRunt | RxTooLong))
+ tp->stats.rx_length_errors++;
+ if (rx_status & RxCRCErr)
+ tp->stats.rx_crc_errors++;
+ } else {
+ tp->xstats.rx_lost_in_ring++;
+ }
+
+#ifndef CONFIG_8139_OLD_RX_RESET
+ tmp8 = RTL_R8 (ChipCmd);
+ RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
+ RTL_W8 (ChipCmd, tmp8);
+ RTL_W32 (RxConfig, tp->rx_config);
+ tp->cur_rx = 0;
+#else
+ /* Reset the receiver, based on RealTek recommendation. (Bug?) */
+
+ /* disable receive */
+ RTL_W8_F (ChipCmd, CmdTxEnb);
+ tmp_work = 200;
+ while (--tmp_work > 0) {
+ udelay(1);
+ tmp8 = RTL_R8 (ChipCmd);
+ if (!(tmp8 & CmdRxEnb))
+ break;
+ }
+ if (tmp_work <= 0)
+ printk (KERN_WARNING PFX "rx stop wait too long\n");
+ /* restart receive */
+ tmp_work = 200;
+ while (--tmp_work > 0) {
+ RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
+ udelay(1);
+ tmp8 = RTL_R8 (ChipCmd);
+ if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
+ break;
+ }
+ if (tmp_work <= 0)
+ printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
+
+ /* and reinitialize all rx related registers */
+ RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+ /* Must enable Tx/Rx before setting transfer thresholds! */
+ RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+ tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+ RTL_W32 (RxConfig, tp->rx_config);
+ tp->cur_rx = 0;
+
+ DPRINTK("init buffer addresses\n");
+
+ /* Lock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ /* init Rx ring buffer DMA address */
+ RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+ /* A.C.: Reset the multicast list. */
+ __set_rx_mode (dev);
+#endif
+}
+
+#if RX_BUF_IDX == 3
+static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
+ u32 offset, unsigned int size)
+{
+ u32 left = RX_BUF_LEN - offset;
+
+ if (size > left) {
+ memcpy(skb->data, ring + offset, left);
+ memcpy(skb->data+left, ring, size - left);
+ } else
+ memcpy(skb->data, ring + offset, size);
+}
+#endif
+
+static void rtl8139_isr_ack(struct rtl8139_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ u16 status;
+
+ status = RTL_R16 (IntrStatus) & RxAckBits;
+
+ /* Clear out errors and receive interrupts */
+ if (likely(status != 0)) {
+ if (unlikely(status & (RxFIFOOver | RxOverflow))) {
+ tp->stats.rx_errors++;
+ if (status & RxFIFOOver)
+ tp->stats.rx_fifo_errors++;
+ }
+ RTL_W16_F (IntrStatus, RxAckBits);
+ }
+}
+
+static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
+ int budget)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int received = 0;
+ unsigned char *rx_ring = tp->rx_ring;
+ unsigned int cur_rx = tp->cur_rx;
+ unsigned int rx_size = 0;
+
+ DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+
+ while (netif_running(dev) && received < budget
+ && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
+ u32 ring_offset = cur_rx % RX_BUF_LEN;
+ u32 rx_status;
+ unsigned int pkt_size;
+ struct sk_buff *skb;
+
+ rmb();
+
+ /* read size+status of next frame from DMA ring buffer */
+ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+ rx_size = rx_status >> 16;
+ pkt_size = rx_size - 4;
+
+ if (netif_msg_rx_status(tp))
+ printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x,"
+ " cur %4.4x.\n", dev->name, rx_status,
+ rx_size, cur_rx);
+#if RTL8139_DEBUG > 2
+ {
+ int i;
+ DPRINTK ("%s: Frame contents ", dev->name);
+ for (i = 0; i < 70; i++)
+ printk (" %2.2x",
+ rx_ring[ring_offset + i]);
+ printk (".\n");
+ }
+#endif
+
+ /* Packet copy from FIFO still in progress.
+ * Theoretically, this should never happen
+ * since EarlyRx is disabled.
+ */
+ if (unlikely(rx_size == 0xfff0)) {
+ if (!tp->fifo_copy_timeout)
+ tp->fifo_copy_timeout = jiffies + 2;
+ else if (time_after(jiffies, tp->fifo_copy_timeout)) {
+ DPRINTK ("%s: hung FIFO. Reset.", dev->name);
+ rx_size = 0;
+ goto no_early_rx;
+ }
+ if (netif_msg_intr(tp)) {
+ printk(KERN_DEBUG "%s: fifo copy in progress.",
+ dev->name);
+ }
+ tp->xstats.early_rx++;
+ break;
+ }
+
+no_early_rx:
+ tp->fifo_copy_timeout = 0;
+
+ /* If Rx err or invalid rx_size/rx_status received
+ * (which happens if we get lost in the ring),
+ * Rx process gets reset, so we abort any further
+ * Rx processing.
+ */
+ if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+ (rx_size < 8) ||
+ (!(rx_status & RxStatusOK)))) {
+ rtl8139_rx_err (rx_status, dev, tp, ioaddr);
+ received = -1;
+ goto out;
+ }
+
+ /* Malloc up new buffer, compatible with net-2e. */
+ /* Omit the four octet CRC from the length. */
+
+ skb = dev_alloc_skb (pkt_size + 2);
+ if (likely(skb)) {
+ skb->dev = dev;
+ skb_reserve (skb, 2); /* 16 byte align the IP fields. */
+#if RX_BUF_IDX == 3
+ wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
+#else
+ eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+#endif
+ skb_put (skb, pkt_size);
+
+ skb->protocol = eth_type_trans (skb, dev);
+
+ dev->last_rx = jiffies;
+ tp->stats.rx_bytes += pkt_size;
+ tp->stats.rx_packets++;
+
+ netif_receive_skb (skb);
+ } else {
+ if (net_ratelimit())
+ printk (KERN_WARNING
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ tp->stats.rx_dropped++;
+ }
+ received++;
+
+ cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+ RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
+
+ rtl8139_isr_ack(tp);
+ }
+
+ if (unlikely(!received || rx_size == 0xfff0))
+ rtl8139_isr_ack(tp);
+
+#if RTL8139_DEBUG > 1
+ DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+ " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+ RTL_R16 (RxBufAddr),
+ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
+#endif
+
+ tp->cur_rx = cur_rx;
+
+ /*
+ * The receive buffer should be mostly empty.
+ * Tell NAPI to reenable the Rx irq.
+ */
+ if (tp->fifo_copy_timeout)
+ received = budget;
+
+out:
+ return received;
+}
+
+
+static void rtl8139_weird_interrupt (struct net_device *dev,
+ struct rtl8139_private *tp,
+ void __iomem *ioaddr,
+ int status, int link_changed)
+{
+ DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+ dev->name, status);
+
+ assert (dev != NULL);
+ assert (tp != NULL);
+ assert (ioaddr != NULL);
+
+ /* Update the error count. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ if ((status & RxUnderrun) && link_changed &&
+ (tp->drv_flags & HAS_LNK_CHNG)) {
+ rtl_check_media(dev, 0);
+ status &= ~RxUnderrun;
+ }
+
+ if (status & (RxUnderrun | RxErr))
+ tp->stats.rx_errors++;
+
+ if (status & PCSTimeout)
+ tp->stats.rx_length_errors++;
+ if (status & RxUnderrun)
+ tp->stats.rx_fifo_errors++;
+ if (status & PCIErr) {
+ u16 pci_cmd_status;
+ pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+ pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
+
+ printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+ dev->name, pci_cmd_status);
+ }
+}
+
+static int rtl8139_poll(struct net_device *dev, int *budget)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int orig_budget = min(*budget, dev->quota);
+ int done = 1;
+
+ spin_lock(&tp->rx_lock);
+ if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
+ int work_done;
+
+ work_done = rtl8139_rx(dev, tp, orig_budget);
+ if (likely(work_done > 0)) {
+ *budget -= work_done;
+ dev->quota -= work_done;
+ done = (work_done < orig_budget);
+ }
+ }
+
+ if (done) {
+ /*
+ * Order is important since data can get interrupted
+ * again when we think we are done.
+ */
+ local_irq_disable();
+ RTL_W16_F(IntrMask, rtl8139_intr_mask);
+ __netif_rx_complete(dev);
+ local_irq_enable();
+ }
+ spin_unlock(&tp->rx_lock);
+
+ return !done;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u16 status, ackstat;
+ int link_changed = 0; /* avoid bogus "uninit" warning */
+ int handled = 0;
+
+ spin_lock (&tp->lock);
+ status = RTL_R16 (IntrStatus);
+
+ /* shared irq? */
+ if (unlikely((status & rtl8139_intr_mask) == 0))
+ goto out;
+
+ handled = 1;
+
+ /* h/w no longer present (hotplug?) or major error, bail */
+ if (unlikely(status == 0xFFFF))
+ goto out;
+
+ /* close possible race's with dev_close */
+ if (unlikely(!netif_running(dev))) {
+ RTL_W16 (IntrMask, 0);
+ goto out;
+ }
+
+ /* Acknowledge all of the current interrupt sources ASAP, but
+ an first get an additional status bit from CSCR. */
+ if (unlikely(status & RxUnderrun))
+ link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+
+ ackstat = status & ~(RxAckBits | TxErr);
+ if (ackstat)
+ RTL_W16 (IntrStatus, ackstat);
+
+ /* Receive packets are processed by poll routine.
+ If not running start it now. */
+ if (status & RxAckBits){
+ if (netif_rx_schedule_prep(dev)) {
+ RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
+ __netif_rx_schedule (dev);
+ }
+ }
+
+ /* Check uncommon events with one test. */
+ if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr)))
+ rtl8139_weird_interrupt (dev, tp, ioaddr,
+ status, link_changed);
+
+ if (status & (TxOK | TxErr)) {
+ rtl8139_tx_interrupt (dev, tp, ioaddr);
+ if (status & TxErr)
+ RTL_W16 (IntrStatus, TxErr);
+ }
+ out:
+ spin_unlock (&tp->lock);
+
+ DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+ return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void rtl8139_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ rtl8139_interrupt(dev->irq, dev, NULL);
+ enable_irq(dev->irq);
+}
+#endif
+
+static int rtl8139_close (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ int ret = 0;
+ unsigned long flags;
+
+ netif_stop_queue (dev);
+
+ if (tp->thr_pid >= 0) {
+ tp->time_to_die = 1;
+ wmb();
+ ret = kill_proc (tp->thr_pid, SIGTERM, 1);
+ if (ret) {
+ printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
+ return ret;
+ }
+ wait_for_completion (&tp->thr_exited);
+ }
+
+ if (netif_msg_ifdown(tp))
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
+ dev->name, RTL_R16 (IntrStatus));
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ /* Stop the chip's Tx and Rx DMA processes. */
+ RTL_W8 (ChipCmd, 0);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ RTL_W16 (IntrMask, 0);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ synchronize_irq (dev->irq); /* racy, but that's ok here */
+ free_irq (dev->irq, dev);
+
+ rtl8139_tx_clear (tp);
+
+ pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+ pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
+ tp->rx_ring = NULL;
+ tp->tx_bufs = NULL;
+
+ /* Green! Put the chip in low-power mode. */
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+
+ if (rtl_chip_info[tp->chipset].flags & HasHltClk)
+ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
+
+ return 0;
+}
+
+
+/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to
+ kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
+ other threads or interrupts aren't messing with the 8139. */
+static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->mmio_addr;
+
+ spin_lock_irq(&np->lock);
+ if (rtl_chip_info[np->chipset].flags & HasLWake) {
+ u8 cfg3 = RTL_R8 (Config3);
+ u8 cfg5 = RTL_R8 (Config5);
+
+ wol->supported = WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+
+ wol->wolopts = 0;
+ if (cfg3 & Cfg3_LinkUp)
+ wol->wolopts |= WAKE_PHY;
+ if (cfg3 & Cfg3_Magic)
+ wol->wolopts |= WAKE_MAGIC;
+ /* (KON)FIXME: See how netdev_set_wol() handles the
+ following constants. */
+ if (cfg5 & Cfg5_UWF)
+ wol->wolopts |= WAKE_UCAST;
+ if (cfg5 & Cfg5_MWF)
+ wol->wolopts |= WAKE_MCAST;
+ if (cfg5 & Cfg5_BWF)
+ wol->wolopts |= WAKE_BCAST;
+ }
+ spin_unlock_irq(&np->lock);
+}
+
+
+/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes
+ that wol points to kernel memory and other threads or interrupts
+ aren't messing with the 8139. */
+static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->mmio_addr;
+ u32 support;
+ u8 cfg3, cfg5;
+
+ support = ((rtl_chip_info[np->chipset].flags & HasLWake)
+ ? (WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)
+ : 0);
+ if (wol->wolopts & ~support)
+ return -EINVAL;
+
+ spin_lock_irq(&np->lock);
+ cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
+ if (wol->wolopts & WAKE_PHY)
+ cfg3 |= Cfg3_LinkUp;
+ if (wol->wolopts & WAKE_MAGIC)
+ cfg3 |= Cfg3_Magic;
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+ RTL_W8 (Config3, cfg3);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+ cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF);
+ /* (KON)FIXME: These are untested. We may have to set the
+ CRC0, Wakeup0 and LSBCRC0 registers too, but I have no
+ documentation. */
+ if (wol->wolopts & WAKE_UCAST)
+ cfg5 |= Cfg5_UWF;
+ if (wol->wolopts & WAKE_MCAST)
+ cfg5 |= Cfg5_MWF;
+ if (wol->wolopts & WAKE_BCAST)
+ cfg5 |= Cfg5_BWF;
+ RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(np->pci_dev));
+ info->regdump_len = np->regs_len;
+}
+
+static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ spin_lock_irq(&np->lock);
+ mii_ethtool_gset(&np->mii, cmd);
+ spin_unlock_irq(&np->lock);
+ return 0;
+}
+
+static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ int rc;
+ spin_lock_irq(&np->lock);
+ rc = mii_ethtool_sset(&np->mii, cmd);
+ spin_unlock_irq(&np->lock);
+ return rc;
+}
+
+static int rtl8139_nway_reset(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return mii_nway_restart(&np->mii);
+}
+
+static u32 rtl8139_get_link(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return mii_link_ok(&np->mii);
+}
+
+static u32 rtl8139_get_msglevel(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return np->msg_enable;
+}
+
+static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ np->msg_enable = datum;
+}
+
+/* TODO: we are too slack to do reg dumping for pio, for now */
+#ifdef CONFIG_8139TOO_PIO
+#define rtl8139_get_regs_len NULL
+#define rtl8139_get_regs NULL
+#else
+static int rtl8139_get_regs_len(struct net_device *dev)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ return np->regs_len;
+}
+
+static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+
+ regs->version = RTL_REGS_VER;
+
+ spin_lock_irq(&np->lock);
+ memcpy_fromio(regbuf, np->mmio_addr, regs->len);
+ spin_unlock_irq(&np->lock);
+}
+#endif /* CONFIG_8139TOO_MMIO */
+
+static int rtl8139_get_stats_count(struct net_device *dev)
+{
+ return RTL_NUM_STATS;
+}
+
+static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+
+ data[0] = np->xstats.early_rx;
+ data[1] = np->xstats.tx_buf_mapped;
+ data[2] = np->xstats.tx_timeouts;
+ data[3] = np->xstats.rx_lost_in_ring;
+}
+
+static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static struct ethtool_ops rtl8139_ethtool_ops = {
+ .get_drvinfo = rtl8139_get_drvinfo,
+ .get_settings = rtl8139_get_settings,
+ .set_settings = rtl8139_set_settings,
+ .get_regs_len = rtl8139_get_regs_len,
+ .get_regs = rtl8139_get_regs,
+ .nway_reset = rtl8139_nway_reset,
+ .get_link = rtl8139_get_link,
+ .get_msglevel = rtl8139_get_msglevel,
+ .set_msglevel = rtl8139_set_msglevel,
+ .get_wol = rtl8139_get_wol,
+ .set_wol = rtl8139_set_wol,
+ .get_strings = rtl8139_get_strings,
+ .get_stats_count = rtl8139_get_stats_count,
+ .get_ethtool_stats = rtl8139_get_ethtool_stats,
+};
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct rtl8139_private *np = netdev_priv(dev);
+ int rc;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&np->lock);
+ rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL);
+ spin_unlock_irq(&np->lock);
+
+ return rc;
+}
+
+
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned long flags;
+
+ if (netif_running(dev)) {
+ spin_lock_irqsave (&tp->lock, flags);
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+ spin_unlock_irqrestore (&tp->lock, flags);
+ }
+
+ return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ This routine is not state sensitive and need not be SMP locked. */
+
+static void __set_rx_mode (struct net_device *dev)
+{
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ int i, rx_mode;
+ u32 tmp;
+
+ DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
+ dev->name, dev->flags, RTL_R32 (RxConfig));
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+ dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else {
+ struct dev_mc_list *mclist;
+ rx_mode = AcceptBroadcast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ rx_mode |= AcceptMulticast;
+ }
+ }
+
+ /* We can safely update without stopping the chip. */
+ tmp = rtl8139_rx_config | rx_mode;
+ if (tp->rx_config != tmp) {
+ RTL_W32_F (RxConfig, tmp);
+ tp->rx_config = tmp;
+ }
+ RTL_W32_F (MAR0 + 0, mc_filter[0]);
+ RTL_W32_F (MAR0 + 4, mc_filter[1]);
+}
+
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+ unsigned long flags;
+ struct rtl8139_private *tp = netdev_priv(dev);
+
+ spin_lock_irqsave (&tp->lock, flags);
+ __set_rx_mode(dev);
+ spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+#ifdef CONFIG_PM
+
+static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ struct rtl8139_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ unsigned long flags;
+
+ pci_save_state (pdev);
+
+ if (!netif_running (dev))
+ return 0;
+
+ netif_device_detach (dev);
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ RTL_W16 (IntrMask, 0);
+ RTL_W8 (ChipCmd, 0);
+
+ /* Update the error counts. */
+ tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+ RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ pci_set_power_state (pdev, PCI_D3hot);
+
+ return 0;
+}
+
+
+static int rtl8139_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ pci_restore_state (pdev);
+ if (!netif_running (dev))
+ return 0;
+ pci_set_power_state (pdev, PCI_D0);
+ rtl8139_init_ring (dev);
+ rtl8139_hw_start (dev);
+ netif_device_attach (dev);
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+static struct pci_driver rtl8139_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rtl8139_pci_tbl,
+ .probe = rtl8139_init_one,
+ .remove = __devexit_p(rtl8139_remove_one),
+#ifdef CONFIG_PM
+ .suspend = rtl8139_suspend,
+ .resume = rtl8139_resume,
+#endif /* CONFIG_PM */
+};
+
+
+static int __init rtl8139_init_module (void)
+{
+ /* when we're a module, we always print a version message,
+ * even if no 8139 board is found.
+ */
+#ifdef MODULE
+ printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
+#endif
+
+ return pci_module_init (&rtl8139_pci_driver);
+}
+
+
+static void __exit rtl8139_cleanup_module (void)
+{
+ pci_unregister_driver (&rtl8139_pci_driver);
+}
+
+
+module_init(rtl8139_init_module);
+module_exit(rtl8139_cleanup_module);
--- a/drivers/8139too.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3045 +0,0 @@
-/******************************************************************************
- *
- * drv_8139too.c
- *
- * EtherCAT-Treiber für RTL8139-kompatible Netzwerkkarten.
- *
- * Autoren: Wilhelm Hagemeister, Florian Pose
- *
- * $Date$
- * $Author$
- *
- * (C) Copyright IgH 2005
- * Ingenieurgemeinschaft IgH
- * Heinz-Bäcker Str. 34
- * D-45356 Essen
- * Tel.: +49 201/61 99 31
- * Fax.: +49 201/61 98 36
- * E-mail: sp@igh-essen.com
- *
- ******************************************************************************/
-
-/*
- 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
-
- Maintained by Jeff Garzik <jgarzik@pobox.com>
- Copyright 2000-2002 Jeff Garzik
-
- Much code comes from Donald Becker's rtl8139.c driver,
- versions 1.13 and older. This driver was originally based
- on rtl8139.c version 1.07. Header of rtl8139.c version 1.13:
-
- -----<snip>-----
-
- Written 1997-2001 by Donald Becker.
- This software may be used and distributed according to the
- terms of the GNU General Public License (GPL), incorporated
- herein by reference. Drivers based on or derived from this
- code fall under the GPL and must retain the authorship,
- copyright and license notice. This file is not a complete
- program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This driver is for boards based on the RTL8129 and RTL8139
- PCI ethernet chips.
-
- The author may be reached as becker@scyld.com, or C/O Scyld
- Computing Corporation 410 Severn Ave., Suite 210 Annapolis
- MD 21403
-
- Support and updates available at
- http://www.scyld.com/network/rtl8139.html
-
- Twister-tuning table provided by Kinston
- <shangh@realtek.com.tw>.
-
- -----<snip>-----
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- Contributors:
-
- Donald Becker - he wrote the original driver, kudos to him!
- (but please don't e-mail him for support, this isn't his driver)
-
- Tigran Aivazian - bug fixes, skbuff free cleanup
-
- Martin Mares - suggestions for PCI cleanup
-
- David S. Miller - PCI DMA and softnet updates
-
- Ernst Gill - fixes ported from BSD driver
-
- Daniel Kobras - identified specific locations of
- posted MMIO write bugginess
-
- Gerard Sharp - bug fix, testing and feedback
-
- David Ford - Rx ring wrap fix
-
- Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
- to find and fix a crucial bug on older chipsets.
-
- Donald Becker/Chris Butterworth/Marcus Westergren -
- Noticed various Rx packet size-related buglets.
-
- Santiago Garcia Mantinan - testing and feedback
-
- Jens David - 2.2.x kernel backports
-
- Martin Dennett - incredibly helpful insight on undocumented
- features of the 8139 chips
-
- Jean-Jacques Michel - bug fix
-
- Tobias Ringström - Rx interrupt status checking suggestion
-
- Andrew Morton - Clear blocked signals, avoid
- buffer overrun setting current->comm.
-
- Kalle Olavi Niemitalo - Wake-on-LAN ioctls
-
- Robert Kuebel - Save kernel thread from dying on any signal.
-
- Submitting bug reports:
-
- "rtl8139-diag -mmmaaavvveefN" output
- enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
-
-*/
-
-#define DRV_NAME "8139too_ecat"
-#define DRV_VERSION "0.9.27"
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/completion.h>
-#include <linux/crc32.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-#include "ec_device.h"
-#include "ec_master.h"
-#include "ec_module.h"
-
-#define LITERAL(X) #X
-#define STRINGIFY(X) LITERAL(X)
-
-#define COMPILE_INFO "Revision " STRINGIFY(EC_REV) \
- ", compiled by " STRINGIFY(EC_USER) \
- " at " STRINGIFY(EC_DATE)
-
-/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
-#define PFX DRV_NAME ": "
-
-/* Default Message level */
-#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
- NETIF_MSG_PROBE | \
- NETIF_MSG_LINK)
-
-
-/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
-#ifdef CONFIG_8139TOO_PIO
-#define USE_IO_OPS 1
-#endif
-
-/* define to 1, 2 or 3 to enable copious debugging info */
-#define RTL8139_DEBUG 0
-
-/* define to 1 to disable lightweight runtime debugging checks */
-#undef RTL8139_NDEBUG
-
-
-#if RTL8139_DEBUG
-/* note: prints function name for you */
-# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-# define DPRINTK(fmt, args...)
-#endif
-
-#ifdef RTL8139_NDEBUG
-# define assert(expr) do {} while (0)
-#else
-# define assert(expr) \
- if(unlikely(!(expr))) { \
- printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
-#endif
-
-
-/* A few user-configurable values. */
-/* media options */
-#define MAX_UNITS 8
-static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-
-/* bitmapped message enable number */
-static int debug = -1;
-
-/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-// Uncomment for debugging
-//#define ECAT_DEBUG
-
-// Device index for EtherCAT device selection
-static int ec_device_index = -1;
-static int ec_device_master_index = 0;
-
-static EtherCAT_device_t rtl_ecat_dev;
-int rtl_ecat_dev_registered = 0;
-
-/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-/*
- * Receive ring size
- * Warning: 64K ring has hardware issues and may lock up.
- */
-#if defined(CONFIG_SH_DREAMCAST)
-#define RX_BUF_IDX 1 /* 16K ring */
-#else
-#define RX_BUF_IDX 2 /* 32K ring */
-#endif
-#define RX_BUF_LEN (8192 << RX_BUF_IDX)
-#define RX_BUF_PAD 16
-#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
-
-#if RX_BUF_LEN == 65536
-#define RX_BUF_TOT_LEN RX_BUF_LEN
-#else
-#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-#endif
-
-/* Number of Tx descriptor registers. */
-#define NUM_TX_DESC 4
-
-/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
-#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
-
-/* PCI Tuning Parameters
- Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
-
-/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
-#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (6*HZ)
-
-
-enum {
- HAS_MII_XCVR = 0x010000,
- HAS_CHIP_XCVR = 0x020000,
- HAS_LNK_CHNG = 0x040000,
-};
-
-#define RTL_NUM_STATS 4 /* number of ETHTOOL_GSTATS u64's */
-#define RTL_REGS_VER 1 /* version of reg. data in ETHTOOL_GREGS */
-#define RTL_MIN_IO_SIZE 0x80
-#define RTL8139B_IO_SIZE 256
-
-#define RTL8129_CAPS HAS_MII_XCVR
-#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
-
-typedef enum {
- RTL8139 = 0,
- RTL8129,
-} board_t;
-
-
-/* indexed by board_t, above */
-static struct {
- const char *name;
- u32 hw_flags;
-} board_info[] __devinitdata = {
- { "RealTek RTL8139", RTL8139_CAPS },
- { "RealTek RTL8129", RTL8129_CAPS },
-};
-
-
-static struct pci_device_id rtl8139_pci_tbl[] = {
- {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1259, 0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
-
-#ifdef CONFIG_SH_SECUREEDGE5410
- /* Bogus 8139 silicon reports 8129 without external PROM :-( */
- {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
-#endif
-#ifdef CONFIG_8139TOO_8129
- {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
-#endif
-
- /* some crazy cards report invalid vendor ids like
- * 0x0001 here. The other ids are valid and constant,
- * so we simply don't match on the main vendor id.
- */
- {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
- {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
- {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
-
- {0,}
-};
-MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
-
-static struct {
- const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
- { "early_rx" },
- { "tx_buf_mapped" },
- { "tx_timeouts" },
- { "rx_lost_in_ring" },
-};
-
-/* The rest of these values should never change. */
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- TxSummary = 0x60,
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
- /* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
-};
-
-enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
-};
-
-enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
-};
-
-enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
-
- /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-/* Bits in Config1 */
-enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
- Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
-};
-
-/* Bits in Config3 */
-enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
-};
-
-/* Bits in Config4 */
-enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
-};
-
-/* Bits in Config5 */
-enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
-};
-
-enum RxConfigBits {
- /* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
- /* Max DMA burst */
- RxCfgDMAShift = 8,
- RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
- /* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
-
- /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
-};
-
-/* Twister tuning parameters from RealTek.
- Completely undocumented, but required to tune bad links on some boards. */
-enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
-};
-
-enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-};
-
-typedef enum {
- CH_8139 = 0,
- CH_8139_K,
- CH_8139A,
- CH_8139A_G,
- CH_8139B,
- CH_8130,
- CH_8139C,
- CH_8100,
- CH_8100B_8139D,
- CH_8101,
-} chip_t;
-
-enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
-};
-
-#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
- (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
-#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
-
-/* directly indexed by chip_t, above */
-const static struct {
- const char *name;
- u32 version; /* from RTL8139C/RTL8139D docs */
- u32 flags;
-} rtl_chip_info[] = {
- { "RTL-8139",
- HW_REVID(1, 0, 0, 0, 0, 0, 0),
- HasHltClk,
- },
-
- { "RTL-8139 rev K",
- HW_REVID(1, 1, 0, 0, 0, 0, 0),
- HasHltClk,
- },
-
- { "RTL-8139A",
- HW_REVID(1, 1, 1, 0, 0, 0, 0),
- HasHltClk, /* XXX undocumented? */
- },
-
- { "RTL-8139A rev G",
- HW_REVID(1, 1, 1, 0, 0, 1, 0),
- HasHltClk, /* XXX undocumented? */
- },
-
- { "RTL-8139B",
- HW_REVID(1, 1, 1, 1, 0, 0, 0),
- HasLWake,
- },
-
- { "RTL-8130",
- HW_REVID(1, 1, 1, 1, 1, 0, 0),
- HasLWake,
- },
-
- { "RTL-8139C",
- HW_REVID(1, 1, 1, 0, 1, 0, 0),
- HasLWake,
- },
-
- { "RTL-8100",
- HW_REVID(1, 1, 1, 1, 0, 1, 0),
- HasLWake,
- },
-
- { "RTL-8100B/8139D",
- HW_REVID(1, 1, 1, 0, 1, 0, 1),
- HasLWake,
- },
-
- { "RTL-8101",
- HW_REVID(1, 1, 1, 0, 1, 1, 1),
- HasLWake,
- },
-};
-
-struct rtl_extra_stats {
- unsigned long early_rx;
- unsigned long tx_buf_mapped;
- unsigned long tx_timeouts;
- unsigned long rx_lost_in_ring;
-};
-
-struct rtl8139_private {
- void __iomem *mmio_addr;
- int drv_flags;
- struct pci_dev *pci_dev;
- u32 msg_enable;
- struct net_device_stats stats;
- unsigned char *rx_ring;
- unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
- unsigned int tx_flag;
- unsigned long cur_tx;
- unsigned long dirty_tx;
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_bufs_dma;
- signed char phys[4]; /* MII device addresses. */
- char twistie, twist_row, twist_col; /* Twister tune state. */
- unsigned int default_port:4; /* Last dev->if_port value. */
- spinlock_t lock;
- spinlock_t rx_lock;
- chip_t chipset;
- pid_t thr_pid;
- wait_queue_head_t thr_wait;
- struct completion thr_exited;
- u32 rx_config;
- struct rtl_extra_stats xstats;
- int time_to_die;
- struct mii_if_info mii;
- unsigned int regs_len;
- unsigned long fifo_copy_timeout;
-};
-
-/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>, Florian Pose <fp@igh-essen.com>");
-MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver with EtherCAT functionality");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(COMPILE_INFO);
-
-/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-module_param(multicast_filter_limit, int, 0);
-module_param_array(media, int, NULL, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param(debug, int, 0);
-MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
-MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
-MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
-MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
-
-/* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-module_param(ec_device_index, int, -1);
-module_param(ec_device_master_index, int, 0);
-MODULE_PARM_DESC(ec_device_index, "Index of the device reserved for EtherCAT.");
-MODULE_PARM_DESC(ec_device_master_index, "Index of the EtherCAT master to register the device.");
-
-/* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-static int read_eeprom (void __iomem *ioaddr, int location, int addr_len);
-static int rtl8139_open (struct net_device *dev);
-static int mdio_read (struct net_device *dev, int phy_id, int location);
-static void mdio_write (struct net_device *dev, int phy_id, int location,
- int val);
-static void rtl8139_start_thread(struct net_device *dev);
-static void rtl8139_tx_timeout (struct net_device *dev);
-static void rtl8139_init_ring (struct net_device *dev);
-static int rtl8139_start_xmit (struct sk_buff *skb,
- struct net_device *dev);
-int rtl8139_poll(struct net_device *dev, int *budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void rtl8139_poll_controller(struct net_device *dev);
-#endif
-irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs);
-static int rtl8139_close (struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static void rtl8139_set_rx_mode (struct net_device *dev);
-static void __set_rx_mode (struct net_device *dev);
-static void rtl8139_hw_start (struct net_device *dev);
-static struct ethtool_ops rtl8139_ethtool_ops;
-
-/* write MMIO register, with flush */
-/* Flush avoids rtl8139 bug w/ posted MMIO writes */
-#define RTL_W8_F(reg, val8) do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)
-#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
-#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
-
-
-#define MMIO_FLUSH_AUDIT_COMPLETE 1
-#if MMIO_FLUSH_AUDIT_COMPLETE
-
-/* write MMIO register */
-#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
-
-#else
-
-/* write MMIO register, then flush */
-#define RTL_W8 RTL_W8_F
-#define RTL_W16 RTL_W16_F
-#define RTL_W32 RTL_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
-/* read MMIO register */
-#define RTL_R8(reg) ioread8 (ioaddr + (reg))
-#define RTL_R16(reg) ioread16 (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
-
-
-static const u16 rtl8139_intr_mask =
- PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
- TxErr | TxOK | RxErr | RxOK;
-
-static const u16 rtl8139_norx_intr_mask =
- PCIErr | PCSTimeout | RxUnderrun |
- TxErr | TxOK | RxErr ;
-
-#if RX_BUF_IDX == 0
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv8K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 1
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv16K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 2
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv32K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 3
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv64K |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#else
-#error "Invalid configuration for 8139_RXBUF_IDX"
-#endif
-
-static const unsigned int rtl8139_tx_config =
- TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
-
-static void __rtl8139_cleanup_dev (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- struct pci_dev *pdev;
-
- assert (dev != NULL);
- assert (tp->pci_dev != NULL);
- pdev = tp->pci_dev;
-
-#ifdef USE_IO_OPS
- if (tp->mmio_addr)
- ioport_unmap (tp->mmio_addr);
-#else
- if (tp->mmio_addr)
- pci_iounmap (pdev, tp->mmio_addr);
-#endif /* USE_IO_OPS */
-
- /* it's ok to call this even if we have no regions to free */
- pci_release_regions (pdev);
-
- free_netdev(dev);
- pci_set_drvdata (pdev, NULL);
-}
-
-
-static void rtl8139_chip_reset (void __iomem *ioaddr)
-{
- int i;
-
- /* Soft reset the chip. */
- RTL_W8 (ChipCmd, CmdReset);
-
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
- barrier();
- if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
- break;
- udelay (10);
- }
-}
-
-
-static int __devinit rtl8139_init_board (struct pci_dev *pdev,
- struct net_device **dev_out)
-{
- void __iomem *ioaddr;
- struct net_device *dev;
- struct rtl8139_private *tp;
- u8 tmp8;
- int rc, disable_dev_on_err = 0;
- unsigned int i;
- unsigned long pio_start, pio_end, pio_flags, pio_len;
- unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
- u32 version;
-
- assert (pdev != NULL);
-
- *dev_out = NULL;
-
- /* dev and priv zeroed in alloc_etherdev */
- dev = alloc_etherdev (sizeof (*tp));
- if (dev == NULL) {
- printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
- return -ENOMEM;
- }
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- tp = netdev_priv(dev);
- tp->pci_dev = pdev;
-
- /* enable device (incl. PCI PM wakeup and hotplug setup) */
- rc = pci_enable_device (pdev);
- if (rc)
- goto err_out;
-
- pio_start = pci_resource_start (pdev, 0);
- pio_end = pci_resource_end (pdev, 0);
- pio_flags = pci_resource_flags (pdev, 0);
- pio_len = pci_resource_len (pdev, 0);
-
- mmio_start = pci_resource_start (pdev, 1);
- mmio_end = pci_resource_end (pdev, 1);
- mmio_flags = pci_resource_flags (pdev, 1);
- mmio_len = pci_resource_len (pdev, 1);
-
- /* set this immediately, we need to know before
- * we talk to the chip directly */
- DPRINTK("PIO region size == 0x%02X\n", pio_len);
- DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
-
-#ifdef USE_IO_OPS
- /* make sure PCI base addr 0 is PIO */
- if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
- /* check for weird/broken PCI region reporting */
- if (pio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
-#else
- /* make sure PCI base addr 1 is MMIO */
- if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
- if (mmio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
-#endif
-
- rc = pci_request_regions (pdev, "8139too");
- if (rc)
- goto err_out;
- disable_dev_on_err = 1;
-
- /* enable PCI bus-mastering */
- pci_set_master (pdev);
-
-#ifdef USE_IO_OPS
- ioaddr = ioport_map(pio_start, pio_len);
- if (!ioaddr) {
- printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
- dev->base_addr = pio_start;
- tp->mmio_addr = ioaddr;
- tp->regs_len = pio_len;
-#else
- /* ioremap MMIO region */
- ioaddr = pci_iomap(pdev, 1, 0);
- if (ioaddr == NULL) {
- printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
- dev->base_addr = (long) ioaddr;
- tp->mmio_addr = ioaddr;
- tp->regs_len = mmio_len;
-#endif /* USE_IO_OPS */
-
- /* Bring old chips out of low-power mode. */
- RTL_W8 (HltClk, 'R');
-
- /* check for missing/broken hardware */
- if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
- printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
- pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
-
- /* identify chip attached to board */
- version = RTL_R32 (TxConfig) & HW_REVID_MASK;
- for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
- if (version == rtl_chip_info[i].version) {
- tp->chipset = i;
- goto match;
- }
-
- /* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
- tp->chipset = 0;
-
-match:
- DPRINTK ("chipset id (%d) == index %d, '%s'\n",
- version, i, rtl_chip_info[i].name);
-
- if (tp->chipset >= CH_8139B) {
- u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
- DPRINTK("PCI PM wakeup\n");
- if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
- (tmp8 & LWAKE))
- new_tmp8 &= ~LWAKE;
- new_tmp8 |= Cfg1_PM_Enable;
- if (new_tmp8 != tmp8) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config1, tmp8);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- }
- if (rtl_chip_info[tp->chipset].flags & HasLWake) {
- tmp8 = RTL_R8 (Config4);
- if (tmp8 & LWPTN) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config4, tmp8 & ~LWPTN);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- }
- }
- } else {
- DPRINTK("Old chip wakeup\n");
- tmp8 = RTL_R8 (Config1);
- tmp8 &= ~(SLEEP | PWRDN);
- RTL_W8 (Config1, tmp8);
- }
-
- rtl8139_chip_reset (ioaddr);
-
- *dev_out = dev;
- return 0;
-
-err_out:
- __rtl8139_cleanup_dev (dev);
- if (disable_dev_on_err)
- pci_disable_device (pdev);
- return rc;
-}
-
-
-static int __devinit rtl8139_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev = NULL;
- struct rtl8139_private *tp;
- int i, addr_len, option;
- void __iomem *ioaddr;
- static int board_idx = -1;
- u8 pci_rev;
-
- assert (pdev != NULL);
- assert (ent != NULL);
-
- board_idx++;
-
- /* when we're built into the kernel, the driver version message
- * is only printed if at least one 8139 board has been found
- */
-#ifndef MODULE
- {
- static int printed_version;
- if (!printed_version++)
- printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
- }
-#endif
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-
- if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
- pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
- printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
- }
-
- i = rtl8139_init_board (pdev, &dev);
- if (i < 0)
- return i;
-
- assert (dev != NULL);
- tp = netdev_priv(dev);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (board_idx == ec_device_index)
- {
- printk("EtherCAT registering board %d.\n", board_idx);
-
- if (EtherCAT_device_assign(&rtl_ecat_dev, dev) < 0)
- goto err_out;
-
- strcpy(dev->name,"ecat0"); //device name überschreiben
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- ioaddr = tp->mmio_addr;
- assert (ioaddr != NULL);
-
- addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
- for (i = 0; i < 3; i++)
- ((u16 *) (dev->dev_addr))[i] =
- le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
-
- /* The Rtl8139-specific entries in the device structure. */
- dev->open = rtl8139_open;
- dev->hard_start_xmit = rtl8139_start_xmit;
- dev->poll = rtl8139_poll;
- dev->weight = 64;
- dev->stop = rtl8139_close;
- dev->get_stats = rtl8139_get_stats;
- dev->set_multicast_list = rtl8139_set_rx_mode;
- dev->do_ioctl = netdev_ioctl;
- dev->ethtool_ops = &rtl8139_ethtool_ops;
- dev->tx_timeout = rtl8139_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = rtl8139_poll_controller;
-#endif
-
- /* note: the hardware is not capable of sg/csum/highdma, however
- * through the use of skb_copy_and_csum_dev we enable these
- * features
- */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
-
- dev->irq = pdev->irq;
-
- /* tp zeroed and aligned in alloc_etherdev */
- tp = netdev_priv(dev);
-
- /* note: tp->chipset set in rtl8139_init_board */
- tp->drv_flags = board_info[ent->driver_data].hw_flags;
- tp->mmio_addr = ioaddr;
- tp->msg_enable =
- (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
- spin_lock_init (&tp->lock);
- spin_lock_init (&tp->rx_lock);
-
- init_waitqueue_head (&tp->thr_wait);
- init_completion (&tp->thr_exited);
- tp->mii.dev = dev;
- tp->mii.mdio_read = mdio_read;
- tp->mii.mdio_write = mdio_write;
- tp->mii.phy_id_mask = 0x3f;
- tp->mii.reg_num_mask = 0x1f;
-
- /* dev is fully set up and ready to use now */
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- /* EtherCAT-Karten nicht beim Stack anmelden. */
- if (dev != rtl_ecat_dev.dev)
- {
- DPRINTK("About to register device named %s (%p)...\n", dev->name, dev);
- i = register_netdev (dev);
- if (i) goto err_out;
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- pci_set_drvdata (pdev, dev);
-
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
- dev->name,
- board_info[ent->driver_data].name,
- dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
- dev->irq);
-
- printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
- dev->name, rtl_chip_info[tp->chipset].name);
-
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later, but
- takes too much time. */
-#ifdef CONFIG_8139TOO_8129
- if (tp->drv_flags & HAS_MII_XCVR) {
- int phy, phy_idx = 0;
- for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
- int mii_status = mdio_read(dev, phy, 1);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- u16 advertising = mdio_read(dev, phy, 4);
- tp->phys[phy_idx++] = phy;
- printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
- "advertising %4.4x.\n",
- dev->name, phy, mii_status, advertising);
- }
- }
- if (phy_idx == 0) {
- printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
- "transceiver.\n",
- dev->name);
- tp->phys[0] = 32;
- }
- } else
-#endif
- tp->phys[0] = 32;
- tp->mii.phy_id = tp->phys[0];
-
- /* The lower four bits are the media type. */
- option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
- if (option > 0) {
- tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
- tp->default_port = option & 0xFF;
- if (tp->default_port)
- tp->mii.force_media = 1;
- }
- if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
- tp->mii.full_duplex = full_duplex[board_idx];
- if (tp->mii.full_duplex) {
- printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
- /* Changing the MII-advertised media because might prevent
- re-connection. */
- tp->mii.force_media = 1;
- }
- if (tp->default_port) {
- printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
- (option & 0x20 ? 100 : 10),
- (option & 0x10 ? "full" : "half"));
- mdio_write(dev, tp->phys[0], 0,
- ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */
- ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
- }
-
- /* Put the chip into low-power mode. */
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
-
- return 0;
-
-err_out:
- __rtl8139_cleanup_dev (dev);
- pci_disable_device (pdev);
- return i;
-}
-
-
-static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
-
- assert (dev != NULL);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- unregister_netdev (dev);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- __rtl8139_cleanup_dev (dev);
- pci_disable_device (pdev);
-}
-
-
-/* Serial EEPROM section. */
-
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
-#define EE_CS 0x08 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x00
-#define EE_WRITE_1 0x02
-#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
-#define EE_ENB (0x80 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
-#define eeprom_delay() RTL_R32(Cfg9346)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5)
-#define EE_READ_CMD (6)
-#define EE_ERASE_CMD (7)
-
-static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- int read_cmd = location | (EE_READ_CMD << addr_len);
-
- RTL_W8 (Cfg9346, EE_ENB & ~EE_CS);
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
-
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- RTL_W8 (Cfg9346, EE_ENB | dataval);
- eeprom_delay ();
- RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK);
- eeprom_delay ();
- }
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
-
- for (i = 16; i > 0; i--) {
- RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK);
- eeprom_delay ();
- retval =
- (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 :
- 0);
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
- }
-
- /* Terminate the EEPROM access. */
- RTL_W8 (Cfg9346, ~EE_CS);
- eeprom_delay ();
-
- return retval;
-}
-
-/* MII serial management: mostly bogus for now. */
-/* Read and write the MII management registers using software-generated
- serial MDIO protocol.
- The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues. */
-#define MDIO_DIR 0x80
-#define MDIO_DATA_OUT 0x04
-#define MDIO_DATA_IN 0x02
-#define MDIO_CLK 0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-
-#define mdio_delay() RTL_R8(Config4)
-
-
-static char mii_2_8139_map[8] = {
- BasicModeCtrl,
- BasicModeStatus,
- 0,
- 0,
- NWayAdvert,
- NWayLPAR,
- NWayExpansion,
- 0
-};
-
-
-#ifdef CONFIG_8139TOO_8129
-/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync (void __iomem *ioaddr)
-{
- int i;
-
- for (i = 32; i >= 0; i--) {
- RTL_W8 (Config4, MDIO_WRITE1);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK);
- mdio_delay ();
- }
-}
-#endif
-
-static int mdio_read (struct net_device *dev, int phy_id, int location)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int retval = 0;
-#ifdef CONFIG_8139TOO_8129
- void __iomem *ioaddr = tp->mmio_addr;
- int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- int i;
-#endif
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- void __iomem *ioaddr = tp->mmio_addr;
- return location < 8 && mii_2_8139_map[location] ?
- RTL_R16 (mii_2_8139_map[location]) : 0;
- }
-
-#ifdef CONFIG_8139TOO_8129
- mdio_sync (ioaddr);
- /* Shift the read command bits out. */
- for (i = 15; i >= 0; i--) {
- int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
- RTL_W8 (Config4, MDIO_DIR | dataval);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK);
- mdio_delay ();
- }
-
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- RTL_W8 (Config4, 0);
- mdio_delay ();
- retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0);
- RTL_W8 (Config4, MDIO_CLK);
- mdio_delay ();
- }
-#endif
-
- return (retval >> 1) & 0xffff;
-}
-
-
-static void mdio_write (struct net_device *dev, int phy_id, int location,
- int value)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-#ifdef CONFIG_8139TOO_8129
- void __iomem *ioaddr = tp->mmio_addr;
- int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
- int i;
-#endif
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- void __iomem *ioaddr = tp->mmio_addr;
- if (location == 0) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W16 (BasicModeCtrl, value);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- } else if (location < 8 && mii_2_8139_map[location])
- RTL_W16 (mii_2_8139_map[location], value);
- return;
- }
-
-#ifdef CONFIG_8139TOO_8129
- mdio_sync (ioaddr);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval =
- (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- RTL_W8 (Config4, dataval);
- mdio_delay ();
- RTL_W8 (Config4, dataval | MDIO_CLK);
- mdio_delay ();
- }
- /* Clear out extra bits. */
- for (i = 2; i > 0; i--) {
- RTL_W8 (Config4, 0);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_CLK);
- mdio_delay ();
- }
-#endif
-}
-
-
-static int rtl8139_open (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int retval;
- void __iomem *ioaddr = tp->mmio_addr;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-#ifdef ECAT_DEBUG
- printk(KERN_DEBUG "%s: open\n", dev->name);
-#endif
-
- if (dev != rtl_ecat_dev.dev)
- {
- retval = request_irq(dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
- if (retval)
- return retval;
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- &tp->tx_bufs_dma);
- tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- &tp->rx_ring_dma);
- if (tp->tx_bufs == NULL || tp->rx_ring == NULL)
- {
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- free_irq(dev->irq, dev);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- if (tp->tx_bufs)
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- if (tp->rx_ring)
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
-
- return -ENOMEM;
- }
-
- tp->mii.full_duplex = tp->mii.force_media;
- tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
-
- rtl8139_init_ring (dev);
- rtl8139_hw_start (dev);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- netif_start_queue (dev);
-
- if (netif_msg_ifup(tp))
- {
- printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
- " GP Pins %2.2x %s-duplex.\n",
- dev->name, pci_resource_start (tp->pci_dev, 1),
- dev->irq, RTL_R8 (MediaStatus),
- tp->mii.full_duplex ? "full" : "half");
- }
-
- rtl8139_start_thread(dev);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- return 0;
-}
-
-
-static void rtl_check_media (struct net_device *dev, unsigned int init_media)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-
- if (tp->phys[0] >= 0) {
- mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
- }
-}
-
-/* Start the hardware at open or resume. */
-static void rtl8139_hw_start (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u32 i;
- u8 tmp;
-
- /* Bring old chips out of low-power mode. */
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'R');
-
- rtl8139_chip_reset (ioaddr);
-
- /* unlock Config[01234] and BMCR register writes */
- RTL_W8_F (Cfg9346, Cfg9346_Unlock);
- /* Restore our idea of the MAC address. */
- RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
-
- /* Must enable Tx/Rx before setting transfer thresholds! */
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
- RTL_W32 (RxConfig, tp->rx_config);
- RTL_W32 (TxConfig, rtl8139_tx_config);
-
- tp->cur_rx = 0;
-
- rtl_check_media (dev, 1);
-
- if (tp->chipset >= CH_8139B) {
- /* Disable magic packet scanning, which is enabled
- * when PM is enabled in Config1. It can be reenabled
- * via ETHTOOL_SWOL if desired. */
- RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
- }
-
- DPRINTK("init buffer addresses\n");
-
- /* Lock Config[01234] and BMCR register writes */
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- /* init Rx ring buffer DMA address */
- RTL_W32_F (RxBuf, tp->rx_ring_dma);
-
- /* init Tx buffer DMA addresses */
- for (i = 0; i < NUM_TX_DESC; i++)
- RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
-
- RTL_W32 (RxMissed, 0);
-
- rtl8139_set_rx_mode (dev);
-
- /* no early-rx interrupts */
- RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
-
- /* make sure RxTx has started */
- tmp = RTL_R8 (ChipCmd);
- if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- /* Enable all known interrupts by setting the interrupt mask. */
- RTL_W16 (IntrMask, rtl8139_intr_mask);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void rtl8139_init_ring (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int i;
-
- tp->cur_rx = 0;
- tp->cur_tx = 0;
- tp->dirty_tx = 0;
-
- for (i = 0; i < NUM_TX_DESC; i++)
- tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
-}
-
-
-/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
-static int next_tick = 3 * HZ;
-
-#ifndef CONFIG_8139TOO_TUNE_TWISTER
-static inline void rtl8139_tune_twister (struct net_device *dev,
- struct rtl8139_private *tp) {}
-#else
-enum TwisterParamVals {
- PARA78_default = 0x78fa8388,
- PARA7c_default = 0xcb38de43, /* param[0][3] */
- PARA7c_xxx = 0xcb38de43,
-};
-
-static const unsigned long param[4][4] = {
- {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
-};
-
-static void rtl8139_tune_twister (struct net_device *dev,
- struct rtl8139_private *tp)
-{
- int linkcase;
- void __iomem *ioaddr = tp->mmio_addr;
-
- /* This is a complicated state machine to configure the "twister" for
- impedance/echos based on the cable length.
- All of this is magic and undocumented.
- */
- switch (tp->twistie) {
- case 1:
- if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
- /* We have link beat, let us tune the twister. */
- RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
- tp->twistie = 2; /* Change to state 2. */
- next_tick = HZ / 10;
- } else {
- /* Just put in some reasonable defaults for when beat returns. */
- RTL_W16 (CSCR, CSCR_LinkDownCmd);
- RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */
- RTL_W32 (PARA78, PARA78_default);
- RTL_W32 (PARA7c, PARA7c_default);
- tp->twistie = 0; /* Bail from future actions. */
- }
- break;
- case 2:
- /* Read how long it took to hear the echo. */
- linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
- if (linkcase == 0x7000)
- tp->twist_row = 3;
- else if (linkcase == 0x3000)
- tp->twist_row = 2;
- else if (linkcase == 0x1000)
- tp->twist_row = 1;
- else
- tp->twist_row = 0;
- tp->twist_col = 0;
- tp->twistie = 3; /* Change to state 2. */
- next_tick = HZ / 10;
- break;
- case 3:
- /* Put out four tuning parameters, one per 100msec. */
- if (tp->twist_col == 0)
- RTL_W16 (FIFOTMS, 0);
- RTL_W32 (PARA7c, param[(int) tp->twist_row]
- [(int) tp->twist_col]);
- next_tick = HZ / 10;
- if (++tp->twist_col >= 4) {
- /* For short cables we are done.
- For long cables (row == 3) check for mistune. */
- tp->twistie =
- (tp->twist_row == 3) ? 4 : 0;
- }
- break;
- case 4:
- /* Special case for long cables: check for mistune. */
- if ((RTL_R16 (CSCR) &
- CSCR_LinkStatusBits) == 0x7000) {
- tp->twistie = 0;
- break;
- } else {
- RTL_W32 (PARA7c, 0xfb38de03);
- tp->twistie = 5;
- next_tick = HZ / 10;
- }
- break;
- case 5:
- /* Retune for shorter cable (column 2). */
- RTL_W32 (FIFOTMS, 0x20);
- RTL_W32 (PARA78, PARA78_default);
- RTL_W32 (PARA7c, PARA7c_default);
- RTL_W32 (FIFOTMS, 0x00);
- tp->twist_row = 2;
- tp->twist_col = 0;
- tp->twistie = 3;
- next_tick = HZ / 10;
- break;
-
- default:
- /* do nothing */
- break;
- }
-}
-#endif /* CONFIG_8139TOO_TUNE_TWISTER */
-
-static inline void rtl8139_thread_iter (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr)
-{
- int mii_lpa;
-
- mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
-
- if (!tp->mii.force_media && mii_lpa != 0xffff) {
- int duplex = (mii_lpa & LPA_100FULL)
- || (mii_lpa & 0x01C0) == 0x0040;
- if (tp->mii.full_duplex != duplex) {
- tp->mii.full_duplex = duplex;
-
- if (mii_lpa) {
- printk (KERN_INFO
- "%s: Setting %s-duplex based on MII #%d link"
- " partner ability of %4.4x.\n",
- dev->name,
- tp->mii.full_duplex ? "full" : "half",
- tp->phys[0], mii_lpa);
- } else {
- printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
- dev->name);
- }
-#if 0
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-#endif
- }
- }
-
- next_tick = HZ * 60;
-
- rtl8139_tune_twister (dev, tp);
-
- DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
- dev->name, RTL_R16 (NWayLPAR));
- DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n",
- dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
- DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
- dev->name, RTL_R8 (Config0),
- RTL_R8 (Config1));
-}
-
-static int rtl8139_thread (void *data)
-{
- struct net_device *dev = data;
- struct rtl8139_private *tp = netdev_priv(dev);
- unsigned long timeout;
-
- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
- while (1) {
- timeout = next_tick;
- do {
- timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
- /* make swsusp happy with our thread */
- try_to_freeze();
- } while (!signal_pending (current) && (timeout > 0));
-
- if (signal_pending (current)) {
- flush_signals(current);
- }
-
- if (tp->time_to_die)
- break;
-
- if (rtnl_lock_interruptible ())
- break;
- rtl8139_thread_iter (dev, tp, tp->mmio_addr);
- rtnl_unlock ();
- }
-
- complete_and_exit (&tp->thr_exited, 0);
-}
-
-static void rtl8139_start_thread(struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-
- tp->thr_pid = -1;
- tp->twistie = 0;
- tp->time_to_die = 0;
- if (tp->chipset == CH_8139_K)
- tp->twistie = 1;
- else if (tp->drv_flags & HAS_LNK_CHNG)
- return;
-
- tp->thr_pid = kernel_thread(rtl8139_thread, dev, CLONE_FS|CLONE_FILES);
- if (tp->thr_pid < 0) {
- printk (KERN_WARNING "%s: unable to start kernel thread\n",
- dev->name);
- }
-}
-
-static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
-{
- tp->cur_tx = 0;
- tp->dirty_tx = 0;
-
- /* XXX account for unsent Tx packets in tp->stats.tx_dropped */
-}
-
-
-static void rtl8139_tx_timeout (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int i;
- u8 tmp8;
- unsigned long flags;
-
- printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
- "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
- RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
- /* Emit info to figure out what went wrong. */
- printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n",
- dev->name, tp->cur_tx, tp->dirty_tx);
- for (i = 0; i < NUM_TX_DESC; i++)
- printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n",
- dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
- i == tp->dirty_tx % NUM_TX_DESC ?
- " (queue head)" : "");
-
- tp->xstats.tx_timeouts++;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- printk(KERN_DEBUG "%s: tx_timeout\n", dev->name);
-
- if (dev == rtl_ecat_dev.dev)
- {
- if (rtl_ecat_dev.state != ECAT_DS_SENT)
- {
- printk(KERN_WARNING "EtherCAT: Wrong status at timeout: %i\n",
- rtl_ecat_dev.state);
- }
-
- rtl_ecat_dev.state = ECAT_DS_TIMEOUT;
- }
-
- /* disable Tx ASAP, if not already */
- tmp8 = RTL_R8 (ChipCmd);
- if (tmp8 & CmdTxEnb)
- RTL_W8 (ChipCmd, CmdRxEnb);
-
- if (dev != rtl_ecat_dev.dev)
- {
- spin_lock(&tp->rx_lock);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16 (IntrMask, 0x0000);
-
- /* Stop a shared interrupt from scavenging while we are. */
- spin_lock_irqsave (&tp->lock, flags);
- rtl8139_tx_clear (tp);
- spin_unlock_irqrestore (&tp->lock, flags);
-
- /* ...and finally, reset everything */
-
- if (netif_running(dev))
- {
- rtl8139_hw_start (dev);
- netif_wake_queue (dev);
- }
-
- spin_unlock(&tp->rx_lock);
- }
- else
- {
- rtl8139_tx_clear (tp);
- rtl8139_hw_start(dev);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-}
-
-static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned int entry;
- unsigned int len = skb->len;
-
- /* Calculate the next Tx descriptor entry. */
- entry = tp->cur_tx % NUM_TX_DESC;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- /* Note: the chip doesn't have auto-pad! */
- if (likely(len < TX_BUF_SIZE))
- {
- if (len < ETH_ZLEN)
- memset(tp->tx_buf[entry], 0, ETH_ZLEN);
-
- skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
- if (dev != rtl_ecat_dev.dev) dev_kfree_skb(skb);
- }
- else
- {
- if (dev != rtl_ecat_dev.dev) dev_kfree_skb(skb);
- tp->stats.tx_dropped++;
- return 0;
- }
-
- if (dev != rtl_ecat_dev.dev)
- {
- spin_lock_irq(&tp->lock);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
- tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
-
- dev->trans_start = jiffies;
-
- tp->cur_tx++;
- wmb();
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
- netif_stop_queue (dev);
-
- spin_unlock_irq(&tp->lock);
-
- if (netif_msg_tx_queued(tp))
- printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
- dev->name, len, entry);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- return 0;
-}
-
-
-static void rtl8139_tx_interrupt (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr)
-{
- unsigned long dirty_tx, tx_left;
-
- assert (dev != NULL);
- assert (ioaddr != NULL);
-
- dirty_tx = tp->dirty_tx;
- tx_left = tp->cur_tx - dirty_tx;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev)
- {
- rtl_ecat_dev.tx_intr_cnt++;
- rdtscl(rtl_ecat_dev.tx_time); // Get CPU cycles
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- while (tx_left > 0) {
- int entry = dirty_tx % NUM_TX_DESC;
- int txstatus;
-
- txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
-
- if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
- break; /* It still hasn't been Txed */
-
- /* Note: TxCarrierLost is always asserted at 100mbps. */
- if (txstatus & (TxOutOfWindow | TxAborted)) {
- /* There was an major error, log it. */
- if (netif_msg_tx_err(tp))
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
- tp->stats.tx_errors++;
- if (txstatus & TxAborted) {
- tp->stats.tx_aborted_errors++;
- RTL_W32 (TxConfig, TxClearAbt);
- RTL_W16 (IntrStatus, TxErr);
- wmb();
- }
- if (txstatus & TxCarrierLost)
- tp->stats.tx_carrier_errors++;
- if (txstatus & TxOutOfWindow)
- tp->stats.tx_window_errors++;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev)
- {
- rtl_ecat_dev.state = ECAT_DS_ERROR;
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- } else {
- if (txstatus & TxUnderrun) {
- /* Add 64 to the Tx FIFO threshold. */
- if (tp->tx_flag < 0x00300000)
- tp->tx_flag += 0x00020000;
- tp->stats.tx_fifo_errors++;
- }
- tp->stats.collisions += (txstatus >> 24) & 15;
- tp->stats.tx_bytes += txstatus & 0x7ff;
- tp->stats.tx_packets++;
- }
-
- dirty_tx++;
- tx_left--;
- }
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-#ifndef RTL8139_NDEBUG
- if (dev != rtl_ecat_dev.dev && tp->cur_tx - dirty_tx > NUM_TX_DESC) {
- printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
- dev->name, dirty_tx, tp->cur_tx);
- dirty_tx += NUM_TX_DESC;
- }
-#endif /* RTL8139_NDEBUG */
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- /* only wake the queue if we did work, and the queue is stopped */
- if (tp->dirty_tx != dirty_tx) {
- tp->dirty_tx = dirty_tx;
- mb();
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- netif_wake_queue (dev);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- }
-}
-
-
-/* TODO: clean this up! Rx reset need not be this intensive */
-static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
- struct rtl8139_private *tp, void __iomem *ioaddr)
-{
- u8 tmp8;
-#ifdef CONFIG_8139_OLD_RX_RESET
- int tmp_work;
-#endif
-
- if (netif_msg_rx_err (tp))
- printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
- dev->name, rx_status);
- tp->stats.rx_errors++;
- if (!(rx_status & RxStatusOK)) {
- if (rx_status & RxTooLong) {
- DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
- dev->name, rx_status);
- /* A.C.: The chip hangs here. */
- }
- if (rx_status & (RxBadSymbol | RxBadAlign))
- tp->stats.rx_frame_errors++;
- if (rx_status & (RxRunt | RxTooLong))
- tp->stats.rx_length_errors++;
- if (rx_status & RxCRCErr)
- tp->stats.rx_crc_errors++;
- } else {
- tp->xstats.rx_lost_in_ring++;
- }
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev)
- {
- rtl_ecat_dev.state = ECAT_DS_ERROR;
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-#ifndef CONFIG_8139_OLD_RX_RESET
- tmp8 = RTL_R8 (ChipCmd);
- RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
- RTL_W8 (ChipCmd, tmp8);
- RTL_W32 (RxConfig, tp->rx_config);
- tp->cur_rx = 0;
-#else
- /* Reset the receiver, based on RealTek recommendation. (Bug?) */
-
- /* disable receive */
- RTL_W8_F (ChipCmd, CmdTxEnb);
- tmp_work = 200;
- while (--tmp_work > 0) {
- udelay(1);
- tmp8 = RTL_R8 (ChipCmd);
- if (!(tmp8 & CmdRxEnb))
- break;
- }
- if (tmp_work <= 0)
- printk (KERN_WARNING PFX "rx stop wait too long\n");
- /* restart receive */
- tmp_work = 200;
- while (--tmp_work > 0) {
- RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
- udelay(1);
- tmp8 = RTL_R8 (ChipCmd);
- if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
- break;
- }
- if (tmp_work <= 0)
- printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
-
- /* and reinitialize all rx related registers */
- RTL_W8_F (Cfg9346, Cfg9346_Unlock);
- /* Must enable Tx/Rx before setting transfer thresholds! */
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
- RTL_W32 (RxConfig, tp->rx_config);
- tp->cur_rx = 0;
-
- DPRINTK("init buffer addresses\n");
-
- /* Lock Config[01234] and BMCR register writes */
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- /* init Rx ring buffer DMA address */
- RTL_W32_F (RxBuf, tp->rx_ring_dma);
-
- /* A.C.: Reset the multicast list. */
- __set_rx_mode (dev);
-#endif
-}
-
-#if RX_BUF_IDX == 3
-static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
- u32 offset, unsigned int size)
-{
- u32 left = RX_BUF_LEN - offset;
-
- if (size > left) {
- memcpy(skb->data, ring + offset, left);
- memcpy(skb->data+left, ring, size - left);
- } else
- memcpy(skb->data, ring + offset, size);
-}
-#endif
-
-static void rtl8139_isr_ack(struct rtl8139_private *tp)
-{
- void __iomem *ioaddr = tp->mmio_addr;
- u16 status;
-
- status = RTL_R16 (IntrStatus) & RxAckBits;
-
- /* Clear out errors and receive interrupts */
- if (likely(status != 0)) {
- if (unlikely(status & (RxFIFOOver | RxOverflow))) {
- tp->stats.rx_errors++;
- if (status & RxFIFOOver)
- tp->stats.rx_fifo_errors++;
- }
- RTL_W16_F (IntrStatus, RxAckBits);
- }
-}
-
-static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
- int budget)
-{
- void __iomem *ioaddr = tp->mmio_addr;
- int received = 0;
- unsigned char *rx_ring = tp->rx_ring;
- unsigned int cur_rx = tp->cur_rx;
- unsigned int rx_size = 0;
-
- DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev)
- {
- rtl_ecat_dev.rx_intr_cnt++;
- rdtscl(rtl_ecat_dev.rx_time); // Get CPU cycles
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- while ((dev == rtl_ecat_dev.dev || netif_running(dev))
- && received < budget
- && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
- u32 ring_offset = cur_rx % RX_BUF_LEN;
- u32 rx_status;
- unsigned int pkt_size;
- struct sk_buff *skb;
-
- rmb();
-
- /* read size+status of next frame from DMA ring buffer */
- rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
- rx_size = rx_status >> 16;
- pkt_size = rx_size - 4;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev && netif_msg_rx_status(tp))
- printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x,"
- " cur %4.4x.\n", dev->name, rx_status,
- rx_size, cur_rx);
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
-#if RTL8139_DEBUG > 2
- {
- int i;
- DPRINTK ("%s: Frame contents ", dev->name);
- for (i = 0; i < 70; i++)
- printk (" %2.2x",
- rx_ring[ring_offset + i]);
- printk (".\n");
- }
-#endif
-
- /* Packet copy from FIFO still in progress.
- * Theoretically, this should never happen
- * since EarlyRx is disabled.
- */
- if (unlikely(rx_size == 0xfff0)) {
- if (!tp->fifo_copy_timeout)
- tp->fifo_copy_timeout = jiffies + 2;
- else if (time_after(jiffies, tp->fifo_copy_timeout)) {
- DPRINTK ("%s: hung FIFO. Reset.", dev->name);
- rx_size = 0;
- goto no_early_rx;
- }
- if (netif_msg_intr(tp)) {
- printk(KERN_DEBUG "%s: fifo copy in progress.",
- dev->name);
- }
- tp->xstats.early_rx++;
- break;
- }
-
-no_early_rx:
- tp->fifo_copy_timeout = 0;
-
- /* If Rx err or invalid rx_size/rx_status received
- * (which happens if we get lost in the ring),
- * Rx process gets reset, so we abort any further
- * Rx processing.
- */
- if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
- (rx_size < 8) ||
- (!(rx_status & RxStatusOK)))) {
- rtl8139_rx_err (rx_status, dev, tp, ioaddr);
- received = -1;
- goto out;
- }
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- /* Malloc up new buffer, compatible with net-2e. */
- /* Omit the four octet CRC from the length. */
- skb = dev_alloc_skb(pkt_size + 2);
-
- if (likely(skb)) {
- skb->dev = dev;
- skb_reserve (skb, 2); /* 16 byte align the IP fields. */
-#if RX_BUF_IDX == 3
- wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
-#else
- eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
-#endif
- skb_put (skb, pkt_size);
-
- skb->protocol = eth_type_trans (skb, dev);
-
- dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
-
- netif_receive_skb (skb);
- } else {
- if (net_ratelimit())
- printk (KERN_WARNING
- "%s: Memory squeeze, dropping packet.\n",
- dev->name);
- tp->stats.rx_dropped++;
- }
- }
- else
- {
- if (rtl_ecat_dev.state != ECAT_DS_SENT)
- {
- printk(KERN_WARNING "EtherCAT: Received frame while not in SENT state!\n");
- }
- else
- {
- // Copy received data to ethercat-device buffer, skip Ethernet-II header
- memcpy(rtl_ecat_dev.rx_data, &rx_ring[ring_offset + 4] + ETH_HLEN,
- pkt_size - ETH_HLEN);
- rtl_ecat_dev.rx_data_length = pkt_size - ETH_HLEN;
-
- rtl_ecat_dev.state = ECAT_DS_RECEIVED;
-
- dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
- }
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- received++;
-
- cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
-
- rtl8139_isr_ack(tp);
- }
-
- if (unlikely(!received || rx_size == 0xfff0))
- rtl8139_isr_ack(tp);
-
-#if RTL8139_DEBUG > 1
- DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
-#endif
-
- tp->cur_rx = cur_rx;
-
- /*
- * The receive buffer should be mostly empty.
- * Tell NAPI to reenable the Rx irq.
- */
- if (tp->fifo_copy_timeout)
- received = budget;
-
-out:
- return received;
-}
-
-
-static void rtl8139_weird_interrupt (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr,
- int status, int link_changed)
-{
- DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
- dev->name, status);
-
- assert (dev != NULL);
- assert (tp != NULL);
- assert (ioaddr != NULL);
-
- /* Update the error count. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- if ((status & RxUnderrun) && link_changed &&
- (tp->drv_flags & HAS_LNK_CHNG)) {
- rtl_check_media(dev, 0);
- status &= ~RxUnderrun;
- }
-
- if (status & (RxUnderrun | RxErr))
- tp->stats.rx_errors++;
-
- if (status & PCSTimeout)
- tp->stats.rx_length_errors++;
- if (status & RxUnderrun)
- tp->stats.rx_fifo_errors++;
- if (status & PCIErr) {
- u16 pci_cmd_status;
- pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
- pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
-
- printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
- dev->name, pci_cmd_status);
- }
-}
-
-int rtl8139_poll(struct net_device *dev, int *budget)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int orig_budget = min(*budget, dev->quota);
- int done = 1;
-
- spin_lock(&tp->rx_lock);
- if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
- int work_done;
-
- work_done = rtl8139_rx(dev, tp, orig_budget);
- if (likely(work_done > 0)) {
- *budget -= work_done;
- dev->quota -= work_done;
- done = (work_done < orig_budget);
- }
- }
-
- if (done) {
- /*
- * Order is important since data can get interrupted
- * again when we think we are done.
- */
-
- local_irq_disable();
- RTL_W16_F(IntrMask, rtl8139_intr_mask);
- __netif_rx_complete(dev);
- local_irq_enable();
- }
- spin_unlock(&tp->rx_lock);
-
- return !done;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *) dev_instance;
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u16 status, ackstat;
- int link_changed = 0; /* avoid bogus "uninit" warning */
- int handled = 0;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev)
- {
- rtl_ecat_dev.intr_cnt++;
- status = RTL_R16 (IntrStatus);
- }
- else
- {
- spin_lock(&tp->lock);
-
- status = RTL_R16 (IntrStatus);
-
- if (unlikely((status & rtl8139_intr_mask) == 0))
- goto out;
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- handled = 1;
-
- /* h/w no longer present (hotplug?) or major error, bail */
- if (unlikely(status == 0xFFFF))
- goto out;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- /* close possible race's with dev_close */
- if (unlikely(!netif_running(dev))) {
- RTL_W16 (IntrMask, 0);
- goto out;
- }
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- /* Acknowledge all of the current interrupt sources ASAP, but
- an first get an additional status bit from CSCR. */
- if (unlikely(status & RxUnderrun))
- link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
-
- ackstat = status & ~(RxAckBits | TxErr);
- if (ackstat) {
- RTL_W16 (IntrStatus, ackstat);
- //printk("ECAT-NIC ack\n"); //HM
- }
-
- /* Receive packets are processed by poll routine.
- If not running start it now. */
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (status & RxAckBits)
- {
- if (dev != rtl_ecat_dev.dev)
- {
- /* Polling vormerken */
- if (netif_rx_schedule_prep(dev)) {
- RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
- __netif_rx_schedule (dev);
- }
- }
- else
- {
- /* Beim EtherCAT-Device einfach alle Frames empfangen */
- rtl8139_rx(dev, tp, 100); // FIXME Das ist echt dirty...
- }
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- /* Check uncommon events with one test. */
- if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr)))
- rtl8139_weird_interrupt (dev, tp, ioaddr,
- status, link_changed);
-
- if (status & (TxOK | TxErr)) {
- rtl8139_tx_interrupt (dev, tp, ioaddr);
- if (status & TxErr)
- RTL_W16 (IntrStatus, TxErr);
- }
- out:
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- spin_unlock (&tp->lock);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
- return IRQ_RETVAL(handled);
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void rtl8139_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- rtl8139_interrupt(dev->irq, dev, NULL);
- enable_irq(dev->irq);
-}
-#endif
-
-static int rtl8139_close (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int ret = 0;
- unsigned long flags;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev != rtl_ecat_dev.dev)
- {
- netif_stop_queue(dev);
- if (tp->thr_pid >= 0) {
- tp->time_to_die = 1;
- wmb();
- ret = kill_proc (tp->thr_pid, SIGTERM, 1);
- if (ret) {
- printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
- return ret;
- }
- wait_for_completion (&tp->thr_exited);
- }
-
- if (netif_msg_ifdown(tp))
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
-
- spin_lock_irqsave (&tp->lock, flags);
-
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8 (ChipCmd, 0);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16 (IntrMask, 0);
-
- /* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
-
- synchronize_irq (dev->irq); /* racy, but that's ok here */
- free_irq (dev->irq, dev);
- }
- else
- {
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8 (ChipCmd, 0);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16 (IntrMask, 0);
-
- /* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- rtl8139_tx_clear (tp);
-
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- tp->rx_ring = NULL;
- tp->tx_bufs = NULL;
-
- /* Green! Put the chip in low-power mode. */
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
-
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
-
- return 0;
-}
-
-
-/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to
- kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
- other threads or interrupts aren't messing with the 8139. */
-static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- void __iomem *ioaddr = np->mmio_addr;
-
- spin_lock_irq(&np->lock);
- if (rtl_chip_info[np->chipset].flags & HasLWake) {
- u8 cfg3 = RTL_R8 (Config3);
- u8 cfg5 = RTL_R8 (Config5);
-
- wol->supported = WAKE_PHY | WAKE_MAGIC
- | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
-
- wol->wolopts = 0;
- if (cfg3 & Cfg3_LinkUp)
- wol->wolopts |= WAKE_PHY;
- if (cfg3 & Cfg3_Magic)
- wol->wolopts |= WAKE_MAGIC;
- /* (KON)FIXME: See how netdev_set_wol() handles the
- following constants. */
- if (cfg5 & Cfg5_UWF)
- wol->wolopts |= WAKE_UCAST;
- if (cfg5 & Cfg5_MWF)
- wol->wolopts |= WAKE_MCAST;
- if (cfg5 & Cfg5_BWF)
- wol->wolopts |= WAKE_BCAST;
- }
- spin_unlock_irq(&np->lock);
-}
-
-
-/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes
- that wol points to kernel memory and other threads or interrupts
- aren't messing with the 8139. */
-static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- void __iomem *ioaddr = np->mmio_addr;
- u32 support;
- u8 cfg3, cfg5;
-
- support = ((rtl_chip_info[np->chipset].flags & HasLWake)
- ? (WAKE_PHY | WAKE_MAGIC
- | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)
- : 0);
- if (wol->wolopts & ~support)
- return -EINVAL;
-
- spin_lock_irq(&np->lock);
- cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
- if (wol->wolopts & WAKE_PHY)
- cfg3 |= Cfg3_LinkUp;
- if (wol->wolopts & WAKE_MAGIC)
- cfg3 |= Cfg3_Magic;
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config3, cfg3);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF);
- /* (KON)FIXME: These are untested. We may have to set the
- CRC0, Wakeup0 and LSBCRC0 registers too, but I have no
- documentation. */
- if (wol->wolopts & WAKE_UCAST)
- cfg5 |= Cfg5_UWF;
- if (wol->wolopts & WAKE_MCAST)
- cfg5 |= Cfg5_MWF;
- if (wol->wolopts & WAKE_BCAST)
- cfg5 |= Cfg5_BWF;
- RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */
- spin_unlock_irq(&np->lock);
-
- return 0;
-}
-
-static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(np->pci_dev));
- info->regdump_len = np->regs_len;
-}
-
-static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- spin_lock_irq(&np->lock);
- mii_ethtool_gset(&np->mii, cmd);
- spin_unlock_irq(&np->lock);
- return 0;
-}
-
-static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- int rc;
- spin_lock_irq(&np->lock);
- rc = mii_ethtool_sset(&np->mii, cmd);
- spin_unlock_irq(&np->lock);
- return rc;
-}
-
-static int rtl8139_nway_reset(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return mii_nway_restart(&np->mii);
-}
-
-static u32 rtl8139_get_link(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return mii_link_ok(&np->mii);
-}
-
-static u32 rtl8139_get_msglevel(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return np->msg_enable;
-}
-
-static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- np->msg_enable = datum;
-}
-
-/* TODO: we are too slack to do reg dumping for pio, for now */
-#ifdef CONFIG_8139TOO_PIO
-#define rtl8139_get_regs_len NULL
-#define rtl8139_get_regs NULL
-#else
-static int rtl8139_get_regs_len(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return np->regs_len;
-}
-
-static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
-{
- struct rtl8139_private *np = netdev_priv(dev);
-
- regs->version = RTL_REGS_VER;
-
- spin_lock_irq(&np->lock);
- memcpy_fromio(regbuf, np->mmio_addr, regs->len);
- spin_unlock_irq(&np->lock);
-}
-#endif /* CONFIG_8139TOO_MMIO */
-
-static int rtl8139_get_stats_count(struct net_device *dev)
-{
- return RTL_NUM_STATS;
-}
-
-static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
-{
- struct rtl8139_private *np = netdev_priv(dev);
-
- data[0] = np->xstats.early_rx;
- data[1] = np->xstats.tx_buf_mapped;
- data[2] = np->xstats.tx_timeouts;
- data[3] = np->xstats.rx_lost_in_ring;
-}
-
-static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
-{
- memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
-}
-
-static struct ethtool_ops rtl8139_ethtool_ops = {
- .get_drvinfo = rtl8139_get_drvinfo,
- .get_settings = rtl8139_get_settings,
- .set_settings = rtl8139_set_settings,
- .get_regs_len = rtl8139_get_regs_len,
- .get_regs = rtl8139_get_regs,
- .nway_reset = rtl8139_nway_reset,
- .get_link = rtl8139_get_link,
- .get_msglevel = rtl8139_get_msglevel,
- .set_msglevel = rtl8139_set_msglevel,
- .get_wol = rtl8139_get_wol,
- .set_wol = rtl8139_set_wol,
- .get_strings = rtl8139_get_strings,
- .get_stats_count = rtl8139_get_stats_count,
- .get_ethtool_stats = rtl8139_get_ethtool_stats,
-};
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- int rc;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev || !netif_running(dev))
- return -EINVAL;
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- spin_lock_irq(&np->lock);
- rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL);
- spin_unlock_irq(&np->lock);
-
- return rc;
-}
-
-
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev || netif_running(dev))
- {
- spin_lock_irqsave (&tp->lock, flags);
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
- spin_unlock_irqrestore (&tp->lock, flags);
- }
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- return &tp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- This routine is not state sensitive and need not be SMP locked. */
-
-static void __set_rx_mode (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
- u32 tmp;
-
- DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
- dev->name, dev->flags, RTL_R32 (RxConfig));
-
- /* Note: do not reorder, GCC is clever about common statements. */
- if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
- rx_mode =
- AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
- AcceptAllPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else {
- struct dev_mc_list *mclist;
- rx_mode = AcceptBroadcast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
- int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- rx_mode |= AcceptMulticast;
- }
- }
-
- /* We can safely update without stopping the chip. */
- tmp = rtl8139_rx_config | rx_mode;
- if (tp->rx_config != tmp) {
- RTL_W32_F (RxConfig, tmp);
- tp->rx_config = tmp;
- }
- RTL_W32_F (MAR0 + 0, mc_filter[0]);
- RTL_W32_F (MAR0 + 4, mc_filter[1]);
-}
-
-static void rtl8139_set_rx_mode (struct net_device *dev)
-{
- unsigned long flags;
- struct rtl8139_private *tp = netdev_priv(dev);
-
- spin_lock_irqsave (&tp->lock, flags);
- __set_rx_mode(dev);
- spin_unlock_irqrestore (&tp->lock, flags);
-}
-
-#ifdef CONFIG_PM
-
-static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- pci_save_state (pdev);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev || !netif_running (dev))
- return 0;
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- netif_device_detach (dev);
-
- spin_lock_irqsave (&tp->lock, flags);
-
- /* Disable interrupts, stop Tx and Rx. */
- RTL_W16 (IntrMask, 0);
- RTL_W8 (ChipCmd, 0);
-
- /* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
-
- pci_set_power_state (pdev, PCI_D3hot);
-
- return 0;
-}
-
-
-static int rtl8139_resume (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
-
- pci_restore_state (pdev);
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- if (dev == rtl_ecat_dev.dev || !netif_running (dev))
- return 0;
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-
- pci_set_power_state (pdev, PCI_D0);
- rtl8139_init_ring (dev);
- rtl8139_hw_start (dev);
- netif_device_attach (dev);
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-
-static struct pci_driver rtl8139_pci_driver = {
- .name = DRV_NAME,
- .id_table = rtl8139_pci_tbl,
- .probe = rtl8139_init_one,
- .remove = __devexit_p(rtl8139_remove_one),
-#ifdef CONFIG_PM
- .suspend = rtl8139_suspend,
- .resume = rtl8139_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init rtl8139_init_module (void)
-{
- /* when we're a module, we always print a version message,
- * even if no 8139 board is found.
- */
-#ifdef MODULE
- printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
-#endif
-
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- printk(KERN_INFO "Initializing RTL8139-EtherCAT module. %s\n", COMPILE_INFO);
-
- EtherCAT_device_init(&rtl_ecat_dev);
- rtl_ecat_dev.isr = rtl8139_interrupt;
- rtl_ecat_dev.module = THIS_MODULE;
-
- if (pci_module_init(&rtl8139_pci_driver) < 0)
- {
- printk(KERN_ERR "Could not init PCI module.\n");
- return -1;
- }
-
- printk(KERN_INFO "EtherCAT device index is %i.\n", ec_device_index);
-
- if (rtl_ecat_dev.dev)
- {
- printk(KERN_INFO "Registering EtherCAT device...\n");
- if (EtherCAT_register_device(ec_device_master_index, &rtl_ecat_dev) < 0)
- {
- printk(KERN_ERR "Could not register device.\n");
- goto out_module;
- }
-
- rtl_ecat_dev_registered = 1;
-
- printk(KERN_INFO "EtherCAT device registered and opened.\n");
- }
- else
- {
- printk(KERN_WARNING "NO EtherCAT device registered!\n");
- }
-
- return 0;
-
- out_module:
-
- pci_unregister_driver(&rtl8139_pci_driver);
- return -1;
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-}
-
-
-static void __exit rtl8139_cleanup_module (void)
-{
- /* EtherCAT >>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
- printk(KERN_INFO "Cleaning up RTL8139-EtherCAT module...\n");
-
- if (rtl_ecat_dev_registered && rtl_ecat_dev.dev)
- {
- printk(KERN_INFO "Unregistering RTL8139-EtherCAT device...\n");
- EtherCAT_unregister_device(ec_device_master_index, &rtl_ecat_dev);
- }
-
- pci_unregister_driver(&rtl8139_pci_driver);
- EtherCAT_device_clear(&rtl_ecat_dev);
-
- printk(KERN_INFO "RTL8139-EtherCAT module cleaned up.\n");
-
- /* EtherCAT <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
-}
-
-
-module_init(rtl8139_init_module);
-module_exit(rtl8139_cleanup_module);
--- a/drivers/EtherCAT.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/******************************************************************************
- *
- * E t h e r C A T . h
- *
- * Header zur Nutzung der EtherCAT-Funktionen.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include "../drivers/ec_master.h"
-#include "../drivers/ec_device.h"
-#include "../drivers/ec_types.h"
-#include "../drivers/ec_module.h"
-
-/*****************************************************************************/
-
--- a/drivers/Makefile Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-#------------------------------------------------------------------------------
-#
-# Makefile
-#
-# IgH EtherCAT-Treiber
-#
-# $Id$
-#
-#------------------------------------------------------------------------------
-
-ifneq ($(KERNELRELEASE),)
-
-#------------------------------------------------------------------------------
-# Kbuild-Abschnitt
-
-obj-m := 8139too-ecat.o ecat-master.o
-
-8139too-ecat-objs := 8139too.o
-
-ecat-master-objs := ec_module.o ec_master.o ec_device.o ec_slave.o \
- ec_command.o ec_types.o ec_domain.o
-
-REV = `svnversion $(src)`
-DATE = `date`
-
-EXTRA_CFLAGS = -DEC_REV="$(REV)" -DEC_USER="$(USER)" -DEC_DATE="$(DATE)"
-
-#------------------------------------------------------------------------------
-
-else
-
-#------------------------------------------------------------------------------
-# Default-Abschnitt
-
-ifneq ($(wildcard ethercat.conf),)
-include ethercat.conf
-else
-KERNELDIR = /lib/modules/`uname -r`/build
-endif
-
-modules:
- $(MAKE) -C $(KERNELDIR) M=`pwd` modules
-
-clean:
- $(MAKE) -C $(KERNELDIR) M=`pwd` clean
-
-#------------------------------------------------------------------------------
-
-endif
--- a/drivers/ec_command.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-/******************************************************************************
- *
- * e c _ c o m m a n d . c
- *
- * Methoden für ein EtherCAT-Kommando.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/slab.h>
-
-#include "ec_command.h"
-
-/*****************************************************************************/
-
-/**
- Kommando-Konstruktor.
-
- Initialisiert alle Variablen innerhalb des Kommandos auf die
- Default-Werte.
-
- @param cmd Zeiger auf das zu initialisierende Kommando.
-*/
-
-void EtherCAT_command_init(EtherCAT_command_t *cmd)
-{
- cmd->type = ECAT_CMD_NONE;
- cmd->address.logical = 0x00000000;
- cmd->data_length = 0;
- cmd->state = ECAT_CS_READY;
- cmd->index = 0;
- cmd->working_counter = 0;
-}
-
-/*****************************************************************************/
-
-/**
- Kommando-Destruktor.
-
- Setzt alle Attribute auf den Anfangswert zurueck.
-
- @param cmd Zeiger auf das zu initialisierende Kommando.
-*/
-
-void EtherCAT_command_clear(EtherCAT_command_t *cmd)
-{
- EtherCAT_command_init(cmd);
-}
-
-/*****************************************************************************/
-
-#define ECAT_FUNC_HEADER \
- EtherCAT_command_init(cmd)
-
-#define ECAT_FUNC_WRITE_FOOTER \
- cmd->data_length = length; \
- memcpy(cmd->data, data, length);
-
-#define ECAT_FUNC_READ_FOOTER \
- cmd->data_length = length;
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-NPRD-Kommando.
-
- @param cmd Zeiger auf das Kommando
- @param node_address Adresse des Knotens (Slaves)
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu lesenden Daten
-*/
-
-void EtherCAT_command_read(EtherCAT_command_t *cmd,
- unsigned short node_address,
- unsigned short offset,
- unsigned int length)
-{
- if (unlikely(node_address == 0x0000))
- printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n");
-
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_NPRD;
- cmd->address.phy.dev.node = node_address;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-NPWR-Kommando.
-
- Alloziert ein "node-adressed physical write"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param node_address Adresse des Knotens (Slaves)
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu schreibenden Daten
- @param data Zeiger auf Speicher mit zu schreibenden Daten
-*/
-
-void EtherCAT_command_write(EtherCAT_command_t *cmd,
- unsigned short node_address,
- unsigned short offset,
- unsigned int length,
- const unsigned char *data)
-{
- if (unlikely(node_address == 0x0000))
- printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n");
-
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_NPWR;
- cmd->address.phy.dev.node = node_address;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-APRD-Kommando.
-
- Alloziert ein "autoincerement physical read"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param ring_position (Negative) Position des Slaves im Bus
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu lesenden Daten
-*/
-
-void EtherCAT_command_position_read(EtherCAT_command_t *cmd,
- short ring_position,
- unsigned short offset,
- unsigned int length)
-{
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_APRD;
- cmd->address.phy.dev.pos = ring_position;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-APWR-Kommando.
-
- Alloziert ein "autoincrement physical write"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param ring_position (Negative) Position des Slaves im Bus
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu schreibenden Daten
- @param data Zeiger auf Speicher mit zu schreibenden Daten
-*/
-
-void EtherCAT_command_position_write(EtherCAT_command_t *cmd,
- short ring_position,
- unsigned short offset,
- unsigned int length,
- const unsigned char *data)
-{
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_APWR;
- cmd->address.phy.dev.pos = ring_position;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-BRD-Kommando.
-
- Alloziert ein "broadcast read"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu lesenden Daten
-*/
-
-void EtherCAT_command_broadcast_read(EtherCAT_command_t *cmd,
- unsigned short offset,
- unsigned int length)
-{
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_BRD;
- cmd->address.phy.dev.node = 0x0000;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_READ_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-BWR-Kommando.
-
- Alloziert ein "broadcast write"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param offset Physikalische Speicheradresse im Slave
- @param length Länge der zu schreibenden Daten
- @param data Zeiger auf Speicher mit zu schreibenden Daten
-*/
-
-void EtherCAT_command_broadcast_write(EtherCAT_command_t *cmd,
- unsigned short offset,
- unsigned int length,
- const unsigned char *data)
-{
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_BWR;
- cmd->address.phy.dev.node = 0x0000;
- cmd->address.phy.mem = offset;
-
- ECAT_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
-
-/**
- Initialisiert ein EtherCAT-LRW-Kommando.
-
- Alloziert ein "logical read write"-Kommando
- und fügt es in die Liste des Masters ein.
-
- @param cmd Zeiger auf das Kommando
- @param offset Logische Speicheradresse
- @param length Länge der zu lesenden/schreibenden Daten
- @param data Zeiger auf Speicher mit zu lesenden/schreibenden Daten
-*/
-
-void EtherCAT_command_logical_read_write(EtherCAT_command_t *cmd,
- unsigned int offset,
- unsigned int length,
- unsigned char *data)
-{
- ECAT_FUNC_HEADER;
-
- cmd->type = ECAT_CMD_LRW;
- cmd->address.logical = offset;
-
- ECAT_FUNC_WRITE_FOOTER;
-}
-
-/*****************************************************************************/
--- a/drivers/ec_command.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/******************************************************************************
- *
- * e c _ c o m m a n d . h
- *
- * Struktur für ein EtherCAT-Kommando.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_COMMAND_H_
-#define _EC_COMMAND_H_
-
-#include "ec_globals.h"
-
-/*****************************************************************************/
-
-/**
- Status eines EtherCAT-Kommandos.
-*/
-
-typedef enum
-{
- ECAT_CS_READY, ECAT_CS_SENT, ECAT_CS_RECEIVED
-}
-EtherCAT_command_state_t;
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Adresse.
-
- Im EtherCAT-Rahmen sind 4 Bytes für die Adresse reserviert, die
- ja nach Kommandoty eine andere bedeutung haben: Bei Autoinkrement-
- befehlen sind die ersten zwei Bytes die (negative)
- Autoinkrement-Adresse, bei Knoten-adressierten Befehlen entsprechen
- sie der Knotenadresse. Das dritte und vierte Byte entspricht in
- diesen Fällen der physikalischen Speicheradresse auf dem Slave.
- Bei einer logischen Adressierung entsprechen alle vier Bytes
- der logischen Adresse.
-*/
-
-typedef union
-{
- struct
- {
- union
- {
- short pos; /**< (Negative) Ring-Position des Slaves */
- unsigned short node; /**< Konfigurierte Knotenadresse */
- }
- dev;
-
- unsigned short mem; /**< Physikalische Speicheradresse im Slave */
- }
- phy;
-
- unsigned long logical; /**< Logische Adresse */
- unsigned char raw[4]; /**< Rohdaten für die Generierung des Frames */
-}
-EtherCAT_address_t;
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Kommando.
-*/
-
-typedef struct EtherCAT_command
-{
- EtherCAT_cmd_type_t type; /**< Typ des Kommandos (APRD, NPWR, etc...) */
- EtherCAT_address_t address; /**< Adresse des/der Empfänger */
- unsigned int data_length; /**< Länge der zu sendenden und/oder
- empfangenen Daten */
-
- EtherCAT_command_state_t state; /**< Zustand des Kommandos
- (bereit, gesendet, etc...) */
- unsigned char index; /**< Kommando-Index, mit der das Kommando gesendet
- wurde (wird vom Master beim Senden gesetzt. */
- unsigned int working_counter; /**< Working-Counter bei Empfang (wird
- vom Master gesetzt) */
-
- unsigned char data[ECAT_FRAME_BUFFER_SIZE]; /**< Kommandodaten */
-}
-EtherCAT_command_t;
-
-/*****************************************************************************/
-
-void EtherCAT_command_init(EtherCAT_command_t *);
-void EtherCAT_command_clear(EtherCAT_command_t *);
-
-void EtherCAT_command_read(EtherCAT_command_t *,
- unsigned short,
- unsigned short,
- unsigned int);
-void EtherCAT_command_write(EtherCAT_command_t *,
- unsigned short,
- unsigned short,
- unsigned int,
- const unsigned char *);
-void EtherCAT_command_position_read(EtherCAT_command_t *,
- short,
- unsigned short,
- unsigned int);
-void EtherCAT_command_position_write(EtherCAT_command_t *,
- short,
- unsigned short,
- unsigned int,
- const unsigned char *);
-void EtherCAT_command_broadcast_read(EtherCAT_command_t *,
- unsigned short,
- unsigned int);
-void EtherCAT_command_broadcast_write(EtherCAT_command_t *,
- unsigned short,
- unsigned int,
- const unsigned char *);
-void EtherCAT_command_logical_read_write(EtherCAT_command_t *,
- unsigned int,
- unsigned int,
- unsigned char *);
-
-/*****************************************************************************/
-
-#endif
--- a/drivers/ec_device.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-/******************************************************************************
- *
- * e c _ d e v i c e . c
- *
- * Methoden für ein EtherCAT-Gerät.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-
-#include "ec_device.h"
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Geräte-Konstuktor.
-
- Initialisiert ein EtherCAT-Gerät, indem es die Variablen
- in der Struktur auf die Default-Werte setzt.
-
- @param ecd Zu initialisierendes EtherCAT-Gerät
-*/
-
-void EtherCAT_device_init(EtherCAT_device_t *ecd)
-{
- ecd->dev = NULL;
- ecd->tx_skb = NULL;
- ecd->rx_skb = NULL;
- ecd->tx_time = 0;
- ecd->rx_time = 0;
- ecd->tx_intr_cnt = 0;
- ecd->rx_intr_cnt = 0;
- ecd->intr_cnt = 0;
- ecd->state = ECAT_DS_READY;
- ecd->rx_data_length = 0;
- ecd->isr = NULL;
- ecd->module = NULL;
- ecd->error_reported = 0;
-}
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Geräte-Destuktor.
-
- Gibt den dynamisch allozierten Speicher des
- EtherCAT-Gerätes (die beiden Socket-Buffer) wieder frei.
-
- @param ecd EtherCAT-Gerät
-*/
-
-void EtherCAT_device_clear(EtherCAT_device_t *ecd)
-{
- ecd->dev = NULL;
-
- if (ecd->tx_skb) {
- dev_kfree_skb(ecd->tx_skb);
- ecd->tx_skb = NULL;
- }
-
- if (ecd->rx_skb) {
- dev_kfree_skb(ecd->rx_skb);
- ecd->rx_skb = NULL;
- }
-}
-
-/*****************************************************************************/
-
-/**
- Weist einem EtherCAT-Gerät das entsprechende net_device zu.
-
- Prüft das net_device, allokiert Socket-Buffer in Sende- und
- Empfangsrichtung und weist dem EtherCAT-Gerät und den
- Socket-Buffern das net_device zu.
-
- @param ecd EtherCAT-Device
- @param dev net_device
-
- @return 0: Erfolg, < 0: Konnte Socket-Buffer nicht allozieren.
-*/
-
-int EtherCAT_device_assign(EtherCAT_device_t *ecd,
- struct net_device *dev)
-{
- if (!dev) {
- printk("EtherCAT: Device is NULL!\n");
- return -1;
- }
-
- if ((ecd->tx_skb = dev_alloc_skb(ECAT_FRAME_BUFFER_SIZE)) == NULL) {
- printk(KERN_ERR "EtherCAT: Could not allocate device tx socket buffer!\n");
- return -1;
- }
-
- if ((ecd->rx_skb = dev_alloc_skb(ECAT_FRAME_BUFFER_SIZE)) == NULL) {
- dev_kfree_skb(ecd->tx_skb);
- ecd->tx_skb = NULL;
- printk(KERN_ERR "EtherCAT: Could not allocate device rx socket buffer!\n");
- return -1;
- }
-
- ecd->dev = dev;
- ecd->tx_skb->dev = dev;
- ecd->rx_skb->dev = dev;
-
- printk("EtherCAT: Assigned Device %X.\n", (unsigned) dev);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Führt die open()-Funktion des Netzwerktreibers aus.
-
- Dies entspricht einem "ifconfig up". Vorher wird der Zeiger
- auf das EtherCAT-Gerät auf Gültigkeit geprüft und der
- Gerätezustand zurückgesetzt.
-
- @param ecd EtherCAT-Gerät
-
- @return 0 bei Erfolg, < 0: Ungültiger Zeiger, oder open()
- fehlgeschlagen
-*/
-
-int EtherCAT_device_open(EtherCAT_device_t *ecd)
-{
- unsigned int i;
-
- if (!ecd) {
- printk(KERN_ERR "EtherCAT: Trying to open a NULL device!\n");
- return -1;
- }
-
- if (!ecd->dev) {
- printk(KERN_ERR "EtherCAT: No net_device to open!\n");
- return -1;
- }
-
- // Device could have received frames before
- for (i = 0; i < 4; i++) EtherCAT_device_call_isr(ecd);
-
- // Reset old device state
- ecd->state = ECAT_DS_READY;
- ecd->tx_intr_cnt = 0;
- ecd->rx_intr_cnt = 0;
-
- return ecd->dev->open(ecd->dev);
-}
-
-/*****************************************************************************/
-
-/**
- Führt die stop()-Funktion des net_devices aus.
-
- @param ecd EtherCAT-Gerät
-
- @return 0 bei Erfolg, < 0: Kein Gerät zum Schliessen
-*/
-
-int EtherCAT_device_close(EtherCAT_device_t *ecd)
-{
- if (!ecd->dev) {
- printk("EtherCAT: No device to close!\n");
- return -1;
- }
-
- printk("EtherCAT: Stopping device (txcnt: %u, rxcnt: %u)\n",
- (unsigned int) ecd->tx_intr_cnt,
- (unsigned int) ecd->rx_intr_cnt);
-
- return ecd->dev->stop(ecd->dev);
-}
-
-/*****************************************************************************/
-
-/**
- Sendet einen Rahmen über das EtherCAT-Gerät.
-
- Kopiert die zu sendenden Daten in den statischen Socket-
- Buffer, fügt den Ethernat-II-Header hinzu und ruft die
- start_xmit()-Funktion der Netzwerkkarte auf.
-
- @param ecd EtherCAT-Gerät
- @param data Zeiger auf die zu sendenden Daten
- @param length Länge der zu sendenden Daten
-
- @return 0 bei Erfolg, < 0: Vorheriger Rahmen noch
- nicht empfangen, oder kein Speicher mehr vorhanden
-*/
-
-int EtherCAT_device_send(EtherCAT_device_t *ecd,
- unsigned char *data,
- unsigned int length)
-{
- unsigned char *frame_data;
- struct ethhdr *eth;
-
- if (unlikely(ecd->state == ECAT_DS_SENT)) {
- printk(KERN_WARNING "EtherCAT: Warning - Trying to send frame"
- " while last was not received!\n");
- }
-
- // Clear transmit socket buffer and reserve
- // space for Ethernet-II header
- skb_trim(ecd->tx_skb, 0);
- skb_reserve(ecd->tx_skb, ETH_HLEN);
-
- // Copy data to socket buffer
- frame_data = skb_put(ecd->tx_skb, length);
- memcpy(frame_data, data, length);
-
- // Add Ethernet-II-Header
- if (unlikely((eth = (struct ethhdr *)
- skb_push(ecd->tx_skb, ETH_HLEN)) == NULL)) {
- printk(KERN_ERR "EtherCAT: device_send -"
- " Could not allocate Ethernet-II header!\n");
- return -1;
- }
-
- // Protocol type
- eth->h_proto = htons(0x88A4);
- // Hardware address
- memcpy(eth->h_source, ecd->dev->dev_addr, ecd->dev->addr_len);
- // Broadcast address
- memset(eth->h_dest, 0xFF, ecd->dev->addr_len);
-
- rdtscl(ecd->tx_time); // Get CPU cycles
-
- // Start sending of frame
- ecd->state = ECAT_DS_SENT;
- ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->dev);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Holt einen empfangenen Rahmen von der Netzwerkkarte.
-
- Zuerst wird geprüft, ob überhaupt ein Rahmen empfangen
- wurde. Wenn ja, wird dieser in den angegebenen
- Speicherbereich kopiert.
-
- @param ecd EtherCAT-Gerät
- @param data Zeiger auf den Speicherbereich, in den die
- empfangenen Daten kopiert werden sollen
-
- @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_device_receive(EtherCAT_device_t *ecd,
- unsigned char *data)
-{
- if (unlikely(ecd->state != ECAT_DS_RECEIVED)) {
- if (likely(ecd->error_reported)) {
- printk(KERN_ERR "EtherCAT: receive - Nothing received!\n");
- ecd->error_reported = 1;
- }
- return -1;
- }
-
- if (unlikely(ecd->rx_data_length > ECAT_FRAME_BUFFER_SIZE)) {
- if (likely(ecd->error_reported)) {
- printk(KERN_ERR "EtherCAT: receive - "
- " Reveived frame is too long (%i Bytes)!\n",
- ecd->rx_data_length);
- ecd->error_reported = 1;
- }
- return -1;
- }
-
- if (unlikely(ecd->error_reported)) {
- ecd->error_reported = 0;
- }
-
- memcpy(data, ecd->rx_data, ecd->rx_data_length);
-
- return ecd->rx_data_length;
-}
-
-/*****************************************************************************/
-
-/**
- Ruft die Interrupt-Routine der Netzwerkkarte auf.
-
- @param ecd EtherCAT-Gerät
-
- @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
-*/
-
-void EtherCAT_device_call_isr(EtherCAT_device_t *ecd)
-{
- if (likely(ecd->isr)) ecd->isr(0, ecd->dev, NULL);
-}
-
-/*****************************************************************************/
-
-/**
- Gibt alle Informationen über das Device-Objekt aus.
-
- @param ecd EtherCAT-Gerät
-*/
-
-void EtherCAT_device_debug(EtherCAT_device_t *ecd)
-{
- printk(KERN_DEBUG "---EtherCAT device information begin---\n");
-
- if (ecd)
- {
- printk(KERN_DEBUG "Assigned net_device: %X\n",
- (unsigned) ecd->dev);
- printk(KERN_DEBUG "Transmit socket buffer: %X\n",
- (unsigned) ecd->tx_skb);
- printk(KERN_DEBUG "Receive socket buffer: %X\n",
- (unsigned) ecd->rx_skb);
- printk(KERN_DEBUG "Time of last transmission: %u\n",
- (unsigned) ecd->tx_time);
- printk(KERN_DEBUG "Time of last receive: %u\n",
- (unsigned) ecd->rx_time);
- printk(KERN_DEBUG "Number of transmit interrupts: %u\n",
- (unsigned) ecd->tx_intr_cnt);
- printk(KERN_DEBUG "Number of receive interrupts: %u\n",
- (unsigned) ecd->rx_intr_cnt);
- printk(KERN_DEBUG "Total Number of interrupts: %u\n",
- (unsigned) ecd->intr_cnt);
- printk(KERN_DEBUG "Actual device state: %i\n",
- (int) ecd->state);
- printk(KERN_DEBUG "Receive buffer: %X\n",
- (unsigned) ecd->rx_data);
- printk(KERN_DEBUG "Receive buffer fill state: %u/%u\n",
- (unsigned) ecd->rx_data_length, ECAT_FRAME_BUFFER_SIZE);
- }
- else
- {
- printk(KERN_DEBUG "Device is NULL!\n");
- }
-
- printk(KERN_DEBUG "---EtherCAT device information end---\n");
-}
-
-/*****************************************************************************/
-
-EXPORT_SYMBOL(EtherCAT_device_init);
-EXPORT_SYMBOL(EtherCAT_device_clear);
-EXPORT_SYMBOL(EtherCAT_device_assign);
-EXPORT_SYMBOL(EtherCAT_device_open);
-EXPORT_SYMBOL(EtherCAT_device_close);
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_device.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/******************************************************************************
- *
- * e c _ d e v i c e . h
- *
- * Struktur für ein EtherCAT-Gerät.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_DEVICE_H_
-#define _EC_DEVICE_H_
-
-#include <linux/interrupt.h>
-
-#include "ec_globals.h"
-
-/*****************************************************************************/
-
-/**
- Zustand eines EtherCAT-Gerätes.
-
- Eine Für EtherCAT reservierte Netzwerkkarte kann bestimmte Zustände haben.
-*/
-
-typedef enum
-{
- ECAT_DS_READY, /**< Das Gerät ist bereit zum Senden */
- ECAT_DS_SENT, /**< Das Gerät hat einen Rahmen abgesendet,
- aber noch keine Antwort enpfangen */
- ECAT_DS_RECEIVED, /**< Das Gerät hat eine Antwort auf einen
- zuvor gesendeten Rahmen empfangen */
- ECAT_DS_TIMEOUT, /**< Nach dem Senden eines Rahmens meldete
- das Gerät einen Timeout */
- ECAT_DS_ERROR /**< Nach dem Senden eines frames hat das
- Gerät einen Fehler festgestellt. */
-}
-EtherCAT_device_state_t;
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Gerät.
-
- Ein EtherCAT-Gerät ist eine Netzwerkkarte, die vom
- EtherCAT-Master dazu verwendet wird, um Frames zu senden
- und zu empfangen.
-*/
-
-typedef struct
-{
- struct net_device *dev; /**< Zeiger auf das reservierte net_device */
- struct sk_buff *tx_skb; /**< Zeiger auf Transmit-Socketbuffer */
- struct sk_buff *rx_skb; /**< Zeiger auf Receive-Socketbuffer */
- unsigned long tx_time; /**< Zeit des letzten Sendens */
- unsigned long rx_time; /**< Zeit des letzten Empfangs */
- unsigned long tx_intr_cnt; /**< Anzahl Tx-Interrupts */
- unsigned long rx_intr_cnt; /**< Anzahl Rx-Interrupts */
- unsigned long intr_cnt; /**< Anzahl Interrupts */
- volatile EtherCAT_device_state_t state; /**< Gesendet, Empfangen,
- Timeout, etc. */
- unsigned char rx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Puffer für
- empfangene Rahmen */
- volatile unsigned int rx_data_length; /**< Länge des zuletzt
- empfangenen Rahmens */
- irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */
- struct module *module; /**< Zeiger auf das Modul, das das Gerät zur
- Verfügung stellt. */
- int error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code
- bereits gemeldet wurde. */
-}
-EtherCAT_device_t;
-
-/*****************************************************************************/
-
-void EtherCAT_device_init(EtherCAT_device_t *);
-int EtherCAT_device_assign(EtherCAT_device_t *, struct net_device *);
-void EtherCAT_device_clear(EtherCAT_device_t *);
-
-int EtherCAT_device_open(EtherCAT_device_t *);
-int EtherCAT_device_close(EtherCAT_device_t *);
-
-int EtherCAT_device_send(EtherCAT_device_t *, unsigned char *, unsigned int);
-int EtherCAT_device_receive(EtherCAT_device_t *, unsigned char *);
-void EtherCAT_device_call_isr(EtherCAT_device_t *);
-
-void EtherCAT_device_debug(EtherCAT_device_t *);
-
-/*****************************************************************************/
-
-#endif
--- a/drivers/ec_domain.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/******************************************************************************
- *
- * e c _ d o m a i n . c
- *
- * Methoden für Gruppen von EtherCAT-Slaves.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-
-#include "ec_globals.h"
-#include "ec_domain.h"
-
-/*****************************************************************************/
-
-/**
- Konstruktor einer EtherCAT-Domäne.
-
- @param pd Zeiger auf die zu initialisierende Domäne
-*/
-
-void EtherCAT_domain_init(EtherCAT_domain_t *dom)
-{
- dom->number = 0;
- dom->data_size = 0;
- dom->logical_offset = 0;
- dom->response_count = 0;
-
- memset(dom->data, 0x00, ECAT_FRAME_BUFFER_SIZE);
-}
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_domain.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/******************************************************************************
- *
- * e c _ d o m a i n . h
- *
- * Struktur für eine Gruppe von EtherCAT-Slaves.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_DOMAIN_H_
-#define _EC_DOMAIN_H_
-
-#include "ec_globals.h"
-#include "ec_slave.h"
-#include "ec_command.h"
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Domäne
-
- Verwaltet die Prozessdaten und das hierfür nötige Kommando einer bestimmten
- Menge von Slaves.
-*/
-
-typedef struct EtherCAT_domain
-{
- unsigned int number; /*<< Domänen-Identifikation */
- EtherCAT_command_t command; /**< Kommando zum Senden und Empfangen der
- Prozessdaten */
- unsigned char data[ECAT_FRAME_BUFFER_SIZE]; /**< Prozessdaten-Array */
- unsigned int data_size; /**< Größe der Prozessdaten */
- unsigned int logical_offset; /**< Logische Basisaddresse */
- unsigned int response_count; /**< Anzahl antwortender Slaves */
-}
-EtherCAT_domain_t;
-
-/*****************************************************************************/
-
-void EtherCAT_domain_init(EtherCAT_domain_t *);
-
-/*****************************************************************************/
-
-#endif
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_globals.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/******************************************************************************
- *
- * e c _ g l o b a l s . h
- *
- * Globale Definitionen und Makros für das EtherCAT-Protokoll.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_GLOBALS_
-#define _EC_GLOBALS_
-
-/*****************************************************************************/
-
-/**
- Maximale Größe eines EtherCAT-Frames
-*/
-#define ECAT_FRAME_BUFFER_SIZE 1500
-
-/**
- Maximale Anzahl der Prozessdatendomänen in einem Master
-*/
-#define ECAT_MAX_DOMAINS 10
-
-/**
- NULL-Define, falls noch nicht definiert.
-*/
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Kommando-Typ
-*/
-
-typedef enum
-{
- ECAT_CMD_NONE = 0x00, /**< Dummy */
- ECAT_CMD_APRD = 0x01, /**< Auto-increment physical read */
- ECAT_CMD_APWR = 0x02, /**< Auto-increment physical write */
- ECAT_CMD_NPRD = 0x04, /**< Node-addressed physical read */
- ECAT_CMD_NPWR = 0x05, /**< Node-addressed physical write */
- ECAT_CMD_BRD = 0x07, /**< Broadcast read */
- ECAT_CMD_BWR = 0x08, /**< Broadcast write */
- ECAT_CMD_LRW = 0x0C /**< Logical read/write */
-}
-EtherCAT_cmd_type_t;
-
-/*****************************************************************************/
-
-/**
- Zustand eines EtherCAT-Slaves
-*/
-
-typedef enum
-{
- ECAT_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
- ECAT_STATE_INIT = 0x01, /**< Init-Zustand (Keine Mailbox-
- Kommunikation, Kein I/O) */
- ECAT_STATE_PREOP = 0x02, /**< Pre-Operational (Mailbox-
- Kommunikation, Kein I/O) */
- ECAT_STATE_SAVEOP = 0x04, /**< Save-Operational (Mailbox-
- Kommunikation und Input Update) */
- ECAT_STATE_OP = 0x08, /**< Operational, (Mailbox-
- Kommunikation und Input/Output Update) */
- ECAT_ACK_STATE = 0x10 /**< Acknoledge-Bit beim Zustandswechsel
- (dies ist kein eigener Zustand) */
-}
-EtherCAT_state_t;
-
-/*****************************************************************************/
-
-typedef struct EtherCAT_master EtherCAT_master_t;
-
-/*****************************************************************************/
-
-#endif
--- a/drivers/ec_master.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1126 +0,0 @@
-/******************************************************************************
- *
- * e c _ m a s t e r . c
- *
- * Methoden für einen EtherCAT-Master.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-
-#include "ec_globals.h"
-#include "ec_master.h"
-
-/*****************************************************************************/
-
-/**
- Konstruktor des EtherCAT-Masters.
-
- @param master Zeiger auf den zu initialisierenden EtherCAT-Master
-*/
-
-void EtherCAT_master_init(EtherCAT_master_t *master)
-{
- master->bus_slaves = NULL;
- master->bus_slaves_count = 0;
- master->dev = NULL;
- master->command_index = 0x00;
- master->tx_data_length = 0;
- master->rx_data_length = 0;
- master->domain_count = 0;
- master->debug_level = 0;
- master->bus_time = 0;
- master->frames_lost = 0;
- master->t_lost_output = 0;
-}
-
-/*****************************************************************************/
-
-/**
- Destruktor eines EtherCAT-Masters.
-
- Entfernt alle Kommandos aus der Liste, löscht den Zeiger
- auf das Slave-Array und gibt die Prozessdaten frei.
-
- @param master Zeiger auf den zu löschenden Master
-*/
-
-void EtherCAT_master_clear(EtherCAT_master_t *master)
-{
- if (master->bus_slaves) {
- kfree(master->bus_slaves);
- master->bus_slaves = NULL;
- }
-
- master->domain_count = 0;
-}
-
-/*****************************************************************************/
-
-/**
- Öffnet ein EtherCAT-Geraet für den Master.
-
- Registriert das Geraet beim Master, der es daraufhin oeffnet.
-
- @param master Der EtherCAT-Master
- @param device Das EtherCAT-Geraet
- @return 0, wenn alles o.k.,
- < 0, wenn bereits ein Geraet registriert
- oder das Geraet nicht geoeffnet werden konnte.
-*/
-
-int EtherCAT_master_open(EtherCAT_master_t *master,
- EtherCAT_device_t *device)
-{
- if (!master || !device) {
- printk(KERN_ERR "EtherCAT: Illegal parameters for master_open()!\n");
- return -1;
- }
-
- if (master->dev) {
- printk(KERN_ERR "EtherCAT: Master already has a device.\n");
- return -1;
- }
-
- if (EtherCAT_device_open(device) < 0) {
- printk(KERN_ERR "EtherCAT: Could not open device %X!\n",
- (unsigned int) master->dev);
- return -1;
- }
-
- master->dev = device;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Schliesst das EtherCAT-Geraet, auf dem der Master arbeitet.
-
- @param master Der EtherCAT-Master
- @param device Das EtherCAT-Geraet
-*/
-
-void EtherCAT_master_close(EtherCAT_master_t *master,
- EtherCAT_device_t *device)
-{
- if (master->dev != device) {
- printk(KERN_WARNING "EtherCAT: Warning -"
- " Trying to close an unknown device!\n");
- return;
- }
-
- if (EtherCAT_device_close(master->dev) < 0) {
- printk(KERN_WARNING "EtherCAT: Warning -"
- " Could not close device!\n");
- }
-
- master->dev = NULL;
-}
-
-/*****************************************************************************/
-
-/**
- Sendet ein einzelnes Kommando in einem Frame und
- wartet auf dessen Empfang.
-
- @param master EtherCAT-Master
- @param cmd Kommando zum Senden/Empfangen
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_simple_send_receive(EtherCAT_master_t *master,
- EtherCAT_command_t *cmd)
-{
- unsigned int tries_left;
-
- if (unlikely(EtherCAT_simple_send(master, cmd) < 0))
- return -1;
-
- udelay(3);
-
- EtherCAT_device_call_isr(master->dev);
-
- tries_left = 20;
- while (unlikely(master->dev->state == ECAT_DS_SENT
- && tries_left)) {
- udelay(1);
- EtherCAT_device_call_isr(master->dev);
- tries_left--;
- }
-
- if (unlikely(EtherCAT_simple_receive(master, cmd) < 0))
- return -1;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Sendet ein einzelnes Kommando in einem Frame.
-
- @param master EtherCAT-Master
- @param cmd Kommando zum Senden
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_simple_send(EtherCAT_master_t *master,
- EtherCAT_command_t *cmd)
-{
- unsigned int length, framelength, i;
-
- if (unlikely(master->debug_level > 0)) {
- printk(KERN_DEBUG "EtherCAT_send_receive_command\n");
- }
-
- if (unlikely(cmd->state != ECAT_CS_READY)) {
- printk(KERN_WARNING "EtherCAT_send_receive_command:"
- "Command not in ready state!\n");
- }
-
- length = cmd->data_length + 12;
- framelength = length + 2;
-
- if (unlikely(framelength > ECAT_FRAME_BUFFER_SIZE)) {
- printk(KERN_ERR "EtherCAT: Frame too long (%i)!\n", framelength);
- return -1;
- }
-
- if (framelength < 46) framelength = 46;
-
- if (unlikely(master->debug_level > 0)) {
- printk(KERN_DEBUG "Frame length: %i\n", framelength);
- }
-
- master->tx_data[0] = length & 0xFF;
- master->tx_data[1] = ((length & 0x700) >> 8) | 0x10;
-
- cmd->index = master->command_index;
- master->command_index = (master->command_index + 1) % 0x0100;
-
- if (unlikely(master->debug_level > 0)) {
- printk(KERN_DEBUG "Sending command index %i\n", cmd->index);
- }
-
- cmd->state = ECAT_CS_SENT;
-
- master->tx_data[2 + 0] = cmd->type;
- master->tx_data[2 + 1] = cmd->index;
- master->tx_data[2 + 2] = cmd->address.raw[0];
- master->tx_data[2 + 3] = cmd->address.raw[1];
- master->tx_data[2 + 4] = cmd->address.raw[2];
- master->tx_data[2 + 5] = cmd->address.raw[3];
- master->tx_data[2 + 6] = cmd->data_length & 0xFF;
- master->tx_data[2 + 7] = (cmd->data_length & 0x700) >> 8;
- master->tx_data[2 + 8] = 0x00;
- master->tx_data[2 + 9] = 0x00;
-
- if (likely(cmd->type == ECAT_CMD_APWR
- || cmd->type == ECAT_CMD_NPWR
- || cmd->type == ECAT_CMD_BWR
- || cmd->type == ECAT_CMD_LRW)) // Write commands
- {
- for (i = 0; i < cmd->data_length; i++)
- master->tx_data[2 + 10 + i] = cmd->data[i];
- }
- else // Read commands
- {
- for (i = 0; i < cmd->data_length; i++) master->tx_data[2 + 10 + i] = 0x00;
- }
-
- master->tx_data[2 + 10 + cmd->data_length] = 0x00;
- master->tx_data[2 + 11 + cmd->data_length] = 0x00;
-
- // Pad with zeros
- for (i = cmd->data_length + 12 + 2; i < 46; i++) master->tx_data[i] = 0x00;
-
- master->tx_data_length = framelength;
-
- if (unlikely(master->debug_level > 0)) {
- printk(KERN_DEBUG "device send...\n");
- }
-
- // Send frame
- if (unlikely(EtherCAT_device_send(master->dev,
- master->tx_data,
- framelength) != 0)) {
- printk(KERN_ERR "EtherCAT: Could not send!\n");
- return -1;
- }
-
- if (unlikely(master->debug_level > 0)) {
- printk(KERN_DEBUG "EtherCAT_send done.\n");
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Wartet auf den Empfang eines einzeln gesendeten
- Kommandos.
-
- @param master EtherCAT-Master
- @param cmd Gesendetes Kommando
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_simple_receive(EtherCAT_master_t *master,
- EtherCAT_command_t *cmd)
-{
- unsigned int length;
- int ret;
- unsigned char command_type, command_index;
-
- if (unlikely((ret = EtherCAT_device_receive(master->dev,
- master->rx_data)) < 0))
- return -1;
-
- master->rx_data_length = (unsigned int) ret;
-
- if (unlikely(master->rx_data_length < 2)) {
- printk(KERN_ERR "EtherCAT: Received frame with incomplete EtherCAT"
- " header!\n");
- output_debug_data(master);
- return -1;
- }
-
- // Länge des gesamten Frames prüfen
- length = ((master->rx_data[1] & 0x07) << 8)
- | (master->rx_data[0] & 0xFF);
-
- if (unlikely(length > master->rx_data_length)) {
- printk(KERN_ERR "EtherCAT: Received corrupted frame (length does"
- " not match)!\n");
- output_debug_data(master);
- return -1;
- }
-
- command_type = master->rx_data[2];
- command_index = master->rx_data[2 + 1];
- length = (master->rx_data[2 + 6] & 0xFF)
- | ((master->rx_data[2 + 7] & 0x07) << 8);
-
- if (unlikely(master->rx_data_length - 2 < length + 12)) {
- printk(KERN_ERR "EtherCAT: Received frame with"
- " incomplete command data!\n");
- output_debug_data(master);
- return -1;
- }
-
- if (likely(cmd->state == ECAT_CS_SENT
- && cmd->type == command_type
- && cmd->index == command_index
- && cmd->data_length == length))
- {
- cmd->state = ECAT_CS_RECEIVED;
-
- // Empfangene Daten in Kommandodatenspeicher kopieren
- memcpy(cmd->data, master->rx_data + 2 + 10, length);
-
- // Working-Counter setzen
- cmd->working_counter
- = ((master->rx_data[length + 2 + 10] & 0xFF)
- | ((master->rx_data[length + 2 + 11] & 0xFF) << 8));
-
- if (unlikely(master->debug_level > 1)) {
- output_debug_data(master);
- }
- }
- else
- {
- printk(KERN_WARNING "EtherCAT: WARNING - Send/Receive anomaly!\n");
- output_debug_data(master);
- }
-
- master->dev->state = ECAT_DS_READY;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Durchsucht den Bus nach Slaves.
-
- @param master Der EtherCAT-Master
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_scan_for_slaves(EtherCAT_master_t *master)
-{
- EtherCAT_command_t cmd;
- EtherCAT_slave_t *cur;
- unsigned int i, j;
- unsigned char data[2];
-
- // Determine number of slaves on bus
-
- EtherCAT_command_broadcast_read(&cmd, 0x0000, 4);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- master->bus_slaves_count = cmd.working_counter;
- printk("EtherCAT: Found %i slaves on bus.\n", master->bus_slaves_count);
-
- if (!master->bus_slaves_count) return 0;
-
- if (!(master->bus_slaves =
- (EtherCAT_slave_t *) kmalloc(master->bus_slaves_count *
- sizeof(EtherCAT_slave_t), GFP_KERNEL))) {
- printk(KERN_ERR "EtherCAT: Could not allocate memory for bus slaves!\n");
- return -1;
- }
-
- // For every slave in the list
- for (i = 0; i < master->bus_slaves_count; i++)
- {
- cur = master->bus_slaves + i;
-
- EtherCAT_slave_init(cur);
-
- // Read base data
-
- EtherCAT_command_read(&cmd, cur->station_address, 0x0000, 4);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Slave %i did not respond"
- " while reading base data!\n", i);
- return -1;
- }
-
- // Get base data
-
- cur->type = cmd.data[0];
- cur->revision = cmd.data[1];
- cur->build = cmd.data[2] | (cmd.data[3] << 8);
-
- // Read identification from "Slave Information Interface" (SII)
-
- if (unlikely(EtherCAT_read_slave_information(master,
- cur->station_address,
- 0x0008,
- &cur->vendor_id) != 0))
- {
- printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n");
- return -1;
- }
-
- if (unlikely(EtherCAT_read_slave_information(master,
- cur->station_address,
- 0x000A,
- &cur->product_code) != 0))
- {
- printk(KERN_ERR "EtherCAT: Could not read SII product code!\n");
- return -1;
- }
-
- if (unlikely(EtherCAT_read_slave_information(master,
- cur->station_address,
- 0x000C,
- &cur->revision_number) != 0))
- {
- printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n");
- return -1;
- }
-
- if (unlikely(EtherCAT_read_slave_information(master,
- cur->station_address,
- 0x000E,
- &cur->serial_number) != 0))
- {
- printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n");
- return -1;
- }
-
- // Search for identification in "database"
-
- for (j = 0; j < slave_ident_count; j++)
- {
- if (unlikely(slave_idents[j].vendor_id == cur->vendor_id
- && slave_idents[j].product_code == cur->product_code))
- {
- cur->desc = slave_idents[j].desc;
- break;
- }
- }
-
- if (unlikely(!cur->desc)) {
- printk(KERN_ERR "EtherCAT: Unknown slave device (vendor %X, code %X) at "
- " position %i.\n", cur->vendor_id, cur->product_code, i);
- return -1;
- }
-
- // Set ring position
- cur->ring_position = -i;
- cur->station_address = i + 1;
-
- // Write station address
-
- data[0] = cur->station_address & 0x00FF;
- data[1] = (cur->station_address & 0xFF00) >> 8;
-
- EtherCAT_command_position_write(&cmd, cur->ring_position,
- 0x0010, 2, data);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Slave %i did not repond"
- " while writing station address!\n", i);
- return -1;
- }
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Registriert einen Slave beim Master.
-
- @param master Der EtherCAT-Master
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-void *EtherCAT_register_slave(EtherCAT_master_t *master,
- unsigned int bus_index,
- const char *vendor_name,
- const char *product_name,
- unsigned int domain)
-{
- EtherCAT_slave_t *slave;
- EtherCAT_domain_t *dom;
- unsigned int j;
-
- if (bus_index >= master->bus_slaves_count) {
- printk(KERN_ERR "EtherCAT: Illegal bus index! (%i / %i)\n", bus_index,
- master->bus_slaves_count);
- return NULL;
- }
-
- slave = master->bus_slaves + bus_index;
-
- if (slave->process_data) {
- printk(KERN_ERR "EtherCAT: Slave %i is already registered!\n", bus_index);
- return NULL;
- }
-
- if (strcmp(vendor_name, slave->desc->vendor_name) ||
- strcmp(product_name, slave->desc->product_name)) {
- printk(KERN_ERR "Invalid Slave Type! Requested: \"%s %s\", present: \"%s"
- "%s\".\n", vendor_name, product_name, slave->desc->vendor_name,
- slave->desc->product_name);
- return NULL;
- }
-
- // Check, if process data domain already exists...
- dom = NULL;
- for (j = 0; j < master->domain_count; j++) {
- if (domain == master->domains[j].number) {
- dom = master->domains + j;
- }
- }
-
- // Create process data domain
- if (!dom) {
- if (master->domain_count > ECAT_MAX_DOMAINS - 1) {
- printk(KERN_ERR "EtherCAT: Too many domains!\n");
- return NULL;
- }
-
- dom = master->domains + master->domain_count;
- EtherCAT_domain_init(dom);
- dom->number = domain;
- dom->logical_offset = master->domain_count * ECAT_FRAME_BUFFER_SIZE;
- master->domain_count++;
- }
-
- if (dom->data_size + slave->desc->process_data_size
- > ECAT_FRAME_BUFFER_SIZE - 14) {
- printk(KERN_ERR "EtherCAT: Oversized domain %i: %i / %i Bytes!\n",
- dom->number, dom->data_size + slave->desc->process_data_size,
- ECAT_FRAME_BUFFER_SIZE - 14);
- return NULL;
- }
-
- slave->process_data = dom->data + dom->data_size;
- dom->data_size += slave->desc->process_data_size;
-
- return slave->process_data;
-}
-
-/*****************************************************************************/
-
-/**
- Liest Daten aus dem Slave-Information-Interface
- eines EtherCAT-Slaves.
-
- @param master EtherCAT-Master
- @param node_address Knotenadresse des Slaves
- @param offset Adresse des zu lesenden SII-Registers
- @param target Zeiger auf einen 4 Byte großen Speicher
- zum Ablegen der Daten
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_read_slave_information(EtherCAT_master_t *master,
- unsigned short int node_address,
- unsigned short int offset,
- unsigned int *target)
-{
- EtherCAT_command_t cmd;
- unsigned char data[10];
- unsigned int tries_left;
-
- // Initiate read operation
-
- data[0] = 0x00;
- data[1] = 0x01;
- data[2] = offset & 0xFF;
- data[3] = (offset & 0xFF00) >> 8;
- data[4] = 0x00;
- data[5] = 0x00;
-
- EtherCAT_command_write(&cmd, node_address, 0x502, 6, data);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: SII-read - Slave %04X did not respond!\n",
- node_address);
- return -1;
- }
-
- // Der Slave legt die Informationen des Slave-Information-Interface
- // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
- // den Status auslesen, bis das Bit weg ist.
-
- tries_left = 100;
- while (likely(tries_left))
- {
- udelay(10);
-
- EtherCAT_command_read(&cmd, node_address, 0x502, 10);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) != 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: SII-read status -"
- " Slave %04X did not respond!\n", node_address);
- return -1;
- }
-
- if (likely((cmd.data[1] & 0x81) == 0)) {
- memcpy(target, cmd.data + 6, 4);
- break;
- }
-
- tries_left--;
- }
-
- if (unlikely(!tries_left)) {
- printk(KERN_WARNING "EtherCAT: SSI-read. Slave %04X timed out!\n",
- node_address);
- return -1;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Ändert den Zustand eines Slaves (asynchron).
-
- Führt eine (asynchrone) Zustandsänderung bei einem Slave durch.
-
- @param master EtherCAT-Master
- @param slave Slave, dessen Zustand geändert werden soll
- @param state_and_ack Neuer Zustand, evtl. mit gesetztem
- Acknowledge-Flag
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_state_change(EtherCAT_master_t *master,
- EtherCAT_slave_t *slave,
- unsigned char state_and_ack)
-{
- EtherCAT_command_t cmd;
- unsigned char data[2];
- unsigned int tries_left;
-
- data[0] = state_and_ack;
- data[1] = 0x00;
-
- EtherCAT_command_write(&cmd, slave->station_address,
- 0x0120, 2, data);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) != 0)) {
- printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to send!\n",
- state_and_ack);
- return -1;
- }
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Could not set state %02X - Device \"%s %s\""
- " (%d) did not respond!\n", state_and_ack, slave->desc->vendor_name,
- slave->desc->product_name, slave->ring_position * (-1));
- return -1;
- }
-
- slave->requested_state = state_and_ack & 0x0F;
-
- tries_left = 100;
- while (likely(tries_left))
- {
- udelay(10);
-
- EtherCAT_command_read(&cmd, slave->station_address, 0x0130, 2);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) != 0)) {
- printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to"
- " send!\n", state_and_ack);
- return -1;
- }
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Could not check state %02X - Device did not"
- " respond!\n", state_and_ack);
- return -1;
- }
-
- if (unlikely(cmd.data[0] & 0x10)) { // State change error
- printk(KERN_ERR "EtherCAT: Could not set state %02X - Device refused"
- " state change (code %02X)!\n", state_and_ack, cmd.data[0]);
- return -1;
- }
-
- if (likely(cmd.data[0] == (state_and_ack & 0x0F))) {
- // State change successful
- break;
- }
-
- tries_left--;
- }
-
- if (unlikely(!tries_left)) {
- printk(KERN_ERR "EtherCAT: Could not check state %02X - Timeout while"
- " checking!\n", state_and_ack);
- return -1;
- }
-
- slave->current_state = state_and_ack & 0x0F;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Konfiguriert einen Slave und setzt den Operational-Zustand.
-
- Führt eine komplette Konfiguration eines Slaves durch,
- setzt Sync-Manager und FMMU's, führt die entsprechenden
- Zustandsübergänge durch, bis der Slave betriebsbereit ist.
-
- @param master EtherCAT-Master
- @param slave Zu aktivierender Slave
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_activate_slave(EtherCAT_master_t *master,
- EtherCAT_slave_t *slave)
-{
- EtherCAT_command_t cmd;
- const EtherCAT_slave_desc_t *desc;
- unsigned char fmmu[16];
- unsigned char data[256];
-
- desc = slave->desc;
-
- if (unlikely(EtherCAT_state_change(master, slave, ECAT_STATE_INIT) != 0))
- return -1;
-
- // Resetting FMMU's
-
- memset(data, 0x00, 256);
-
- EtherCAT_command_write(&cmd, slave->station_address, 0x0600, 256, data);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Resetting FMMUs - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
-
- // Resetting Sync Manager channels
-
- if (desc->type != ECAT_ST_SIMPLE_NOSYNC)
- {
- memset(data, 0x00, 256);
-
- EtherCAT_command_write(&cmd, slave->station_address, 0x0800, 256, data);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Resetting SMs - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
- }
-
- // Init Mailbox communication
-
- if (desc->type == ECAT_ST_MAILBOX)
- {
- if (desc->sm0)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0800, 8,
- desc->sm0);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
- }
-
- if (desc->sm1)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0808, 8,
- desc->sm1);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM1 -"
- " Slave %04X did not respond!\n",
- slave->station_address);
- return -1;
- }
- }
- }
-
- // Change state to PREOP
-
- if (unlikely(EtherCAT_state_change(master, slave, ECAT_STATE_PREOP) != 0))
- return -1;
-
- // Set FMMU's
-
- if (desc->fmmu0)
- {
- if (unlikely(!slave->process_data)) {
- printk(KERN_ERR "EtherCAT: Warning - Slave %04X is not assigned to any"
- " process data object!\n", slave->station_address);
- return -1;
- }
-
- memcpy(fmmu, desc->fmmu0, 16);
-
- fmmu[0] = slave->logical_address & 0x000000FF;
- fmmu[1] = (slave->logical_address & 0x0000FF00) >> 8;
- fmmu[2] = (slave->logical_address & 0x00FF0000) >> 16;
- fmmu[3] = (slave->logical_address & 0xFF000000) >> 24;
-
- EtherCAT_command_write(&cmd, slave->station_address, 0x0600, 16, fmmu);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting FMMU0 - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
- }
-
- // Set Sync Managers
-
- if (desc->type != ECAT_ST_MAILBOX)
- {
- if (desc->sm0)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0800, 8,
- desc->sm0);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
- }
-
- if (desc->sm1)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0808, 8,
- desc->sm1);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM1 - Slave %04X did not"
- " respond!\n", slave->station_address);
- return -1;
- }
- }
- }
-
- if (desc->sm2)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0810, 8, desc->sm2);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM2 - Slave %04X did not respond!\n",
- slave->station_address);
- return -1;
- }
- }
-
- if (desc->sm3)
- {
- EtherCAT_command_write(&cmd, slave->station_address, 0x0818, 8, desc->sm3);
-
- if (unlikely(EtherCAT_simple_send_receive(master, &cmd) < 0))
- return -1;
-
- if (unlikely(cmd.working_counter != 1)) {
- printk(KERN_ERR "EtherCAT: Setting SM3 - Slave %04X did not respond!\n",
- slave->station_address);
- return -1;
- }
- }
-
- // Change state to SAVEOP
- if (unlikely(EtherCAT_state_change(master, slave, ECAT_STATE_SAVEOP) != 0))
- return -1;
-
- // Change state to OP
- if (unlikely(EtherCAT_state_change(master, slave, ECAT_STATE_OP) != 0))
- return -1;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Setzt einen Slave zurück in den Init-Zustand.
-
- @param master EtherCAT-Master
- @param slave Zu deaktivierender Slave
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_deactivate_slave(EtherCAT_master_t *master,
- EtherCAT_slave_t *slave)
-{
- if (unlikely(EtherCAT_state_change(master, slave,
- ECAT_STATE_INIT) != 0))
- return -1;
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Sendet und empfängt Prozessdaten der angegebenen Domäne
-
- @param master EtherCAT-Master
- domain Domäne
- timeout_us Timeout in Mikrosekunden
-
- @return 0 bei Erfolg, sonst < 0
-*/
-
-int EtherCAT_process_data_cycle(EtherCAT_master_t *master, unsigned int domain,
- unsigned int timeout_us)
-{
- unsigned int i;
- EtherCAT_domain_t *dom;
- unsigned long start_ticks, end_ticks, timeout_ticks;
-
- ecat_output_lost_frames(master); // Evtl. verlorene Frames ausgeben
-
- // Domäne bestimmen
- dom = NULL;
- for (i = 0; i < master->domain_count; i++) {
- if (master->domains[i].number == domain) {
- dom = master->domains + i;
- break;
- }
- }
-
- if (unlikely(!dom)) {
- printk(KERN_ERR "EtherCAT: No such domain: %i!\n", domain);
- return -1;
- }
-
- EtherCAT_command_logical_read_write(&dom->command,
- dom->logical_offset, dom->data_size,
- dom->data);
-
- rdtscl(start_ticks); // Sendezeit nehmen
-
- if (unlikely(EtherCAT_simple_send(master, &dom->command) < 0)) {
- printk(KERN_ERR "EtherCAT: Could not send process data command!\n");
- return -1;
- }
-
- timeout_ticks = timeout_us * cpu_khz / 1000;
-
- // Warten
- do {
- EtherCAT_device_call_isr(master->dev);
- rdtscl(end_ticks); // Empfangszeit nehmen
- }
- while (unlikely(master->dev->state == ECAT_DS_SENT
- && end_ticks - start_ticks < timeout_ticks));
-
- master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
-
- if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
- master->dev->state = ECAT_DS_READY;
- master->frames_lost++;
- ecat_output_lost_frames(master);
- return -1;
- }
-
- if (unlikely(EtherCAT_simple_receive(master, &dom->command) < 0)) {
- printk(KERN_ERR "EtherCAT: Could not receive cyclic command!\n");
- return -1;
- }
-
- if (unlikely(dom->command.state != ECAT_CS_RECEIVED)) {
- printk(KERN_WARNING "EtherCAT: Process data command not received!\n");
- return -1;
- }
-
- if (dom->command.working_counter != dom->response_count) {
- dom->response_count = dom->command.working_counter;
- printk(KERN_INFO "EtherCAT: Domain %i State change - %i slaves"
- " responding.\n", dom->number, dom->response_count);
- }
-
- // Daten vom Kommando in den Prozessdatenspeicher kopieren
- memcpy(dom->data, dom->command.data, dom->data_size);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Gibt Frame-Inhalte zwecks Debugging aus.
-
- @param master EtherCAT-Master
-*/
-
-void output_debug_data(const EtherCAT_master_t *master)
-{
- unsigned int i;
-
- printk(KERN_DEBUG "EtherCAT: tx_data content (%i Bytes):\n",
- master->tx_data_length);
-
- printk(KERN_DEBUG);
- for (i = 0; i < master->tx_data_length; i++)
- {
- printk("%02X ", master->tx_data[i]);
- if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG);
- }
- printk("\n");
-
- printk(KERN_DEBUG "EtherCAT: rx_data content (%i Bytes):\n",
- master->rx_data_length);
-
- printk(KERN_DEBUG);
- for (i = 0; i < master->rx_data_length; i++)
- {
- printk("%02X ", master->rx_data[i]);
- if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG);
- }
- printk("\n");
-}
-
-/*****************************************************************************/
-
-/**
- Gibt von Zeit zu Zeit die Anzahl verlorener Frames aus.
-
- @param master EtherCAT-Master
-*/
-
-void ecat_output_lost_frames(EtherCAT_master_t *master)
-{
- unsigned long int t;
-
- if (master->frames_lost) {
- rdtscl(t);
- if ((t - master->t_lost_output) / cpu_khz > 1000) {
- printk(KERN_ERR "EtherCAT: %u frame(s) LOST!\n", master->frames_lost);
- master->frames_lost = 0;
- master->t_lost_output = t;
- }
- }
-}
-
-/*****************************************************************************/
-
-EXPORT_SYMBOL(EtherCAT_master_open);
-EXPORT_SYMBOL(EtherCAT_master_close);
-EXPORT_SYMBOL(EtherCAT_activate_slave);
-EXPORT_SYMBOL(EtherCAT_deactivate_slave);
-EXPORT_SYMBOL(EtherCAT_process_data_cycle);
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_master.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/******************************************************************************
- *
- * e c _ m a s t e r . h
- *
- * Struktur für einen EtherCAT-Master.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_MASTER_H_
-#define _EC_MASTER_H_
-
-#include "ec_device.h"
-#include "ec_slave.h"
-#include "ec_command.h"
-#include "ec_domain.h"
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Master
-
- Verwaltet die EtherCAT-Slaves und kommuniziert mit
- dem zugewiesenen EtherCAT-Gerät.
-*/
-
-struct EtherCAT_master
-{
- EtherCAT_slave_t *bus_slaves; /**< Array von Slaves auf dem Bus */
- unsigned int bus_slaves_count; /**< Anzahl Slaves auf dem Bus */
- EtherCAT_device_t *dev; /**< Zeiger auf das zugewiesene EtherCAT-Gerät */
- unsigned char command_index; /**< Aktueller Kommando-Index */
- unsigned char tx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Statischer Speicher
- für zu sendende Daten */
- unsigned int tx_data_length; /**< Länge der Daten im Sendespeicher */
- unsigned char rx_data[ECAT_FRAME_BUFFER_SIZE]; /**< Statische Speicher für
- eine Kopie des Rx-Buffers
- im EtherCAT-Gerät */
- unsigned int rx_data_length; /**< Länge der Daten im Empfangsspeicher */
- EtherCAT_domain_t domains[ECAT_MAX_DOMAINS]; /** Prozessdatendomänen */
- unsigned int domain_count;
- int debug_level; /**< Debug-Level im Master-Code */
- unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */
- unsigned int frames_lost; /**< Anzahl verlorene Frames */
- unsigned long t_lost_output; /*<< Timer-Ticks bei der letzten Ausgabe von
- verlorenen Frames */
-};
-
-/*****************************************************************************/
-
-// Public methods
-
-void *EtherCAT_register_slave(EtherCAT_master_t *, unsigned int,
- const char *, const char *, unsigned int);
-int EtherCAT_activate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
-int EtherCAT_deactivate_slave(EtherCAT_master_t *, EtherCAT_slave_t *);
-int EtherCAT_process_data_cycle(EtherCAT_master_t *, unsigned int,
- unsigned int);
-
-// Private Methods
-
-// Master creation and deletion
-void EtherCAT_master_init(EtherCAT_master_t *);
-void EtherCAT_master_clear(EtherCAT_master_t *);
-
-// Registration of devices
-int EtherCAT_master_open(EtherCAT_master_t *, EtherCAT_device_t *);
-void EtherCAT_master_close(EtherCAT_master_t *, EtherCAT_device_t *);
-
-// Sending and receiving
-int EtherCAT_simple_send_receive(EtherCAT_master_t *, EtherCAT_command_t *);
-int EtherCAT_simple_send(EtherCAT_master_t *, EtherCAT_command_t *);
-int EtherCAT_simple_receive(EtherCAT_master_t *, EtherCAT_command_t *);
-
-// Slave management
-int EtherCAT_scan_for_slaves(EtherCAT_master_t *);
-int EtherCAT_read_slave_information(EtherCAT_master_t *, unsigned short int,
- unsigned short int, unsigned int *);
-int EtherCAT_state_change(EtherCAT_master_t *, EtherCAT_slave_t *,
- unsigned char);
-
-// Misc.
-
-void output_debug_data(const EtherCAT_master_t *);
-void ecat_output_lost_frames(EtherCAT_master_t *);
-
-/*****************************************************************************/
-
-#endif
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_module.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-/******************************************************************************
- *
- * ec_module.c
- *
- * EtherCAT-Master-Treiber
- *
- * Autoren: Wilhelm Hagemeister, Florian Pose
- *
- * $Id$
- *
- * (C) Copyright IgH 2005
- * Ingenieurgemeinschaft IgH
- * Heinz-Bäcker Str. 34
- * D-45356 Essen
- * Tel.: +49 201/61 99 31
- * Fax.: +49 201/61 98 36
- * E-mail: sp@igh-essen.com
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include "ec_module.h"
-
-int __init ecat_init_module(void);
-void __exit ecat_cleanup_module(void);
-
-/*****************************************************************************/
-
-#define LIT(X) #X
-#define STR(X) LIT(X)
-
-#define COMPILE_INFO "Revision " STR(EC_REV) \
- ", compiled by " STR(EC_USER) \
- " at " STR(EC_DATE)
-
-/*****************************************************************************/
-
-int ecat_master_count = 1;
-EtherCAT_master_t *ecat_masters = NULL;
-int *ecat_masters_reserved = NULL;
-
-/*****************************************************************************/
-
-MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>,"
- "Florian Pose <fp@igh-essen.com>");
-MODULE_DESCRIPTION ("EtherCAT master driver module");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(COMPILE_INFO);
-
-module_param(ecat_master_count, int, 1);
-MODULE_PARM_DESC(ecat_master_count,
- "Number of EtherCAT master to initialize.");
-
-module_init(ecat_init_module);
-module_exit(ecat_cleanup_module);
-
-EXPORT_SYMBOL(EtherCAT_register_device);
-EXPORT_SYMBOL(EtherCAT_unregister_device);
-EXPORT_SYMBOL(EtherCAT_request);
-EXPORT_SYMBOL(EtherCAT_release);
-
-/*****************************************************************************/
-
-/**
- Init-Funktion des EtherCAT-Master-Treibermodules
-
- Initialisiert soviele Master, wie im Parameter ecat_master_count
- angegeben wurde (Default ist 1).
-
- @returns 0, wenn alles o.k., -1 bei ungueltiger Anzahl Master
- oder zu wenig Speicher.
-*/
-
-int __init ecat_init_module(void)
-{
- unsigned int i;
-
- printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO);
-
- if (ecat_master_count < 1) {
- printk(KERN_ERR "EtherCAT: Error - Illegal"
- " ecat_master_count: %i\n", ecat_master_count);
- return -1;
- }
-
- printk(KERN_ERR "EtherCAT: Initializing %i EtherCAT master(s)...\n",
- ecat_master_count);
-
- if ((ecat_masters =
- (EtherCAT_master_t *) kmalloc(sizeof(EtherCAT_master_t)
- * ecat_master_count,
- GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "EtherCAT: Could not allocate"
- " memory for EtherCAT master(s)!\n");
- return -1;
- }
-
- if ((ecat_masters_reserved =
- (int *) kmalloc(sizeof(int) * ecat_master_count,
- GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "EtherCAT: Could not allocate"
- " memory for reservation flags!\n");
- kfree(ecat_masters);
- return -1;
- }
-
- for (i = 0; i < ecat_master_count; i++)
- {
- EtherCAT_master_init(&ecat_masters[i]);
- ecat_masters_reserved[i] = 0;
- }
-
- printk(KERN_ERR "EtherCAT: Master driver initialized.\n");
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/**
- Cleanup-Funktion des EtherCAT-Master-Treibermoduls
-
- Entfernt alle Master-Instanzen.
-*/
-
-void __exit ecat_cleanup_module(void)
-{
- unsigned int i;
-
- printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n");
-
- if (ecat_masters)
- {
- for (i = 0; i < ecat_master_count; i++)
- {
- if (ecat_masters_reserved[i]) {
- printk(KERN_WARNING "EtherCAT: Warning -"
- " Master %i is still in use!\n", i);
- }
-
- EtherCAT_master_clear(&ecat_masters[i]);
- }
-
- kfree(ecat_masters);
- }
-
- printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n");
-}
-
-/*****************************************************************************/
-
-/**
- Setzt das EtherCAT-Geraet, auf dem der Master arbeitet.
-
- Registriert das Geraet beim Master, der es daraufhin oeffnet.
-
- @param master Der EtherCAT-Master
- @param device Das EtherCAT-Geraet
- @return 0, wenn alles o.k.,
- < 0, wenn bereits ein Geraet registriert
- oder das Geraet nicht geoeffnet werden konnte.
-*/
-
-int EtherCAT_register_device(int index, EtherCAT_device_t *device)
-{
- if (index < 0 || index >= ecat_master_count) {
- printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index);
- return -1;
- }
-
- return EtherCAT_master_open(&ecat_masters[index], device);
-}
-
-/*****************************************************************************/
-
-/**
- Loescht das EtherCAT-Geraet, auf dem der Master arbeitet.
-
- @param master Der EtherCAT-Master
- @param device Das EtherCAT-Geraet
-*/
-
-void EtherCAT_unregister_device(int index, EtherCAT_device_t *device)
-{
- if (index < 0 || index >= ecat_master_count) {
- printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", index);
- return;
- }
-
- EtherCAT_master_close(&ecat_masters[index], device);
-}
-
-/*****************************************************************************/
-
-/**
- Reserviert einen bestimmten EtherCAT-Master und das zugehörige Gerät.
-
- Gibt einen Zeiger auf den reservierten EtherCAT-Master zurueck.
-
- @param index Index des gewuenschten Masters
- @returns Zeiger auf EtherCAT-Master oder NULL, wenn Parameter ungueltig.
-*/
-
-EtherCAT_master_t *EtherCAT_request(int index)
-{
- if (index < 0 || index >= ecat_master_count) {
- printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index);
- return NULL;
- }
-
- if (ecat_masters_reserved[index]) {
- printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index);
- return NULL;
- }
-
- if (!ecat_masters[index].dev) {
- printk(KERN_ERR "EtherCAT: Master %i has no device assigned yet!\n",
- index);
- return NULL;
- }
-
- if (!ecat_masters[index].dev->module) {
- printk(KERN_ERR "EtherCAT: Master %i device module is not set!\n", index);
- return NULL;
- }
-
- if (!try_module_get(ecat_masters[index].dev->module)) {
- printk(KERN_ERR "EtherCAT: Could not reserve device module!\n");
- return NULL;
- }
-
- if (EtherCAT_scan_for_slaves(&ecat_masters[index]) != 0) {
- printk(KERN_ERR "EtherCAT: Could not scan for slaves!\n");
- return NULL;
- }
-
- ecat_masters_reserved[index] = 1;
-
- printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index);
-
- return &ecat_masters[index];
-}
-
-/*****************************************************************************/
-
-/**
- Gibt einen zuvor angeforderten EtherCAT-Master wieder frei.
-
- @param master Zeiger auf den freizugebenden EtherCAT-Master.
-*/
-
-void EtherCAT_release(EtherCAT_master_t *master)
-{
- unsigned int i;
-
- for (i = 0; i < ecat_master_count; i++)
- {
- if (&ecat_masters[i] == master)
- {
- if (!ecat_masters[i].dev) {
- printk(KERN_WARNING "EtherCAT: Could not release device"
- "module because of no device!\n");
- return;
- }
-
- module_put(ecat_masters[i].dev->module);
- ecat_masters_reserved[i] = 0;
-
- printk(KERN_INFO "EtherCAT: Released master %i.\n", i);
-
- return;
- }
- }
-
- printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n",
- (unsigned int) master);
-}
-
-/*****************************************************************************/
--- a/drivers/ec_module.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/******************************************************************************
- *
- * ec_module.h
- *
- * EtherCAT-Master-Treiber
- *
- * Autoren: Wilhelm Hagemeister, Florian Pose
- *
- * $Id$
- *
- * (C) Copyright IgH 2005
- * Ingenieurgemeinschaft IgH
- * Heinz-Bäcker Str. 34
- * D-45356 Essen
- * Tel.: +49 201/61 99 31
- * Fax.: +49 201/61 98 36
- * E-mail: sp@igh-essen.com
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include "ec_master.h"
-
-/*****************************************************************************/
-
-// Registration of devices
-int EtherCAT_register_device(int, EtherCAT_device_t *);
-void EtherCAT_unregister_device(int, EtherCAT_device_t *);
-
-EtherCAT_master_t *EtherCAT_request(int);
-void EtherCAT_release(EtherCAT_master_t *);
-
-/*****************************************************************************/
--- a/drivers/ec_slave.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/******************************************************************************
- *
- * e c _ s l a v e . c
- *
- * Methoden für einen EtherCAT-Slave.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-
-#include "ec_globals.h"
-#include "ec_slave.h"
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Slave-Konstruktor.
-
- Initialisiert einen EtherCAT-Slave.
-
- ACHTUNG! Dieser Konstruktor wird quasi nie aufgerufen. Bitte immer das
- Makro ECAT_INIT_SLAVE() in ec_slave.h anpassen!
-
- @param slave Zeiger auf den zu initialisierenden Slave
-*/
-
-void EtherCAT_slave_init(EtherCAT_slave_t *slave)
-{
- slave->type = 0;
- slave->revision = 0;
- slave->build = 0;
- slave->ring_position = 0;
- slave->station_address = 0;
- slave->vendor_id = 0;
- slave->product_code = 0;
- slave->revision_number = 0;
- slave->serial_number = 0;
- slave->desc = NULL;
- slave->logical_address = 0;
- slave->current_state = ECAT_STATE_UNKNOWN;
- slave->requested_state = ECAT_STATE_UNKNOWN;
- slave->process_data = NULL;
- slave->domain = 0;
- slave->error_reported = 0;
-}
-
-/*****************************************************************************/
-
-/**
- Liest einen bestimmten Kanal des Slaves als Integer-Wert.
-
- Prüft zuerst, ob der entsprechende Slave eine
- bekannte Beschreibung besitzt, ob dort eine
- read()-Funktion hinterlegt ist und ob die angegebene
- Kanalnummer gültig ist. Wenn ja, wird der dekodierte
- Wert zurückgegeben, sonst ist der Wert 0.
-
- @param slave EtherCAT-Slave
- @param channel Kanalnummer
-
- @return Gelesener Wert bzw. 0
-*/
-
-int EtherCAT_read_value(EtherCAT_slave_t *slave,
- unsigned int channel)
-{
- if (unlikely(!slave->desc)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Reading failed on slave %04X (addr %0X)"
- " - Slave has no description.\n",
- slave->station_address, (unsigned int) slave);
- slave->error_reported = 1;
- }
- return 0;
- }
-
- if (unlikely(!slave->desc->read)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Reading failed on slave %04X (addr %0X)"
- " - Slave type (%s %s) has no read method.\n",
- slave->station_address, (unsigned int) slave,
- slave->desc->vendor_name, slave->desc->product_name);
- slave->error_reported = 1;
- }
- return 0;
- }
-
- if (unlikely(channel >= slave->desc->channel_count)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Reading failed on slave %4X (addr %0X)"
- " - Type (%s %s) has no channel %i.\n",
- slave->station_address, (unsigned int) slave,
- slave->desc->vendor_name, slave->desc->product_name,
- channel);
- slave->error_reported = 1;
- }
- return 0;
- }
-
- if (unlikely(!slave->process_data)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Reading failed on slave %4X (addr %0X)"
- " - Slave does not belong to any process data object!\n",
- slave->station_address, (unsigned int) slave);
- slave->error_reported = 1;
- }
- return 0;
- }
-
- if (unlikely(slave->error_reported))
- slave->error_reported = 0;
-
- return slave->desc->read(slave->process_data, channel);
-}
-
-/*****************************************************************************/
-
-/**
- Schreibt einen bestimmten Kanal des Slaves als Integer-Wert .
-
- Prüft zuerst, ob der entsprechende Slave eine
- bekannte Beschreibung besitzt, ob dort eine
- write()-Funktion hinterlegt ist und ob die angegebene
- Kanalnummer gültig ist. Wenn ja, wird der Wert entsprechend
- kodiert und geschrieben.
-
- @param slave EtherCAT-Slave
- @param channel Kanalnummer
- @param value Zu schreibender Wert
-*/
-
-void EtherCAT_write_value(EtherCAT_slave_t *slave,
- unsigned int channel,
- int value)
-{
- if (unlikely(!slave->desc)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Writing failed on slave %04X (addr %0X)"
- " - Slave has no description.\n",
- slave->station_address, (unsigned int) slave);
- slave->error_reported = 1;
- }
- return;
- }
-
- if (unlikely(!slave->desc->write)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Writing failed on slave %04X (addr %0X)"
- " - Type (%s %s) has no write method.\n",
- slave->station_address, (unsigned int) slave,
- slave->desc->vendor_name, slave->desc->product_name);
- slave->error_reported = 1;
- }
- return;
- }
-
- if (unlikely(channel >= slave->desc->channel_count)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Writing failed on slave %4X (addr %0X)"
- " - Type (%s %s) has no channel %i.\n",
- slave->station_address, (unsigned int) slave,
- slave->desc->vendor_name, slave->desc->product_name,
- channel);
- slave->error_reported = 1;
- }
- return;
- }
-
- if (unlikely(!slave->process_data)) {
- if (likely(slave->error_reported)) {
- printk(KERN_WARNING "EtherCAT: Writing failed on slave %4X (addr %0X)"
- " - Slave does not belong to any process data object!\n",
- slave->station_address, (unsigned int) slave);
- slave->error_reported = 1;
- }
- return;
- }
-
- if (unlikely(slave->error_reported))
- slave->error_reported = 0;
-
- slave->desc->write(slave->process_data, channel, value);
-}
-
-/*****************************************************************************/
-
-EXPORT_SYMBOL(EtherCAT_write_value);
-EXPORT_SYMBOL(EtherCAT_read_value);
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_slave.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/******************************************************************************
- *
- * e c _ s l a v e . h
- *
- * Struktur für einen EtherCAT-Slave.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_SLAVE_H_
-#define _EC_SLAVE_H_
-
-#include "ec_types.h"
-
-/*****************************************************************************/
-
-/**
- EtherCAT-Slave
-
- Achtung: Bei Änderungen dieser Struktur immer das Define
- ECAT_INIT_SLAVE anpassen!
-*/
-
-typedef struct
-{
- // Base data
- unsigned char type; /**< Slave-Typ */
- unsigned char revision; /**< Revision */
- unsigned short build; /**< Build-Nummer */
-
- // Addresses
- short ring_position; /**< (Negative) Position des Slaves im Bus */
- unsigned short station_address; /**< Konfigurierte Slave-Adresse */
-
- // Slave information interface
- unsigned int vendor_id; /**< Identifikationsnummer des Herstellers */
- unsigned int product_code; /**< Herstellerspezifischer Produktcode */
- unsigned int revision_number; /**< Revisionsnummer */
- unsigned int serial_number; /**< Seriennummer der Klemme */
-
- const EtherCAT_slave_desc_t *desc; /**< Zeiger auf die Beschreibung
- des Slave-Typs */
-
- unsigned int logical_address; /**< Konfigurierte, logische adresse */
-
- EtherCAT_state_t current_state; /**< Aktueller Zustand */
- EtherCAT_state_t requested_state; /**< Angeforderter Zustand */
-
- unsigned char *process_data; /**< Zeiger auf den Speicherbereich
- innerhalb eines Prozessdatenobjekts */
- unsigned int domain; /**< Prozessdatendomäne */
- int error_reported; /**< Ein Zugriffsfehler wurde bereits gemeldet */
-}
-EtherCAT_slave_t;
-
-#define ECAT_INIT_SLAVE(TYPE, DOMAIN) {0, 0, 0, 0, 0, 0, 0, 0, 0, \
- TYPE, 0, ECAT_STATE_UNKNOWN, \
- ECAT_STATE_UNKNOWN, NULL, DOMAIN, 0}
-
-/*****************************************************************************/
-
-// Slave construction and deletion
-void EtherCAT_slave_init(EtherCAT_slave_t *);
-
-int EtherCAT_read_value(EtherCAT_slave_t *, unsigned int);
-void EtherCAT_write_value(EtherCAT_slave_t *, unsigned int, int);
-
-/*****************************************************************************/
-
-#endif
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:2 ***
-;;; End: ***
-*/
--- a/drivers/ec_types.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-/******************************************************************************
- *
- * e c _ t y p e s . c
- *
- * EtherCAT-Slave-Typen.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-
-#include "ec_globals.h"
-#include "ec_types.h"
-
-/*****************************************************************************/
-
-/* Konfigurationen der Sync-Manager */
-
-unsigned char sm0_multi[] = {0x00, 0x18, 0xF6, 0x00, 0x26, 0x00, 0x01, 0x00};
-unsigned char sm1_multi[] = {0xF6, 0x18, 0xF6, 0x00, 0x22, 0x00, 0x01, 0x00};
-
-unsigned char sm0_1014[] = {0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
-
-unsigned char sm0_2004[] = {0x00, 0x0F, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00};
-
-unsigned char sm2_31xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00};
-unsigned char sm3_31xx[] = {0x00, 0x11, 0x06, 0x00, 0x20, 0x00, 0x01, 0x00};
-
-unsigned char sm2_41xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00};
-
-/* Konfigurationen der Memory-Management-Units */
-
-unsigned char fmmu0_1014[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
- 0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
-
-unsigned char fmmu0_2004[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
- 0x00, 0x0F, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
-
-unsigned char fmmu0_31xx[] = {0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07,
- 0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
-
-unsigned char fmmu0_41xx[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07,
- 0x00, 0x10, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
-
-/*****************************************************************************/
-
-/* Lese- und Schreibfunktionen */
-
-int read_1014(unsigned char *data, unsigned int channel)
-{
- return (data[0] >> channel) & 0x01;
-}
-
-void write_2004(unsigned char *data, unsigned int channel, int value)
-{
- if (value)
- {
- data[0] |= (1 << channel);
- }
- else
- {
- data[0] &= ~(1 << channel);
- }
-}
-
-int read_31xx(unsigned char *data, unsigned int channel)
-{
- return (short int) ((data[channel * 3 + 2] << 8) | data[channel * 3 + 1]);
-}
-
-void write_41xx(unsigned char *data, unsigned int channel, int value)
-{
- data[channel * 3 + 1] = (value & 0xFF00) >> 8;
- data[channel * 3 + 2] = value & 0xFF;
-}
-
-/*****************************************************************************/
-
-/* Klemmen-Objekte */
-
-EtherCAT_slave_desc_t Beckhoff_EK1100[] =
-{{
- "Beckhoff", "EK1100", "Bus Coupler",
- ECAT_ST_SIMPLE_NOSYNC,
- NULL, NULL, NULL, NULL,
- NULL,
- 0, 0,
- NULL, NULL
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL1014[] =
-{{
- "Beckhoff", "EL1014", "4x Digital Input",
- ECAT_ST_SIMPLE,
- sm0_1014, NULL, NULL, NULL,
- fmmu0_1014,
- 1, 4,
- read_1014, NULL
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL2004[] =
-{{
- "Beckhoff", "EL2004", "4x Digital Output",
- ECAT_ST_SIMPLE,
- sm0_2004, NULL, NULL, NULL,
- fmmu0_2004,
- 1, 4,
- NULL, write_2004
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL3102[] =
-{{
- "Beckhoff", "EL3102", "2x Analog Input diff.",
- ECAT_ST_MAILBOX,
- sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
- fmmu0_31xx,
- 6, 2,
- read_31xx, NULL
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL3162[] =
-{{
- "Beckhoff", "EL3162", "2x Analog Input",
- ECAT_ST_MAILBOX,
- sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
- fmmu0_31xx,
- 6, 2,
- read_31xx, NULL
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL4102[] =
-{{
- "Beckhoff", "EL4102", "2x Analog Output",
- ECAT_ST_MAILBOX,
- sm0_multi, sm1_multi, sm2_41xx, NULL,
- fmmu0_41xx,
- 4, 2,
- NULL, write_41xx
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL4132[] =
-{{
- "Beckhoff", "EL4132", "2x Analog Output diff.",
- ECAT_ST_MAILBOX,
- sm0_multi, sm1_multi, sm2_41xx, NULL,
- fmmu0_41xx,
- 4, 2,
- NULL, write_41xx
-}};
-
-EtherCAT_slave_desc_t Beckhoff_EL5001[] =
-{{
- "Beckhoff", "EL5001", "SSI-Interface",
- ECAT_ST_SIMPLE,
- NULL, NULL, NULL, NULL, // Noch nicht eingepflegt...
- NULL,
- 0, 0,
- NULL, NULL
-}};
-
-/*****************************************************************************/
-
-/**
- Beziehung zwischen Identifikationsnummern und Klemmen-Objekt.
-
- Diese Tabelle stellt die Beziehungen zwischen bestimmten Kombinationen
- aus Vendor-IDs und Product-Codes und der entsprechenden Klemme her.
- Neue Klemmen müssen hier eingetragen werden.
-*/
-
-EtherCAT_slave_ident_t slave_idents[] =
-{
- {0x00000002, 0x03F63052, Beckhoff_EL1014},
- {0x00000002, 0x044C2C52, Beckhoff_EK1100},
- {0x00000002, 0x07D43052, Beckhoff_EL2004},
- {0x00000002, 0x0C1E3052, Beckhoff_EL3102},
- {0x00000002, 0x0C5A3052, Beckhoff_EL3162},
- {0x00000002, 0x10063052, Beckhoff_EL4102},
- {0x00000002, 0x10243052, Beckhoff_EL4132},
- {0x00000002, 0x13893052, Beckhoff_EL5001}
-};
-
-unsigned int slave_ident_count = sizeof(slave_idents)
- / sizeof(EtherCAT_slave_ident_t);
-
-
-/*****************************************************************************/
-
-EXPORT_SYMBOL(Beckhoff_EK1100);
-EXPORT_SYMBOL(Beckhoff_EL1014);
-EXPORT_SYMBOL(Beckhoff_EL2004);
-EXPORT_SYMBOL(Beckhoff_EL3102);
-EXPORT_SYMBOL(Beckhoff_EL3162);
-EXPORT_SYMBOL(Beckhoff_EL4102);
-EXPORT_SYMBOL(Beckhoff_EL4132);
-EXPORT_SYMBOL(Beckhoff_EL5001);
-
-/*****************************************************************************/
--- a/drivers/ec_types.h Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/******************************************************************************
- *
- * e c _ t y p e s . h
- *
- * EtherCAT-Slave-Typen.
- *
- * $Id$
- *
- *****************************************************************************/
-
-#ifndef _EC_TYPES_H_
-#define _EC_TYPES_H_
-
-/*****************************************************************************/
-
-/**
- Typ eines EtherCAT-Slaves.
-
- Dieser Typ muss für die Konfiguration bekannt sein. Der
- Master entscheidet danach, ober bspw. Mailboxes konfigurieren,
- oder Sync-Manager setzen soll.
-*/
-
-typedef enum
-{
- ECAT_ST_SIMPLE, ECAT_ST_MAILBOX, ECAT_ST_SIMPLE_NOSYNC
-}
-EtherCAT_slave_type_t;
-
-/*****************************************************************************/
-
-/**
- Beschreibung eines EtherCAT-Slave-Typs.
-
- Diese Beschreibung dient zur Konfiguration einer bestimmten
- Slave-Art. Sie enthält die Konfigurationsdaten für die
- Slave-internen Sync-Manager und FMMU's.
-*/
-
-typedef struct slave_desc
-{
- const char *vendor_name; /**< Name des Herstellers */
- const char *product_name; /**< Name des Slaves-Typs */
- const char *product_desc; /**< Genauere Beschreibung des Slave-Typs */
-
- const EtherCAT_slave_type_t type; /**< Art des Slave-Typs */
-
- const unsigned char *sm0; /**< Konfigurationsdaten des
- ersten Sync-Managers */
- const unsigned char *sm1; /**< Konfigurationsdaten des
- zweiten Sync-Managers */
- const unsigned char *sm2; /**< Konfigurationsdaten des
- dritten Sync-Managers */
- const unsigned char *sm3; /**< Konfigurationsdaten des
- vierten Sync-Managers */
-
- const unsigned char *fmmu0; /**< Konfigurationsdaten
- der ersten FMMU */
-
- const unsigned int process_data_size; /**< Länge der Prozessdaten in Bytes */
- const unsigned int channel_count; /**< Anzahl der Kanäle */
-
- int (*read) (unsigned char *, unsigned int); /**< Funktion zum Dekodieren
- und Lesen der Kanaldaten */
- void (*write) (unsigned char *, unsigned int, int); /**< Funktion zum
- Kodieren und Schreiben
- der Kanaldaten */
-}
-EtherCAT_slave_desc_t;
-
-/*****************************************************************************/
-
-/**
- Identifikation eines Slave-Typs.
-
- Diese Struktur wird zur 1:n-Zuordnung von Hersteller- und
- Produktcodes zu den einzelnen Slave-Typen verwendet.
-*/
-
-typedef struct slave_ident
-{
- const unsigned int vendor_id; /**< Hersteller-Code */
- const unsigned int product_code; /**< Herstellerspezifischer Produktcode */
- const EtherCAT_slave_desc_t *desc; /**< Zeiger auf den dazugehörigen
- Slave-Typ */
-}
-EtherCAT_slave_ident_t;
-
-extern EtherCAT_slave_ident_t slave_idents[]; /**< Statisches Array der
- Slave-Identifikationen */
-extern unsigned int slave_ident_count; /**< Anzahl der vorhandenen
- Slave-Identifikationen */
-
-/*****************************************************************************/
-
-extern EtherCAT_slave_desc_t Beckhoff_EK1100[];
-extern EtherCAT_slave_desc_t Beckhoff_EL1014[];
-extern EtherCAT_slave_desc_t Beckhoff_EL2004[];
-extern EtherCAT_slave_desc_t Beckhoff_EL3102[];
-extern EtherCAT_slave_desc_t Beckhoff_EL3162[];
-extern EtherCAT_slave_desc_t Beckhoff_EL4102[];
-extern EtherCAT_slave_desc_t Beckhoff_EL4132[];
-extern EtherCAT_slave_desc_t Beckhoff_EL5001[];
-
-/*****************************************************************************/
-
-#endif
--- a/drivers/original_8139too.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2646 +0,0 @@
-/*
-
- 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
-
- Maintained by Jeff Garzik <jgarzik@pobox.com>
- Copyright 2000-2002 Jeff Garzik
-
- Much code comes from Donald Becker's rtl8139.c driver,
- versions 1.13 and older. This driver was originally based
- on rtl8139.c version 1.07. Header of rtl8139.c version 1.13:
-
- -----<snip>-----
-
- Written 1997-2001 by Donald Becker.
- This software may be used and distributed according to the
- terms of the GNU General Public License (GPL), incorporated
- herein by reference. Drivers based on or derived from this
- code fall under the GPL and must retain the authorship,
- copyright and license notice. This file is not a complete
- program and may only be used when the entire operating
- system is licensed under the GPL.
-
- This driver is for boards based on the RTL8129 and RTL8139
- PCI ethernet chips.
-
- The author may be reached as becker@scyld.com, or C/O Scyld
- Computing Corporation 410 Severn Ave., Suite 210 Annapolis
- MD 21403
-
- Support and updates available at
- http://www.scyld.com/network/rtl8139.html
-
- Twister-tuning table provided by Kinston
- <shangh@realtek.com.tw>.
-
- -----<snip>-----
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- Contributors:
-
- Donald Becker - he wrote the original driver, kudos to him!
- (but please don't e-mail him for support, this isn't his driver)
-
- Tigran Aivazian - bug fixes, skbuff free cleanup
-
- Martin Mares - suggestions for PCI cleanup
-
- David S. Miller - PCI DMA and softnet updates
-
- Ernst Gill - fixes ported from BSD driver
-
- Daniel Kobras - identified specific locations of
- posted MMIO write bugginess
-
- Gerard Sharp - bug fix, testing and feedback
-
- David Ford - Rx ring wrap fix
-
- Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
- to find and fix a crucial bug on older chipsets.
-
- Donald Becker/Chris Butterworth/Marcus Westergren -
- Noticed various Rx packet size-related buglets.
-
- Santiago Garcia Mantinan - testing and feedback
-
- Jens David - 2.2.x kernel backports
-
- Martin Dennett - incredibly helpful insight on undocumented
- features of the 8139 chips
-
- Jean-Jacques Michel - bug fix
-
- Tobias Ringström - Rx interrupt status checking suggestion
-
- Andrew Morton - Clear blocked signals, avoid
- buffer overrun setting current->comm.
-
- Kalle Olavi Niemitalo - Wake-on-LAN ioctls
-
- Robert Kuebel - Save kernel thread from dying on any signal.
-
- Submitting bug reports:
-
- "rtl8139-diag -mmmaaavvveefN" output
- enable RTL8139_DEBUG below, and look at 'dmesg' or kernel log
-
-*/
-
-#define DRV_NAME "8139too"
-#define DRV_VERSION "0.9.27"
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/completion.h>
-#include <linux/crc32.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
-#define PFX DRV_NAME ": "
-
-/* Default Message level */
-#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
- NETIF_MSG_PROBE | \
- NETIF_MSG_LINK)
-
-
-/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
-#ifdef CONFIG_8139TOO_PIO
-#define USE_IO_OPS 1
-#endif
-
-/* define to 1, 2 or 3 to enable copious debugging info */
-#define RTL8139_DEBUG 0
-
-/* define to 1 to disable lightweight runtime debugging checks */
-#undef RTL8139_NDEBUG
-
-
-#if RTL8139_DEBUG
-/* note: prints function name for you */
-# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-# define DPRINTK(fmt, args...)
-#endif
-
-#ifdef RTL8139_NDEBUG
-# define assert(expr) do {} while (0)
-#else
-# define assert(expr) \
- if(unlikely(!(expr))) { \
- printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
-#endif
-
-
-/* A few user-configurable values. */
-/* media options */
-#define MAX_UNITS 8
-static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-
-/* bitmapped message enable number */
-static int debug = -1;
-
-/*
- * Receive ring size
- * Warning: 64K ring has hardware issues and may lock up.
- */
-#if defined(CONFIG_SH_DREAMCAST)
-#define RX_BUF_IDX 1 /* 16K ring */
-#else
-#define RX_BUF_IDX 2 /* 32K ring */
-#endif
-#define RX_BUF_LEN (8192 << RX_BUF_IDX)
-#define RX_BUF_PAD 16
-#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
-
-#if RX_BUF_LEN == 65536
-#define RX_BUF_TOT_LEN RX_BUF_LEN
-#else
-#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
-#endif
-
-/* Number of Tx descriptor registers. */
-#define NUM_TX_DESC 4
-
-/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
-#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
-
-/* PCI Tuning Parameters
- Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */
-
-/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
-#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (6*HZ)
-
-
-enum {
- HAS_MII_XCVR = 0x010000,
- HAS_CHIP_XCVR = 0x020000,
- HAS_LNK_CHNG = 0x040000,
-};
-
-#define RTL_NUM_STATS 4 /* number of ETHTOOL_GSTATS u64's */
-#define RTL_REGS_VER 1 /* version of reg. data in ETHTOOL_GREGS */
-#define RTL_MIN_IO_SIZE 0x80
-#define RTL8139B_IO_SIZE 256
-
-#define RTL8129_CAPS HAS_MII_XCVR
-#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
-
-typedef enum {
- RTL8139 = 0,
- RTL8129,
-} board_t;
-
-
-/* indexed by board_t, above */
-static struct {
- const char *name;
- u32 hw_flags;
-} board_info[] __devinitdata = {
- { "RealTek RTL8139", RTL8139_CAPS },
- { "RealTek RTL8129", RTL8129_CAPS },
-};
-
-
-static struct pci_device_id rtl8139_pci_tbl[] = {
- {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1259, 0xa117, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1259, 0xa11e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
- {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
-
-#ifdef CONFIG_SH_SECUREEDGE5410
- /* Bogus 8139 silicon reports 8129 without external PROM :-( */
- {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
-#endif
-#ifdef CONFIG_8139TOO_8129
- {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
-#endif
-
- /* some crazy cards report invalid vendor ids like
- * 0x0001 here. The other ids are valid and constant,
- * so we simply don't match on the main vendor id.
- */
- {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
- {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, RTL8139 },
- {PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, RTL8139 },
-
- {0,}
-};
-MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
-
-static struct {
- const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
- { "early_rx" },
- { "tx_buf_mapped" },
- { "tx_timeouts" },
- { "rx_lost_in_ring" },
-};
-
-/* The rest of these values should never change. */
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- TxSummary = 0x60,
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
- /* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
-};
-
-enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
-};
-
-enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
-};
-
-enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
-
- /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-/* Bits in Config1 */
-enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
- Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
-};
-
-/* Bits in Config3 */
-enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
-};
-
-/* Bits in Config4 */
-enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
-};
-
-/* Bits in Config5 */
-enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
-};
-
-enum RxConfigBits {
- /* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
- /* Max DMA burst */
- RxCfgDMAShift = 8,
- RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
- /* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
-
- /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
-};
-
-/* Twister tuning parameters from RealTek.
- Completely undocumented, but required to tune bad links on some boards. */
-enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
-};
-
-enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-};
-
-typedef enum {
- CH_8139 = 0,
- CH_8139_K,
- CH_8139A,
- CH_8139A_G,
- CH_8139B,
- CH_8130,
- CH_8139C,
- CH_8100,
- CH_8100B_8139D,
- CH_8101,
-} chip_t;
-
-enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
-};
-
-#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
- (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
-#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
-
-/* directly indexed by chip_t, above */
-const static struct {
- const char *name;
- u32 version; /* from RTL8139C/RTL8139D docs */
- u32 flags;
-} rtl_chip_info[] = {
- { "RTL-8139",
- HW_REVID(1, 0, 0, 0, 0, 0, 0),
- HasHltClk,
- },
-
- { "RTL-8139 rev K",
- HW_REVID(1, 1, 0, 0, 0, 0, 0),
- HasHltClk,
- },
-
- { "RTL-8139A",
- HW_REVID(1, 1, 1, 0, 0, 0, 0),
- HasHltClk, /* XXX undocumented? */
- },
-
- { "RTL-8139A rev G",
- HW_REVID(1, 1, 1, 0, 0, 1, 0),
- HasHltClk, /* XXX undocumented? */
- },
-
- { "RTL-8139B",
- HW_REVID(1, 1, 1, 1, 0, 0, 0),
- HasLWake,
- },
-
- { "RTL-8130",
- HW_REVID(1, 1, 1, 1, 1, 0, 0),
- HasLWake,
- },
-
- { "RTL-8139C",
- HW_REVID(1, 1, 1, 0, 1, 0, 0),
- HasLWake,
- },
-
- { "RTL-8100",
- HW_REVID(1, 1, 1, 1, 0, 1, 0),
- HasLWake,
- },
-
- { "RTL-8100B/8139D",
- HW_REVID(1, 1, 1, 0, 1, 0, 1),
- HasLWake,
- },
-
- { "RTL-8101",
- HW_REVID(1, 1, 1, 0, 1, 1, 1),
- HasLWake,
- },
-};
-
-struct rtl_extra_stats {
- unsigned long early_rx;
- unsigned long tx_buf_mapped;
- unsigned long tx_timeouts;
- unsigned long rx_lost_in_ring;
-};
-
-struct rtl8139_private {
- void __iomem *mmio_addr;
- int drv_flags;
- struct pci_dev *pci_dev;
- u32 msg_enable;
- struct net_device_stats stats;
- unsigned char *rx_ring;
- unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
- unsigned int tx_flag;
- unsigned long cur_tx;
- unsigned long dirty_tx;
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_bufs_dma;
- signed char phys[4]; /* MII device addresses. */
- char twistie, twist_row, twist_col; /* Twister tune state. */
- unsigned int default_port:4; /* Last dev->if_port value. */
- spinlock_t lock;
- spinlock_t rx_lock;
- chip_t chipset;
- pid_t thr_pid;
- wait_queue_head_t thr_wait;
- struct completion thr_exited;
- u32 rx_config;
- struct rtl_extra_stats xstats;
- int time_to_die;
- struct mii_if_info mii;
- unsigned int regs_len;
- unsigned long fifo_copy_timeout;
-};
-
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
-MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_param(multicast_filter_limit, int, 0);
-module_param_array(media, int, NULL, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param(debug, int, 0);
-MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
-MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
-MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
-MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
-
-static int read_eeprom (void __iomem *ioaddr, int location, int addr_len);
-static int rtl8139_open (struct net_device *dev);
-static int mdio_read (struct net_device *dev, int phy_id, int location);
-static void mdio_write (struct net_device *dev, int phy_id, int location,
- int val);
-static void rtl8139_start_thread(struct net_device *dev);
-static void rtl8139_tx_timeout (struct net_device *dev);
-static void rtl8139_init_ring (struct net_device *dev);
-static int rtl8139_start_xmit (struct sk_buff *skb,
- struct net_device *dev);
-static int rtl8139_poll(struct net_device *dev, int *budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void rtl8139_poll_controller(struct net_device *dev);
-#endif
-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs);
-static int rtl8139_close (struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
-static void rtl8139_set_rx_mode (struct net_device *dev);
-static void __set_rx_mode (struct net_device *dev);
-static void rtl8139_hw_start (struct net_device *dev);
-static struct ethtool_ops rtl8139_ethtool_ops;
-
-/* write MMIO register, with flush */
-/* Flush avoids rtl8139 bug w/ posted MMIO writes */
-#define RTL_W8_F(reg, val8) do { iowrite8 ((val8), ioaddr + (reg)); ioread8 (ioaddr + (reg)); } while (0)
-#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
-#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
-
-
-#define MMIO_FLUSH_AUDIT_COMPLETE 1
-#if MMIO_FLUSH_AUDIT_COMPLETE
-
-/* write MMIO register */
-#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
-
-#else
-
-/* write MMIO register, then flush */
-#define RTL_W8 RTL_W8_F
-#define RTL_W16 RTL_W16_F
-#define RTL_W32 RTL_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
-/* read MMIO register */
-#define RTL_R8(reg) ioread8 (ioaddr + (reg))
-#define RTL_R16(reg) ioread16 (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
-
-
-static const u16 rtl8139_intr_mask =
- PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
- TxErr | TxOK | RxErr | RxOK;
-
-static const u16 rtl8139_norx_intr_mask =
- PCIErr | PCSTimeout | RxUnderrun |
- TxErr | TxOK | RxErr ;
-
-#if RX_BUF_IDX == 0
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv8K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 1
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv16K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 2
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv32K | RxNoWrap |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#elif RX_BUF_IDX == 3
-static const unsigned int rtl8139_rx_config =
- RxCfgRcv64K |
- (RX_FIFO_THRESH << RxCfgFIFOShift) |
- (RX_DMA_BURST << RxCfgDMAShift);
-#else
-#error "Invalid configuration for 8139_RXBUF_IDX"
-#endif
-
-static const unsigned int rtl8139_tx_config =
- TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
-
-static void __rtl8139_cleanup_dev (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- struct pci_dev *pdev;
-
- assert (dev != NULL);
- assert (tp->pci_dev != NULL);
- pdev = tp->pci_dev;
-
-#ifdef USE_IO_OPS
- if (tp->mmio_addr)
- ioport_unmap (tp->mmio_addr);
-#else
- if (tp->mmio_addr)
- pci_iounmap (pdev, tp->mmio_addr);
-#endif /* USE_IO_OPS */
-
- /* it's ok to call this even if we have no regions to free */
- pci_release_regions (pdev);
-
- free_netdev(dev);
- pci_set_drvdata (pdev, NULL);
-}
-
-
-static void rtl8139_chip_reset (void __iomem *ioaddr)
-{
- int i;
-
- /* Soft reset the chip. */
- RTL_W8 (ChipCmd, CmdReset);
-
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
- barrier();
- if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
- break;
- udelay (10);
- }
-}
-
-
-static int __devinit rtl8139_init_board (struct pci_dev *pdev,
- struct net_device **dev_out)
-{
- void __iomem *ioaddr;
- struct net_device *dev;
- struct rtl8139_private *tp;
- u8 tmp8;
- int rc, disable_dev_on_err = 0;
- unsigned int i;
- unsigned long pio_start, pio_end, pio_flags, pio_len;
- unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
- u32 version;
-
- assert (pdev != NULL);
-
- *dev_out = NULL;
-
- /* dev and priv zeroed in alloc_etherdev */
- dev = alloc_etherdev (sizeof (*tp));
- if (dev == NULL) {
- printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
- return -ENOMEM;
- }
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- tp = netdev_priv(dev);
- tp->pci_dev = pdev;
-
- /* enable device (incl. PCI PM wakeup and hotplug setup) */
- rc = pci_enable_device (pdev);
- if (rc)
- goto err_out;
-
- pio_start = pci_resource_start (pdev, 0);
- pio_end = pci_resource_end (pdev, 0);
- pio_flags = pci_resource_flags (pdev, 0);
- pio_len = pci_resource_len (pdev, 0);
-
- mmio_start = pci_resource_start (pdev, 1);
- mmio_end = pci_resource_end (pdev, 1);
- mmio_flags = pci_resource_flags (pdev, 1);
- mmio_len = pci_resource_len (pdev, 1);
-
- /* set this immediately, we need to know before
- * we talk to the chip directly */
- DPRINTK("PIO region size == 0x%02X\n", pio_len);
- DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
-
-#ifdef USE_IO_OPS
- /* make sure PCI base addr 0 is PIO */
- if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
- /* check for weird/broken PCI region reporting */
- if (pio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
-#else
- /* make sure PCI base addr 1 is MMIO */
- if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
- if (mmio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
- rc = -ENODEV;
- goto err_out;
- }
-#endif
-
- rc = pci_request_regions (pdev, "8139too");
- if (rc)
- goto err_out;
- disable_dev_on_err = 1;
-
- /* enable PCI bus-mastering */
- pci_set_master (pdev);
-
-#ifdef USE_IO_OPS
- ioaddr = ioport_map(pio_start, pio_len);
- if (!ioaddr) {
- printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
- dev->base_addr = pio_start;
- tp->mmio_addr = ioaddr;
- tp->regs_len = pio_len;
-#else
- /* ioremap MMIO region */
- ioaddr = pci_iomap(pdev, 1, 0);
- if (ioaddr == NULL) {
- printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
- dev->base_addr = (long) ioaddr;
- tp->mmio_addr = ioaddr;
- tp->regs_len = mmio_len;
-#endif /* USE_IO_OPS */
-
- /* Bring old chips out of low-power mode. */
- RTL_W8 (HltClk, 'R');
-
- /* check for missing/broken hardware */
- if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
- printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
- pci_name(pdev));
- rc = -EIO;
- goto err_out;
- }
-
- /* identify chip attached to board */
- version = RTL_R32 (TxConfig) & HW_REVID_MASK;
- for (i = 0; i < ARRAY_SIZE (rtl_chip_info); i++)
- if (version == rtl_chip_info[i].version) {
- tp->chipset = i;
- goto match;
- }
-
- /* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
- tp->chipset = 0;
-
-match:
- DPRINTK ("chipset id (%d) == index %d, '%s'\n",
- version, i, rtl_chip_info[i].name);
-
- if (tp->chipset >= CH_8139B) {
- u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
- DPRINTK("PCI PM wakeup\n");
- if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
- (tmp8 & LWAKE))
- new_tmp8 &= ~LWAKE;
- new_tmp8 |= Cfg1_PM_Enable;
- if (new_tmp8 != tmp8) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config1, tmp8);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- }
- if (rtl_chip_info[tp->chipset].flags & HasLWake) {
- tmp8 = RTL_R8 (Config4);
- if (tmp8 & LWPTN) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config4, tmp8 & ~LWPTN);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- }
- }
- } else {
- DPRINTK("Old chip wakeup\n");
- tmp8 = RTL_R8 (Config1);
- tmp8 &= ~(SLEEP | PWRDN);
- RTL_W8 (Config1, tmp8);
- }
-
- rtl8139_chip_reset (ioaddr);
-
- *dev_out = dev;
- return 0;
-
-err_out:
- __rtl8139_cleanup_dev (dev);
- if (disable_dev_on_err)
- pci_disable_device (pdev);
- return rc;
-}
-
-
-static int __devinit rtl8139_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev = NULL;
- struct rtl8139_private *tp;
- int i, addr_len, option;
- void __iomem *ioaddr;
- static int board_idx = -1;
- u8 pci_rev;
-
- assert (pdev != NULL);
- assert (ent != NULL);
-
- board_idx++;
-
- /* when we're built into the kernel, the driver version message
- * is only printed if at least one 8139 board has been found
- */
-#ifndef MODULE
- {
- static int printed_version;
- if (!printed_version++)
- printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
- }
-#endif
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-
- if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
- pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
- printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
- }
-
- i = rtl8139_init_board (pdev, &dev);
- if (i < 0)
- return i;
-
- assert (dev != NULL);
- tp = netdev_priv(dev);
-
- ioaddr = tp->mmio_addr;
- assert (ioaddr != NULL);
-
- addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
- for (i = 0; i < 3; i++)
- ((u16 *) (dev->dev_addr))[i] =
- le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
-
- /* The Rtl8139-specific entries in the device structure. */
- dev->open = rtl8139_open;
- dev->hard_start_xmit = rtl8139_start_xmit;
- dev->poll = rtl8139_poll;
- dev->weight = 64;
- dev->stop = rtl8139_close;
- dev->get_stats = rtl8139_get_stats;
- dev->set_multicast_list = rtl8139_set_rx_mode;
- dev->do_ioctl = netdev_ioctl;
- dev->ethtool_ops = &rtl8139_ethtool_ops;
- dev->tx_timeout = rtl8139_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = rtl8139_poll_controller;
-#endif
-
- /* note: the hardware is not capable of sg/csum/highdma, however
- * through the use of skb_copy_and_csum_dev we enable these
- * features
- */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
-
- dev->irq = pdev->irq;
-
- /* tp zeroed and aligned in alloc_etherdev */
- tp = netdev_priv(dev);
-
- /* note: tp->chipset set in rtl8139_init_board */
- tp->drv_flags = board_info[ent->driver_data].hw_flags;
- tp->mmio_addr = ioaddr;
- tp->msg_enable =
- (debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
- spin_lock_init (&tp->lock);
- spin_lock_init (&tp->rx_lock);
- init_waitqueue_head (&tp->thr_wait);
- init_completion (&tp->thr_exited);
- tp->mii.dev = dev;
- tp->mii.mdio_read = mdio_read;
- tp->mii.mdio_write = mdio_write;
- tp->mii.phy_id_mask = 0x3f;
- tp->mii.reg_num_mask = 0x1f;
-
- /* dev is fully set up and ready to use now */
- DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
- i = register_netdev (dev);
- if (i) goto err_out;
-
- pci_set_drvdata (pdev, dev);
-
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
- dev->name,
- board_info[ent->driver_data].name,
- dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
- dev->irq);
-
- printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
- dev->name, rtl_chip_info[tp->chipset].name);
-
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later, but
- takes too much time. */
-#ifdef CONFIG_8139TOO_8129
- if (tp->drv_flags & HAS_MII_XCVR) {
- int phy, phy_idx = 0;
- for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
- int mii_status = mdio_read(dev, phy, 1);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- u16 advertising = mdio_read(dev, phy, 4);
- tp->phys[phy_idx++] = phy;
- printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
- "advertising %4.4x.\n",
- dev->name, phy, mii_status, advertising);
- }
- }
- if (phy_idx == 0) {
- printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM "
- "transceiver.\n",
- dev->name);
- tp->phys[0] = 32;
- }
- } else
-#endif
- tp->phys[0] = 32;
- tp->mii.phy_id = tp->phys[0];
-
- /* The lower four bits are the media type. */
- option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
- if (option > 0) {
- tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
- tp->default_port = option & 0xFF;
- if (tp->default_port)
- tp->mii.force_media = 1;
- }
- if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
- tp->mii.full_duplex = full_duplex[board_idx];
- if (tp->mii.full_duplex) {
- printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
- /* Changing the MII-advertised media because might prevent
- re-connection. */
- tp->mii.force_media = 1;
- }
- if (tp->default_port) {
- printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
- (option & 0x20 ? 100 : 10),
- (option & 0x10 ? "full" : "half"));
- mdio_write(dev, tp->phys[0], 0,
- ((option & 0x20) ? 0x2000 : 0) | /* 100Mbps? */
- ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
- }
-
- /* Put the chip into low-power mode. */
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
-
- return 0;
-
-err_out:
- __rtl8139_cleanup_dev (dev);
- pci_disable_device (pdev);
- return i;
-}
-
-
-static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
-
- assert (dev != NULL);
-
- unregister_netdev (dev);
-
- __rtl8139_cleanup_dev (dev);
- pci_disable_device (pdev);
-}
-
-
-/* Serial EEPROM section. */
-
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
-#define EE_CS 0x08 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
-#define EE_WRITE_0 0x00
-#define EE_WRITE_1 0x02
-#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
-#define EE_ENB (0x80 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
- No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
-#define eeprom_delay() RTL_R32(Cfg9346)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD (5)
-#define EE_READ_CMD (6)
-#define EE_ERASE_CMD (7)
-
-static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- int read_cmd = location | (EE_READ_CMD << addr_len);
-
- RTL_W8 (Cfg9346, EE_ENB & ~EE_CS);
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
-
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- RTL_W8 (Cfg9346, EE_ENB | dataval);
- eeprom_delay ();
- RTL_W8 (Cfg9346, EE_ENB | dataval | EE_SHIFT_CLK);
- eeprom_delay ();
- }
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
-
- for (i = 16; i > 0; i--) {
- RTL_W8 (Cfg9346, EE_ENB | EE_SHIFT_CLK);
- eeprom_delay ();
- retval =
- (retval << 1) | ((RTL_R8 (Cfg9346) & EE_DATA_READ) ? 1 :
- 0);
- RTL_W8 (Cfg9346, EE_ENB);
- eeprom_delay ();
- }
-
- /* Terminate the EEPROM access. */
- RTL_W8 (Cfg9346, ~EE_CS);
- eeprom_delay ();
-
- return retval;
-}
-
-/* MII serial management: mostly bogus for now. */
-/* Read and write the MII management registers using software-generated
- serial MDIO protocol.
- The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues. */
-#define MDIO_DIR 0x80
-#define MDIO_DATA_OUT 0x04
-#define MDIO_DATA_IN 0x02
-#define MDIO_CLK 0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-
-#define mdio_delay() RTL_R8(Config4)
-
-
-static char mii_2_8139_map[8] = {
- BasicModeCtrl,
- BasicModeStatus,
- 0,
- 0,
- NWayAdvert,
- NWayLPAR,
- NWayExpansion,
- 0
-};
-
-
-#ifdef CONFIG_8139TOO_8129
-/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync (void __iomem *ioaddr)
-{
- int i;
-
- for (i = 32; i >= 0; i--) {
- RTL_W8 (Config4, MDIO_WRITE1);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_WRITE1 | MDIO_CLK);
- mdio_delay ();
- }
-}
-#endif
-
-static int mdio_read (struct net_device *dev, int phy_id, int location)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int retval = 0;
-#ifdef CONFIG_8139TOO_8129
- void __iomem *ioaddr = tp->mmio_addr;
- int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- int i;
-#endif
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- void __iomem *ioaddr = tp->mmio_addr;
- return location < 8 && mii_2_8139_map[location] ?
- RTL_R16 (mii_2_8139_map[location]) : 0;
- }
-
-#ifdef CONFIG_8139TOO_8129
- mdio_sync (ioaddr);
- /* Shift the read command bits out. */
- for (i = 15; i >= 0; i--) {
- int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
- RTL_W8 (Config4, MDIO_DIR | dataval);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_DIR | dataval | MDIO_CLK);
- mdio_delay ();
- }
-
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- RTL_W8 (Config4, 0);
- mdio_delay ();
- retval = (retval << 1) | ((RTL_R8 (Config4) & MDIO_DATA_IN) ? 1 : 0);
- RTL_W8 (Config4, MDIO_CLK);
- mdio_delay ();
- }
-#endif
-
- return (retval >> 1) & 0xffff;
-}
-
-
-static void mdio_write (struct net_device *dev, int phy_id, int location,
- int value)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-#ifdef CONFIG_8139TOO_8129
- void __iomem *ioaddr = tp->mmio_addr;
- int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
- int i;
-#endif
-
- if (phy_id > 31) { /* Really a 8139. Use internal registers. */
- void __iomem *ioaddr = tp->mmio_addr;
- if (location == 0) {
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W16 (BasicModeCtrl, value);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
- } else if (location < 8 && mii_2_8139_map[location])
- RTL_W16 (mii_2_8139_map[location], value);
- return;
- }
-
-#ifdef CONFIG_8139TOO_8129
- mdio_sync (ioaddr);
-
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval =
- (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
- RTL_W8 (Config4, dataval);
- mdio_delay ();
- RTL_W8 (Config4, dataval | MDIO_CLK);
- mdio_delay ();
- }
- /* Clear out extra bits. */
- for (i = 2; i > 0; i--) {
- RTL_W8 (Config4, 0);
- mdio_delay ();
- RTL_W8 (Config4, MDIO_CLK);
- mdio_delay ();
- }
-#endif
-}
-
-
-static int rtl8139_open (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int retval;
- void __iomem *ioaddr = tp->mmio_addr;
-
- retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
- if (retval)
- return retval;
-
- tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- &tp->tx_bufs_dma);
- tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- &tp->rx_ring_dma);
- if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
- free_irq(dev->irq, dev);
-
- if (tp->tx_bufs)
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- if (tp->rx_ring)
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
-
- return -ENOMEM;
-
- }
-
- tp->mii.full_duplex = tp->mii.force_media;
- tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
-
- rtl8139_init_ring (dev);
- rtl8139_hw_start (dev);
- netif_start_queue (dev);
-
- if (netif_msg_ifup(tp))
- printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
- " GP Pins %2.2x %s-duplex.\n",
- dev->name, pci_resource_start (tp->pci_dev, 1),
- dev->irq, RTL_R8 (MediaStatus),
- tp->mii.full_duplex ? "full" : "half");
-
- rtl8139_start_thread(dev);
-
- return 0;
-}
-
-
-static void rtl_check_media (struct net_device *dev, unsigned int init_media)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-
- if (tp->phys[0] >= 0) {
- mii_check_media(&tp->mii, netif_msg_link(tp), init_media);
- }
-}
-
-/* Start the hardware at open or resume. */
-static void rtl8139_hw_start (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u32 i;
- u8 tmp;
-
- /* Bring old chips out of low-power mode. */
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'R');
-
- rtl8139_chip_reset (ioaddr);
-
- /* unlock Config[01234] and BMCR register writes */
- RTL_W8_F (Cfg9346, Cfg9346_Unlock);
- /* Restore our idea of the MAC address. */
- RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
-
- /* Must enable Tx/Rx before setting transfer thresholds! */
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
- RTL_W32 (RxConfig, tp->rx_config);
- RTL_W32 (TxConfig, rtl8139_tx_config);
-
- tp->cur_rx = 0;
-
- rtl_check_media (dev, 1);
-
- if (tp->chipset >= CH_8139B) {
- /* Disable magic packet scanning, which is enabled
- * when PM is enabled in Config1. It can be reenabled
- * via ETHTOOL_SWOL if desired. */
- RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);
- }
-
- DPRINTK("init buffer addresses\n");
-
- /* Lock Config[01234] and BMCR register writes */
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- /* init Rx ring buffer DMA address */
- RTL_W32_F (RxBuf, tp->rx_ring_dma);
-
- /* init Tx buffer DMA addresses */
- for (i = 0; i < NUM_TX_DESC; i++)
- RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs));
-
- RTL_W32 (RxMissed, 0);
-
- rtl8139_set_rx_mode (dev);
-
- /* no early-rx interrupts */
- RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);
-
- /* make sure RxTx has started */
- tmp = RTL_R8 (ChipCmd);
- if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- /* Enable all known interrupts by setting the interrupt mask. */
- RTL_W16 (IntrMask, rtl8139_intr_mask);
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void rtl8139_init_ring (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- int i;
-
- tp->cur_rx = 0;
- tp->cur_tx = 0;
- tp->dirty_tx = 0;
-
- for (i = 0; i < NUM_TX_DESC; i++)
- tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
-}
-
-
-/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
-static int next_tick = 3 * HZ;
-
-#ifndef CONFIG_8139TOO_TUNE_TWISTER
-static inline void rtl8139_tune_twister (struct net_device *dev,
- struct rtl8139_private *tp) {}
-#else
-enum TwisterParamVals {
- PARA78_default = 0x78fa8388,
- PARA7c_default = 0xcb38de43, /* param[0][3] */
- PARA7c_xxx = 0xcb38de43,
-};
-
-static const unsigned long param[4][4] = {
- {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
- {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
-};
-
-static void rtl8139_tune_twister (struct net_device *dev,
- struct rtl8139_private *tp)
-{
- int linkcase;
- void __iomem *ioaddr = tp->mmio_addr;
-
- /* This is a complicated state machine to configure the "twister" for
- impedance/echos based on the cable length.
- All of this is magic and undocumented.
- */
- switch (tp->twistie) {
- case 1:
- if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
- /* We have link beat, let us tune the twister. */
- RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
- tp->twistie = 2; /* Change to state 2. */
- next_tick = HZ / 10;
- } else {
- /* Just put in some reasonable defaults for when beat returns. */
- RTL_W16 (CSCR, CSCR_LinkDownCmd);
- RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */
- RTL_W32 (PARA78, PARA78_default);
- RTL_W32 (PARA7c, PARA7c_default);
- tp->twistie = 0; /* Bail from future actions. */
- }
- break;
- case 2:
- /* Read how long it took to hear the echo. */
- linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
- if (linkcase == 0x7000)
- tp->twist_row = 3;
- else if (linkcase == 0x3000)
- tp->twist_row = 2;
- else if (linkcase == 0x1000)
- tp->twist_row = 1;
- else
- tp->twist_row = 0;
- tp->twist_col = 0;
- tp->twistie = 3; /* Change to state 2. */
- next_tick = HZ / 10;
- break;
- case 3:
- /* Put out four tuning parameters, one per 100msec. */
- if (tp->twist_col == 0)
- RTL_W16 (FIFOTMS, 0);
- RTL_W32 (PARA7c, param[(int) tp->twist_row]
- [(int) tp->twist_col]);
- next_tick = HZ / 10;
- if (++tp->twist_col >= 4) {
- /* For short cables we are done.
- For long cables (row == 3) check for mistune. */
- tp->twistie =
- (tp->twist_row == 3) ? 4 : 0;
- }
- break;
- case 4:
- /* Special case for long cables: check for mistune. */
- if ((RTL_R16 (CSCR) &
- CSCR_LinkStatusBits) == 0x7000) {
- tp->twistie = 0;
- break;
- } else {
- RTL_W32 (PARA7c, 0xfb38de03);
- tp->twistie = 5;
- next_tick = HZ / 10;
- }
- break;
- case 5:
- /* Retune for shorter cable (column 2). */
- RTL_W32 (FIFOTMS, 0x20);
- RTL_W32 (PARA78, PARA78_default);
- RTL_W32 (PARA7c, PARA7c_default);
- RTL_W32 (FIFOTMS, 0x00);
- tp->twist_row = 2;
- tp->twist_col = 0;
- tp->twistie = 3;
- next_tick = HZ / 10;
- break;
-
- default:
- /* do nothing */
- break;
- }
-}
-#endif /* CONFIG_8139TOO_TUNE_TWISTER */
-
-static inline void rtl8139_thread_iter (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr)
-{
- int mii_lpa;
-
- mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
-
- if (!tp->mii.force_media && mii_lpa != 0xffff) {
- int duplex = (mii_lpa & LPA_100FULL)
- || (mii_lpa & 0x01C0) == 0x0040;
- if (tp->mii.full_duplex != duplex) {
- tp->mii.full_duplex = duplex;
-
- if (mii_lpa) {
- printk (KERN_INFO
- "%s: Setting %s-duplex based on MII #%d link"
- " partner ability of %4.4x.\n",
- dev->name,
- tp->mii.full_duplex ? "full" : "half",
- tp->phys[0], mii_lpa);
- } else {
- printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
- dev->name);
- }
-#if 0
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-#endif
- }
- }
-
- next_tick = HZ * 60;
-
- rtl8139_tune_twister (dev, tp);
-
- DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
- dev->name, RTL_R16 (NWayLPAR));
- DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n",
- dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));
- DPRINTK ("%s: Chip config %2.2x %2.2x.\n",
- dev->name, RTL_R8 (Config0),
- RTL_R8 (Config1));
-}
-
-static int rtl8139_thread (void *data)
-{
- struct net_device *dev = data;
- struct rtl8139_private *tp = netdev_priv(dev);
- unsigned long timeout;
-
- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
- while (1) {
- timeout = next_tick;
- do {
- timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
- /* make swsusp happy with our thread */
- try_to_freeze();
- } while (!signal_pending (current) && (timeout > 0));
-
- if (signal_pending (current)) {
- flush_signals(current);
- }
-
- if (tp->time_to_die)
- break;
-
- if (rtnl_lock_interruptible ())
- break;
- rtl8139_thread_iter (dev, tp, tp->mmio_addr);
- rtnl_unlock ();
- }
-
- complete_and_exit (&tp->thr_exited, 0);
-}
-
-static void rtl8139_start_thread(struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
-
- tp->thr_pid = -1;
- tp->twistie = 0;
- tp->time_to_die = 0;
- if (tp->chipset == CH_8139_K)
- tp->twistie = 1;
- else if (tp->drv_flags & HAS_LNK_CHNG)
- return;
-
- tp->thr_pid = kernel_thread(rtl8139_thread, dev, CLONE_FS|CLONE_FILES);
- if (tp->thr_pid < 0) {
- printk (KERN_WARNING "%s: unable to start kernel thread\n",
- dev->name);
- }
-}
-
-static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
-{
- tp->cur_tx = 0;
- tp->dirty_tx = 0;
-
- /* XXX account for unsent Tx packets in tp->stats.tx_dropped */
-}
-
-
-static void rtl8139_tx_timeout (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int i;
- u8 tmp8;
- unsigned long flags;
-
- printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "
- "media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),
- RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));
- /* Emit info to figure out what went wrong. */
- printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n",
- dev->name, tp->cur_tx, tp->dirty_tx);
- for (i = 0; i < NUM_TX_DESC; i++)
- printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n",
- dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
- i == tp->dirty_tx % NUM_TX_DESC ?
- " (queue head)" : "");
-
- tp->xstats.tx_timeouts++;
-
- /* disable Tx ASAP, if not already */
- tmp8 = RTL_R8 (ChipCmd);
- if (tmp8 & CmdTxEnb)
- RTL_W8 (ChipCmd, CmdRxEnb);
-
- spin_lock(&tp->rx_lock);
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16 (IntrMask, 0x0000);
-
- /* Stop a shared interrupt from scavenging while we are. */
- spin_lock_irqsave (&tp->lock, flags);
- rtl8139_tx_clear (tp);
- spin_unlock_irqrestore (&tp->lock, flags);
-
- /* ...and finally, reset everything */
- if (netif_running(dev)) {
- rtl8139_hw_start (dev);
- netif_wake_queue (dev);
- }
- spin_unlock(&tp->rx_lock);
-}
-
-
-static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned int entry;
- unsigned int len = skb->len;
-
- /* Calculate the next Tx descriptor entry. */
- entry = tp->cur_tx % NUM_TX_DESC;
-
- /* Note: the chip doesn't have auto-pad! */
- if (likely(len < TX_BUF_SIZE)) {
- if (len < ETH_ZLEN)
- memset(tp->tx_buf[entry], 0, ETH_ZLEN);
- skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
- dev_kfree_skb(skb);
- } else {
- dev_kfree_skb(skb);
- tp->stats.tx_dropped++;
- return 0;
- }
-
- spin_lock_irq(&tp->lock);
- RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
- tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
-
- dev->trans_start = jiffies;
-
- tp->cur_tx++;
- wmb();
-
- if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
- netif_stop_queue (dev);
- spin_unlock_irq(&tp->lock);
-
- if (netif_msg_tx_queued(tp))
- printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
- dev->name, len, entry);
-
- return 0;
-}
-
-
-static void rtl8139_tx_interrupt (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr)
-{
- unsigned long dirty_tx, tx_left;
-
- assert (dev != NULL);
- assert (ioaddr != NULL);
-
- dirty_tx = tp->dirty_tx;
- tx_left = tp->cur_tx - dirty_tx;
- while (tx_left > 0) {
- int entry = dirty_tx % NUM_TX_DESC;
- int txstatus;
-
- txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
-
- if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
- break; /* It still hasn't been Txed */
-
- /* Note: TxCarrierLost is always asserted at 100mbps. */
- if (txstatus & (TxOutOfWindow | TxAborted)) {
- /* There was an major error, log it. */
- if (netif_msg_tx_err(tp))
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, txstatus);
- tp->stats.tx_errors++;
- if (txstatus & TxAborted) {
- tp->stats.tx_aborted_errors++;
- RTL_W32 (TxConfig, TxClearAbt);
- RTL_W16 (IntrStatus, TxErr);
- wmb();
- }
- if (txstatus & TxCarrierLost)
- tp->stats.tx_carrier_errors++;
- if (txstatus & TxOutOfWindow)
- tp->stats.tx_window_errors++;
- } else {
- if (txstatus & TxUnderrun) {
- /* Add 64 to the Tx FIFO threshold. */
- if (tp->tx_flag < 0x00300000)
- tp->tx_flag += 0x00020000;
- tp->stats.tx_fifo_errors++;
- }
- tp->stats.collisions += (txstatus >> 24) & 15;
- tp->stats.tx_bytes += txstatus & 0x7ff;
- tp->stats.tx_packets++;
- }
-
- dirty_tx++;
- tx_left--;
- }
-
-#ifndef RTL8139_NDEBUG
- if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
- printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
- dev->name, dirty_tx, tp->cur_tx);
- dirty_tx += NUM_TX_DESC;
- }
-#endif /* RTL8139_NDEBUG */
-
- /* only wake the queue if we did work, and the queue is stopped */
- if (tp->dirty_tx != dirty_tx) {
- tp->dirty_tx = dirty_tx;
- mb();
- netif_wake_queue (dev);
- }
-}
-
-
-/* TODO: clean this up! Rx reset need not be this intensive */
-static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
- struct rtl8139_private *tp, void __iomem *ioaddr)
-{
- u8 tmp8;
-#ifdef CONFIG_8139_OLD_RX_RESET
- int tmp_work;
-#endif
-
- if (netif_msg_rx_err (tp))
- printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
- dev->name, rx_status);
- tp->stats.rx_errors++;
- if (!(rx_status & RxStatusOK)) {
- if (rx_status & RxTooLong) {
- DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
- dev->name, rx_status);
- /* A.C.: The chip hangs here. */
- }
- if (rx_status & (RxBadSymbol | RxBadAlign))
- tp->stats.rx_frame_errors++;
- if (rx_status & (RxRunt | RxTooLong))
- tp->stats.rx_length_errors++;
- if (rx_status & RxCRCErr)
- tp->stats.rx_crc_errors++;
- } else {
- tp->xstats.rx_lost_in_ring++;
- }
-
-#ifndef CONFIG_8139_OLD_RX_RESET
- tmp8 = RTL_R8 (ChipCmd);
- RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
- RTL_W8 (ChipCmd, tmp8);
- RTL_W32 (RxConfig, tp->rx_config);
- tp->cur_rx = 0;
-#else
- /* Reset the receiver, based on RealTek recommendation. (Bug?) */
-
- /* disable receive */
- RTL_W8_F (ChipCmd, CmdTxEnb);
- tmp_work = 200;
- while (--tmp_work > 0) {
- udelay(1);
- tmp8 = RTL_R8 (ChipCmd);
- if (!(tmp8 & CmdRxEnb))
- break;
- }
- if (tmp_work <= 0)
- printk (KERN_WARNING PFX "rx stop wait too long\n");
- /* restart receive */
- tmp_work = 200;
- while (--tmp_work > 0) {
- RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
- udelay(1);
- tmp8 = RTL_R8 (ChipCmd);
- if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
- break;
- }
- if (tmp_work <= 0)
- printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
-
- /* and reinitialize all rx related registers */
- RTL_W8_F (Cfg9346, Cfg9346_Unlock);
- /* Must enable Tx/Rx before setting transfer thresholds! */
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
- RTL_W32 (RxConfig, tp->rx_config);
- tp->cur_rx = 0;
-
- DPRINTK("init buffer addresses\n");
-
- /* Lock Config[01234] and BMCR register writes */
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- /* init Rx ring buffer DMA address */
- RTL_W32_F (RxBuf, tp->rx_ring_dma);
-
- /* A.C.: Reset the multicast list. */
- __set_rx_mode (dev);
-#endif
-}
-
-#if RX_BUF_IDX == 3
-static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,
- u32 offset, unsigned int size)
-{
- u32 left = RX_BUF_LEN - offset;
-
- if (size > left) {
- memcpy(skb->data, ring + offset, left);
- memcpy(skb->data+left, ring, size - left);
- } else
- memcpy(skb->data, ring + offset, size);
-}
-#endif
-
-static void rtl8139_isr_ack(struct rtl8139_private *tp)
-{
- void __iomem *ioaddr = tp->mmio_addr;
- u16 status;
-
- status = RTL_R16 (IntrStatus) & RxAckBits;
-
- /* Clear out errors and receive interrupts */
- if (likely(status != 0)) {
- if (unlikely(status & (RxFIFOOver | RxOverflow))) {
- tp->stats.rx_errors++;
- if (status & RxFIFOOver)
- tp->stats.rx_fifo_errors++;
- }
- RTL_W16_F (IntrStatus, RxAckBits);
- }
-}
-
-static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,
- int budget)
-{
- void __iomem *ioaddr = tp->mmio_addr;
- int received = 0;
- unsigned char *rx_ring = tp->rx_ring;
- unsigned int cur_rx = tp->cur_rx;
- unsigned int rx_size = 0;
-
- DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
-
- while (netif_running(dev) && received < budget
- && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
- u32 ring_offset = cur_rx % RX_BUF_LEN;
- u32 rx_status;
- unsigned int pkt_size;
- struct sk_buff *skb;
-
- rmb();
-
- /* read size+status of next frame from DMA ring buffer */
- rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
- rx_size = rx_status >> 16;
- pkt_size = rx_size - 4;
-
- if (netif_msg_rx_status(tp))
- printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x,"
- " cur %4.4x.\n", dev->name, rx_status,
- rx_size, cur_rx);
-#if RTL8139_DEBUG > 2
- {
- int i;
- DPRINTK ("%s: Frame contents ", dev->name);
- for (i = 0; i < 70; i++)
- printk (" %2.2x",
- rx_ring[ring_offset + i]);
- printk (".\n");
- }
-#endif
-
- /* Packet copy from FIFO still in progress.
- * Theoretically, this should never happen
- * since EarlyRx is disabled.
- */
- if (unlikely(rx_size == 0xfff0)) {
- if (!tp->fifo_copy_timeout)
- tp->fifo_copy_timeout = jiffies + 2;
- else if (time_after(jiffies, tp->fifo_copy_timeout)) {
- DPRINTK ("%s: hung FIFO. Reset.", dev->name);
- rx_size = 0;
- goto no_early_rx;
- }
- if (netif_msg_intr(tp)) {
- printk(KERN_DEBUG "%s: fifo copy in progress.",
- dev->name);
- }
- tp->xstats.early_rx++;
- break;
- }
-
-no_early_rx:
- tp->fifo_copy_timeout = 0;
-
- /* If Rx err or invalid rx_size/rx_status received
- * (which happens if we get lost in the ring),
- * Rx process gets reset, so we abort any further
- * Rx processing.
- */
- if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
- (rx_size < 8) ||
- (!(rx_status & RxStatusOK)))) {
- rtl8139_rx_err (rx_status, dev, tp, ioaddr);
- received = -1;
- goto out;
- }
-
- /* Malloc up new buffer, compatible with net-2e. */
- /* Omit the four octet CRC from the length. */
-
- skb = dev_alloc_skb (pkt_size + 2);
- if (likely(skb)) {
- skb->dev = dev;
- skb_reserve (skb, 2); /* 16 byte align the IP fields. */
-#if RX_BUF_IDX == 3
- wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
-#else
- eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
-#endif
- skb_put (skb, pkt_size);
-
- skb->protocol = eth_type_trans (skb, dev);
-
- dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
-
- netif_receive_skb (skb);
- } else {
- if (net_ratelimit())
- printk (KERN_WARNING
- "%s: Memory squeeze, dropping packet.\n",
- dev->name);
- tp->stats.rx_dropped++;
- }
- received++;
-
- cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
- RTL_W16 (RxBufPtr, (u16) (cur_rx - 16));
-
- rtl8139_isr_ack(tp);
- }
-
- if (unlikely(!received || rx_size == 0xfff0))
- rtl8139_isr_ack(tp);
-
-#if RTL8139_DEBUG > 1
- DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
- " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
- RTL_R16 (RxBufAddr),
- RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));
-#endif
-
- tp->cur_rx = cur_rx;
-
- /*
- * The receive buffer should be mostly empty.
- * Tell NAPI to reenable the Rx irq.
- */
- if (tp->fifo_copy_timeout)
- received = budget;
-
-out:
- return received;
-}
-
-
-static void rtl8139_weird_interrupt (struct net_device *dev,
- struct rtl8139_private *tp,
- void __iomem *ioaddr,
- int status, int link_changed)
-{
- DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
- dev->name, status);
-
- assert (dev != NULL);
- assert (tp != NULL);
- assert (ioaddr != NULL);
-
- /* Update the error count. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- if ((status & RxUnderrun) && link_changed &&
- (tp->drv_flags & HAS_LNK_CHNG)) {
- rtl_check_media(dev, 0);
- status &= ~RxUnderrun;
- }
-
- if (status & (RxUnderrun | RxErr))
- tp->stats.rx_errors++;
-
- if (status & PCSTimeout)
- tp->stats.rx_length_errors++;
- if (status & RxUnderrun)
- tp->stats.rx_fifo_errors++;
- if (status & PCIErr) {
- u16 pci_cmd_status;
- pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
- pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status);
-
- printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
- dev->name, pci_cmd_status);
- }
-}
-
-static int rtl8139_poll(struct net_device *dev, int *budget)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int orig_budget = min(*budget, dev->quota);
- int done = 1;
-
- spin_lock(&tp->rx_lock);
- if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
- int work_done;
-
- work_done = rtl8139_rx(dev, tp, orig_budget);
- if (likely(work_done > 0)) {
- *budget -= work_done;
- dev->quota -= work_done;
- done = (work_done < orig_budget);
- }
- }
-
- if (done) {
- /*
- * Order is important since data can get interrupted
- * again when we think we are done.
- */
- local_irq_disable();
- RTL_W16_F(IntrMask, rtl8139_intr_mask);
- __netif_rx_complete(dev);
- local_irq_enable();
- }
- spin_unlock(&tp->rx_lock);
-
- return !done;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *) dev_instance;
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u16 status, ackstat;
- int link_changed = 0; /* avoid bogus "uninit" warning */
- int handled = 0;
-
- spin_lock (&tp->lock);
- status = RTL_R16 (IntrStatus);
-
- /* shared irq? */
- if (unlikely((status & rtl8139_intr_mask) == 0))
- goto out;
-
- handled = 1;
-
- /* h/w no longer present (hotplug?) or major error, bail */
- if (unlikely(status == 0xFFFF))
- goto out;
-
- /* close possible race's with dev_close */
- if (unlikely(!netif_running(dev))) {
- RTL_W16 (IntrMask, 0);
- goto out;
- }
-
- /* Acknowledge all of the current interrupt sources ASAP, but
- an first get an additional status bit from CSCR. */
- if (unlikely(status & RxUnderrun))
- link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
-
- ackstat = status & ~(RxAckBits | TxErr);
- if (ackstat)
- RTL_W16 (IntrStatus, ackstat);
-
- /* Receive packets are processed by poll routine.
- If not running start it now. */
- if (status & RxAckBits){
- if (netif_rx_schedule_prep(dev)) {
- RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
- __netif_rx_schedule (dev);
- }
- }
-
- /* Check uncommon events with one test. */
- if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr)))
- rtl8139_weird_interrupt (dev, tp, ioaddr,
- status, link_changed);
-
- if (status & (TxOK | TxErr)) {
- rtl8139_tx_interrupt (dev, tp, ioaddr);
- if (status & TxErr)
- RTL_W16 (IntrStatus, TxErr);
- }
- out:
- spin_unlock (&tp->lock);
-
- DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
- return IRQ_RETVAL(handled);
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void rtl8139_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- rtl8139_interrupt(dev->irq, dev, NULL);
- enable_irq(dev->irq);
-}
-#endif
-
-static int rtl8139_close (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- int ret = 0;
- unsigned long flags;
-
- netif_stop_queue (dev);
-
- if (tp->thr_pid >= 0) {
- tp->time_to_die = 1;
- wmb();
- ret = kill_proc (tp->thr_pid, SIGTERM, 1);
- if (ret) {
- printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
- return ret;
- }
- wait_for_completion (&tp->thr_exited);
- }
-
- if (netif_msg_ifdown(tp))
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
-
- spin_lock_irqsave (&tp->lock, flags);
-
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8 (ChipCmd, 0);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16 (IntrMask, 0);
-
- /* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
-
- synchronize_irq (dev->irq); /* racy, but that's ok here */
- free_irq (dev->irq, dev);
-
- rtl8139_tx_clear (tp);
-
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
- tp->rx_ring = NULL;
- tp->tx_bufs = NULL;
-
- /* Green! Put the chip in low-power mode. */
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
-
- if (rtl_chip_info[tp->chipset].flags & HasHltClk)
- RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
-
- return 0;
-}
-
-
-/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to
- kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
- other threads or interrupts aren't messing with the 8139. */
-static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- void __iomem *ioaddr = np->mmio_addr;
-
- spin_lock_irq(&np->lock);
- if (rtl_chip_info[np->chipset].flags & HasLWake) {
- u8 cfg3 = RTL_R8 (Config3);
- u8 cfg5 = RTL_R8 (Config5);
-
- wol->supported = WAKE_PHY | WAKE_MAGIC
- | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
-
- wol->wolopts = 0;
- if (cfg3 & Cfg3_LinkUp)
- wol->wolopts |= WAKE_PHY;
- if (cfg3 & Cfg3_Magic)
- wol->wolopts |= WAKE_MAGIC;
- /* (KON)FIXME: See how netdev_set_wol() handles the
- following constants. */
- if (cfg5 & Cfg5_UWF)
- wol->wolopts |= WAKE_UCAST;
- if (cfg5 & Cfg5_MWF)
- wol->wolopts |= WAKE_MCAST;
- if (cfg5 & Cfg5_BWF)
- wol->wolopts |= WAKE_BCAST;
- }
- spin_unlock_irq(&np->lock);
-}
-
-
-/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes
- that wol points to kernel memory and other threads or interrupts
- aren't messing with the 8139. */
-static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- void __iomem *ioaddr = np->mmio_addr;
- u32 support;
- u8 cfg3, cfg5;
-
- support = ((rtl_chip_info[np->chipset].flags & HasLWake)
- ? (WAKE_PHY | WAKE_MAGIC
- | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)
- : 0);
- if (wol->wolopts & ~support)
- return -EINVAL;
-
- spin_lock_irq(&np->lock);
- cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic);
- if (wol->wolopts & WAKE_PHY)
- cfg3 |= Cfg3_LinkUp;
- if (wol->wolopts & WAKE_MAGIC)
- cfg3 |= Cfg3_Magic;
- RTL_W8 (Cfg9346, Cfg9346_Unlock);
- RTL_W8 (Config3, cfg3);
- RTL_W8 (Cfg9346, Cfg9346_Lock);
-
- cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF);
- /* (KON)FIXME: These are untested. We may have to set the
- CRC0, Wakeup0 and LSBCRC0 registers too, but I have no
- documentation. */
- if (wol->wolopts & WAKE_UCAST)
- cfg5 |= Cfg5_UWF;
- if (wol->wolopts & WAKE_MCAST)
- cfg5 |= Cfg5_MWF;
- if (wol->wolopts & WAKE_BCAST)
- cfg5 |= Cfg5_BWF;
- RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */
- spin_unlock_irq(&np->lock);
-
- return 0;
-}
-
-static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(np->pci_dev));
- info->regdump_len = np->regs_len;
-}
-
-static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- spin_lock_irq(&np->lock);
- mii_ethtool_gset(&np->mii, cmd);
- spin_unlock_irq(&np->lock);
- return 0;
-}
-
-static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- int rc;
- spin_lock_irq(&np->lock);
- rc = mii_ethtool_sset(&np->mii, cmd);
- spin_unlock_irq(&np->lock);
- return rc;
-}
-
-static int rtl8139_nway_reset(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return mii_nway_restart(&np->mii);
-}
-
-static u32 rtl8139_get_link(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return mii_link_ok(&np->mii);
-}
-
-static u32 rtl8139_get_msglevel(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return np->msg_enable;
-}
-
-static void rtl8139_set_msglevel(struct net_device *dev, u32 datum)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- np->msg_enable = datum;
-}
-
-/* TODO: we are too slack to do reg dumping for pio, for now */
-#ifdef CONFIG_8139TOO_PIO
-#define rtl8139_get_regs_len NULL
-#define rtl8139_get_regs NULL
-#else
-static int rtl8139_get_regs_len(struct net_device *dev)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- return np->regs_len;
-}
-
-static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
-{
- struct rtl8139_private *np = netdev_priv(dev);
-
- regs->version = RTL_REGS_VER;
-
- spin_lock_irq(&np->lock);
- memcpy_fromio(regbuf, np->mmio_addr, regs->len);
- spin_unlock_irq(&np->lock);
-}
-#endif /* CONFIG_8139TOO_MMIO */
-
-static int rtl8139_get_stats_count(struct net_device *dev)
-{
- return RTL_NUM_STATS;
-}
-
-static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
-{
- struct rtl8139_private *np = netdev_priv(dev);
-
- data[0] = np->xstats.early_rx;
- data[1] = np->xstats.tx_buf_mapped;
- data[2] = np->xstats.tx_timeouts;
- data[3] = np->xstats.rx_lost_in_ring;
-}
-
-static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
-{
- memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
-}
-
-static struct ethtool_ops rtl8139_ethtool_ops = {
- .get_drvinfo = rtl8139_get_drvinfo,
- .get_settings = rtl8139_get_settings,
- .set_settings = rtl8139_set_settings,
- .get_regs_len = rtl8139_get_regs_len,
- .get_regs = rtl8139_get_regs,
- .nway_reset = rtl8139_nway_reset,
- .get_link = rtl8139_get_link,
- .get_msglevel = rtl8139_get_msglevel,
- .set_msglevel = rtl8139_set_msglevel,
- .get_wol = rtl8139_get_wol,
- .set_wol = rtl8139_set_wol,
- .get_strings = rtl8139_get_strings,
- .get_stats_count = rtl8139_get_stats_count,
- .get_ethtool_stats = rtl8139_get_ethtool_stats,
-};
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct rtl8139_private *np = netdev_priv(dev);
- int rc;
-
- if (!netif_running(dev))
- return -EINVAL;
-
- spin_lock_irq(&np->lock);
- rc = generic_mii_ioctl(&np->mii, if_mii(rq), cmd, NULL);
- spin_unlock_irq(&np->lock);
-
- return rc;
-}
-
-
-static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- if (netif_running(dev)) {
- spin_lock_irqsave (&tp->lock, flags);
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
- spin_unlock_irqrestore (&tp->lock, flags);
- }
-
- return &tp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- This routine is not state sensitive and need not be SMP locked. */
-
-static void __set_rx_mode (struct net_device *dev)
-{
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
- u32 tmp;
-
- DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
- dev->name, dev->flags, RTL_R32 (RxConfig));
-
- /* Note: do not reorder, GCC is clever about common statements. */
- if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
- rx_mode =
- AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
- AcceptAllPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else if ((dev->mc_count > multicast_filter_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
- } else {
- struct dev_mc_list *mclist;
- rx_mode = AcceptBroadcast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next) {
- int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- rx_mode |= AcceptMulticast;
- }
- }
-
- /* We can safely update without stopping the chip. */
- tmp = rtl8139_rx_config | rx_mode;
- if (tp->rx_config != tmp) {
- RTL_W32_F (RxConfig, tmp);
- tp->rx_config = tmp;
- }
- RTL_W32_F (MAR0 + 0, mc_filter[0]);
- RTL_W32_F (MAR0 + 4, mc_filter[1]);
-}
-
-static void rtl8139_set_rx_mode (struct net_device *dev)
-{
- unsigned long flags;
- struct rtl8139_private *tp = netdev_priv(dev);
-
- spin_lock_irqsave (&tp->lock, flags);
- __set_rx_mode(dev);
- spin_unlock_irqrestore (&tp->lock, flags);
-}
-
-#ifdef CONFIG_PM
-
-static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
- struct rtl8139_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- pci_save_state (pdev);
-
- if (!netif_running (dev))
- return 0;
-
- netif_device_detach (dev);
-
- spin_lock_irqsave (&tp->lock, flags);
-
- /* Disable interrupts, stop Tx and Rx. */
- RTL_W16 (IntrMask, 0);
- RTL_W8 (ChipCmd, 0);
-
- /* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
- RTL_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
-
- pci_set_power_state (pdev, PCI_D3hot);
-
- return 0;
-}
-
-
-static int rtl8139_resume (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata (pdev);
-
- pci_restore_state (pdev);
- if (!netif_running (dev))
- return 0;
- pci_set_power_state (pdev, PCI_D0);
- rtl8139_init_ring (dev);
- rtl8139_hw_start (dev);
- netif_device_attach (dev);
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-
-static struct pci_driver rtl8139_pci_driver = {
- .name = DRV_NAME,
- .id_table = rtl8139_pci_tbl,
- .probe = rtl8139_init_one,
- .remove = __devexit_p(rtl8139_remove_one),
-#ifdef CONFIG_PM
- .suspend = rtl8139_suspend,
- .resume = rtl8139_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init rtl8139_init_module (void)
-{
- /* when we're a module, we always print a version message,
- * even if no 8139 board is found.
- */
-#ifdef MODULE
- printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
-#endif
-
- return pci_module_init (&rtl8139_pci_driver);
-}
-
-
-static void __exit rtl8139_cleanup_module (void)
-{
- pci_unregister_driver (&rtl8139_pci_driver);
-}
-
-
-module_init(rtl8139_init_module);
-module_exit(rtl8139_cleanup_module);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/EtherCAT_dev.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Oeffentliche EtherCAT-Schnittstellen fuer EtherCAT-Geraetetreiber.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _ETHERCAT_DEVICE_H_
+#define _ETHERCAT_DEVICE_H_
+
+#include <linux/netdevice.h>
+
+/*****************************************************************************/
+
+struct ec_device;
+
+typedef struct ec_device ec_device_t;
+
+/*****************************************************************************/
+
+typedef enum
+{
+ EC_DEVICE_STATE_READY, EC_DEVICE_STATE_SENT, EC_DEVICE_STATE_RECEIVED,
+ EC_DEVICE_STATE_TIMEOUT, EC_DEVICE_STATE_ERROR
+}
+ec_device_state_t;
+
+/*****************************************************************************/
+
+ec_device_t *EtherCAT_dev_register(unsigned int, struct net_device *,
+ irqreturn_t (*)(int, void *,
+ struct pt_regs *),
+ struct module *);
+void EtherCAT_dev_unregister(unsigned int);
+int EtherCAT_dev_is_ec(ec_device_t *, struct net_device *);
+void EtherCAT_dev_state(ec_device_t *, ec_device_state_t);
+int EtherCAT_dev_receive(ec_device_t *, void *, unsigned int);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/EtherCAT_rt.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Oeffentliche EtherCAT-Schnittstellen fuer Echtzeitprozesse.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _ETHERCAT_RT_H_
+#define _ETHERCAT_RT_H_
+
+/*****************************************************************************/
+
+struct ec_master;
+typedef struct ec_master ec_master_t;
+
+/*****************************************************************************/
+
+ec_master_t *EtherCAT_rt_request_master(unsigned int master_index);
+
+void EtherCAT_rt_release_master(ec_master_t *master);
+
+void *EtherCAT_rt_register_slave(ec_master_t *master, unsigned int slave_index,
+ const char *vendor_name,
+ const char *product_name);
+
+int EtherCAT_rt_activate_slaves(ec_master_t *master);
+
+int EtherCAT_rt_deactivate_slaves(ec_master_t *master);
+
+int EtherCAT_rt_domain_cycle(ec_master_t *master, unsigned int domain,
+ unsigned int timeout_us);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/Makefile Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,46 @@
+#------------------------------------------------------------------------------
+#
+# Makefile
+#
+# IgH EtherCAT-Treiber
+#
+# $Id$
+#
+#------------------------------------------------------------------------------
+
+ifneq ($(KERNELRELEASE),)
+
+#------------------------------------------------------------------------------
+# Kbuild-Abschnitt
+
+obj-m := ec_master.o
+
+ec_master-objs := module.o master.o device.o slave.o command.o types.o domain.o
+
+REV = `svnversion $(src)`
+DATE = `date`
+
+EXTRA_CFLAGS = -DEC_REV="$(REV)" -DEC_USER="$(USER)" -DEC_DATE="$(DATE)"
+
+#------------------------------------------------------------------------------
+
+else
+
+#------------------------------------------------------------------------------
+# Default-Abschnitt
+
+ifneq ($(wildcard ethercat.conf),)
+include ethercat.conf
+else
+KERNELDIR = /lib/modules/`uname -r`/build
+endif
+
+modules:
+ $(MAKE) -C $(KERNELDIR) M=`pwd` modules
+
+clean:
+ $(MAKE) -C $(KERNELDIR) M=`pwd` clean
+
+#------------------------------------------------------------------------------
+
+endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/command.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * c o m m a n d . c
+ *
+ * Methoden für ein EtherCAT-Kommando.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/slab.h>
+
+#include "command.h"
+
+/*****************************************************************************/
+
+/**
+ Kommando-Konstruktor.
+
+ Initialisiert alle Variablen innerhalb des Kommandos auf die
+ Default-Werte.
+
+ @param cmd Zeiger auf das zu initialisierende Kommando.
+*/
+
+void ec_command_init(ec_command_t *cmd)
+{
+ cmd->type = EC_COMMAND_NONE;
+ cmd->address.logical = 0x00000000;
+ cmd->data_length = 0;
+ cmd->state = EC_COMMAND_STATE_READY;
+ cmd->index = 0;
+ cmd->working_counter = 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Kommando-Destruktor.
+
+ Setzt alle Attribute auf den Anfangswert zurueck.
+
+ @param cmd Zeiger auf das zu initialisierende Kommando.
+*/
+
+void ec_command_clear(ec_command_t *cmd)
+{
+ ec_command_init(cmd);
+}
+
+/*****************************************************************************/
+
+#define EC_FUNC_HEADER \
+ ec_command_init(cmd)
+
+#define EC_FUNC_WRITE_FOOTER \
+ cmd->data_length = length; \
+ memcpy(cmd->data, data, length);
+
+#define EC_FUNC_READ_FOOTER \
+ cmd->data_length = length;
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-NPRD-Kommando.
+
+ @param cmd Zeiger auf das Kommando
+ @param node_address Adresse des Knotens (Slaves)
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu lesenden Daten
+*/
+
+void ec_command_read(ec_command_t *cmd, unsigned short node_address,
+ unsigned short offset, unsigned int length)
+{
+ if (unlikely(node_address == 0x0000))
+ printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n");
+
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_NPRD;
+ cmd->address.phy.dev.node = node_address;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-NPWR-Kommando.
+
+ Alloziert ein "node-adressed physical write"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param node_address Adresse des Knotens (Slaves)
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu schreibenden Daten
+ @param data Zeiger auf Speicher mit zu schreibenden Daten
+*/
+
+void ec_command_write(ec_command_t *cmd, unsigned short node_address,
+ unsigned short offset, unsigned int length,
+ const unsigned char *data)
+{
+ if (unlikely(node_address == 0x0000))
+ printk(KERN_WARNING "EtherCAT: Warning - Using node address 0x0000!\n");
+
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_NPWR;
+ cmd->address.phy.dev.node = node_address;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-APRD-Kommando.
+
+ Alloziert ein "autoincerement physical read"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param ring_position (Negative) Position des Slaves im Bus
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu lesenden Daten
+*/
+
+void ec_command_position_read(ec_command_t *cmd, short ring_position,
+ unsigned short offset, unsigned int length)
+{
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_APRD;
+ cmd->address.phy.dev.pos = ring_position;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-APWR-Kommando.
+
+ Alloziert ein "autoincrement physical write"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param ring_position (Negative) Position des Slaves im Bus
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu schreibenden Daten
+ @param data Zeiger auf Speicher mit zu schreibenden Daten
+*/
+
+void ec_command_position_write(ec_command_t *cmd, short ring_position,
+ unsigned short offset, unsigned int length,
+ const unsigned char *data)
+{
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_APWR;
+ cmd->address.phy.dev.pos = ring_position;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-BRD-Kommando.
+
+ Alloziert ein "broadcast read"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu lesenden Daten
+*/
+
+void ec_command_broadcast_read(ec_command_t *cmd, unsigned short offset,
+ unsigned int length)
+{
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_BRD;
+ cmd->address.phy.dev.node = 0x0000;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_READ_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-BWR-Kommando.
+
+ Alloziert ein "broadcast write"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param offset Physikalische Speicheradresse im Slave
+ @param length Länge der zu schreibenden Daten
+ @param data Zeiger auf Speicher mit zu schreibenden Daten
+*/
+
+void ec_command_broadcast_write(ec_command_t *cmd, unsigned short offset,
+ unsigned int length, const unsigned char *data)
+{
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_BWR;
+ cmd->address.phy.dev.node = 0x0000;
+ cmd->address.phy.mem = offset;
+
+ EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
+
+/**
+ Initialisiert ein EtherCAT-LRW-Kommando.
+
+ Alloziert ein "logical read write"-Kommando
+ und fügt es in die Liste des Masters ein.
+
+ @param cmd Zeiger auf das Kommando
+ @param offset Logische Speicheradresse
+ @param length Länge der zu lesenden/schreibenden Daten
+ @param data Zeiger auf Speicher mit zu lesenden/schreibenden Daten
+*/
+
+void ec_command_logical_read_write(ec_command_t *cmd, unsigned int offset,
+ unsigned int length, unsigned char *data)
+{
+ EC_FUNC_HEADER;
+
+ cmd->type = EC_COMMAND_LRW;
+ cmd->address.logical = offset;
+
+ EC_FUNC_WRITE_FOOTER;
+}
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/command.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,103 @@
+/******************************************************************************
+ *
+ * c o m m a n d . h
+ *
+ * Struktur für ein EtherCAT-Kommando.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_COMMAND_H_
+#define _EC_COMMAND_H_
+
+#include "globals.h"
+
+/*****************************************************************************/
+
+/**
+ Status eines EtherCAT-Kommandos.
+*/
+
+typedef enum
+{
+ EC_COMMAND_STATE_READY, EC_COMMAND_STATE_SENT, EC_COMMAND_STATE_RECEIVED
+}
+ec_command_state_t;
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Adresse.
+
+ Im EtherCAT-Rahmen sind 4 Bytes für die Adresse reserviert, die
+ ja nach Kommandoty eine andere bedeutung haben: Bei Autoinkrement-
+ befehlen sind die ersten zwei Bytes die (negative)
+ Autoinkrement-Adresse, bei Knoten-adressierten Befehlen entsprechen
+ sie der Knotenadresse. Das dritte und vierte Byte entspricht in
+ diesen Fällen der physikalischen Speicheradresse auf dem Slave.
+ Bei einer logischen Adressierung entsprechen alle vier Bytes
+ der logischen Adresse.
+*/
+
+typedef union
+{
+ struct
+ {
+ union
+ {
+ short pos; /**< (Negative) Ring-Position des Slaves */
+ unsigned short node; /**< Konfigurierte Knotenadresse */
+ }
+ dev;
+
+ unsigned short mem; /**< Physikalische Speicheradresse im Slave */
+ }
+ phy;
+
+ unsigned long logical; /**< Logische Adresse */
+ unsigned char raw[4]; /**< Rohdaten für die Generierung des Frames */
+}
+ec_address_t;
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Kommando.
+*/
+
+typedef struct ec_command
+{
+ ec_command_type_t type; /**< Typ des Kommandos (APRD, NPWR, etc...) */
+ ec_address_t address; /**< Adresse des/der Empfänger */
+ unsigned int data_length; /**< Länge der zu sendenden und/oder
+ empfangenen Daten */
+ ec_command_state_t state; /**< Zustand des Kommandos
+ (bereit, gesendet, etc...) */
+ unsigned char index; /**< Kommando-Index, mit der das Kommando gesendet
+ wurde (wird vom Master beim Senden gesetzt. */
+ unsigned int working_counter; /**< Working-Counter bei Empfang (wird
+ vom Master gesetzt) */
+ unsigned char data[EC_FRAME_SIZE]; /**< Kommandodaten */
+}
+ec_command_t;
+
+/*****************************************************************************/
+
+void ec_command_read(ec_command_t *, unsigned short, unsigned short,
+ unsigned int);
+void ec_command_write(ec_command_t *, unsigned short, unsigned short,
+ unsigned int, const unsigned char *);
+void ec_command_position_read(ec_command_t *, short, unsigned short,
+ unsigned int);
+void ec_command_position_write(ec_command_t *, short, unsigned short,
+ unsigned int, const unsigned char *);
+void ec_command_broadcast_read(ec_command_t *, unsigned short, unsigned int);
+void ec_command_broadcast_write(ec_command_t *, unsigned short, unsigned int,
+ const unsigned char *);
+void ec_command_logical_read_write(ec_command_t *, unsigned int, unsigned int,
+ unsigned char *);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/device.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ * d e v i c e . c
+ *
+ * Methoden für ein EtherCAT-Gerät.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+
+#include "device.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Geräte-Konstuktor.
+
+ Initialisiert ein EtherCAT-Gerät, indem es die Variablen
+ in der Struktur auf die Default-Werte setzt.
+
+ @param ecd Zu initialisierendes EtherCAT-Gerät
+*/
+
+int ec_device_init(ec_device_t *ecd)
+{
+ ecd->dev = NULL;
+ ecd->open = 0;
+ ecd->tx_time = 0;
+ ecd->rx_time = 0;
+ ecd->tx_intr_cnt = 0;
+ ecd->rx_intr_cnt = 0;
+ ecd->intr_cnt = 0;
+ ecd->state = EC_DEVICE_STATE_READY;
+ ecd->rx_data_length = 0;
+ ecd->isr = NULL;
+ ecd->module = NULL;
+ ecd->error_reported = 0;
+
+ if ((ecd->tx_skb = dev_alloc_skb(EC_FRAME_SIZE)) == NULL) {
+ printk(KERN_ERR "EtherCAT: Could not allocate device tx socket buffer!\n");
+ return -1;
+ }
+
+ if ((ecd->rx_skb = dev_alloc_skb(EC_FRAME_SIZE)) == NULL) {
+ dev_kfree_skb(ecd->tx_skb);
+ ecd->tx_skb = NULL;
+ printk(KERN_ERR "EtherCAT: Could not allocate device rx socket buffer!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Geräte-Destuktor.
+
+ Gibt den dynamisch allozierten Speicher des
+ EtherCAT-Gerätes (die beiden Socket-Buffer) wieder frei.
+
+ @param ecd EtherCAT-Gerät
+*/
+
+void ec_device_clear(ec_device_t *ecd)
+{
+ if (ecd->open) ec_device_close(ecd);
+
+ ecd->dev = NULL;
+
+ if (ecd->tx_skb) {
+ dev_kfree_skb(ecd->tx_skb);
+ ecd->tx_skb = NULL;
+ }
+
+ if (ecd->rx_skb) {
+ dev_kfree_skb(ecd->rx_skb);
+ ecd->rx_skb = NULL;
+ }
+}
+
+/*****************************************************************************/
+
+/**
+ Führt die open()-Funktion des Netzwerktreibers aus.
+
+ Dies entspricht einem "ifconfig up". Vorher wird der Zeiger
+ auf das EtherCAT-Gerät auf Gültigkeit geprüft und der
+ Gerätezustand zurückgesetzt.
+
+ @param ecd EtherCAT-Gerät
+
+ @return 0 bei Erfolg, < 0: Ungültiger Zeiger, oder open()
+ fehlgeschlagen
+*/
+
+int ec_device_open(ec_device_t *ecd)
+{
+ unsigned int i;
+
+ if (!ecd) {
+ printk(KERN_ERR "EtherCAT: Trying to open a NULL device!\n");
+ return -1;
+ }
+
+ if (!ecd->dev) {
+ printk(KERN_ERR "EtherCAT: No net_device to open!\n");
+ return -1;
+ }
+
+ if (ecd->open) {
+ printk(KERN_WARNING "EtherCAT: Device already opened!\n");
+ }
+ else {
+ // Device could have received frames before
+ for (i = 0; i < 4; i++) ec_device_call_isr(ecd);
+
+ // Reset old device state
+ ecd->state = EC_DEVICE_STATE_READY;
+ ecd->tx_intr_cnt = 0;
+ ecd->rx_intr_cnt = 0;
+
+ if (ecd->dev->open(ecd->dev) == 0) ecd->open = 1;
+ }
+
+ return ecd->open ? 0 : -1;
+}
+
+/*****************************************************************************/
+
+/**
+ Führt die stop()-Funktion des net_devices aus.
+
+ @param ecd EtherCAT-Gerät
+
+ @return 0 bei Erfolg, < 0: Kein Gerät zum Schliessen oder
+ Schliessen fehlgeschlagen.
+*/
+
+int ec_device_close(ec_device_t *ecd)
+{
+ if (!ecd->dev) {
+ printk(KERN_ERR "EtherCAT: No device to close!\n");
+ return -1;
+ }
+
+ if (!ecd->open) {
+ printk(KERN_WARNING "EtherCAT: Device already closed!\n");
+ }
+ else {
+ printk(KERN_INFO "EtherCAT: Stopping device (txcnt: %u, rxcnt: %u)\n",
+ (unsigned int) ecd->tx_intr_cnt, (unsigned int) ecd->rx_intr_cnt);
+
+ if (ecd->dev->stop(ecd->dev) == 0) ecd->open = 0;
+ }
+
+ return !ecd->open ? 0 : -1;
+}
+
+/*****************************************************************************/
+
+/**
+ Sendet einen Rahmen über das EtherCAT-Gerät.
+
+ Kopiert die zu sendenden Daten in den statischen Socket-
+ Buffer, fügt den Ethernat-II-Header hinzu und ruft die
+ start_xmit()-Funktion der Netzwerkkarte auf.
+
+ @param ecd EtherCAT-Gerät
+ @param data Zeiger auf die zu sendenden Daten
+ @param length Länge der zu sendenden Daten
+
+ @return 0 bei Erfolg, < 0: Vorheriger Rahmen noch
+ nicht empfangen, oder kein Speicher mehr vorhanden
+*/
+
+int ec_device_send(ec_device_t *ecd, unsigned char *data, unsigned int length)
+{
+ unsigned char *frame_data;
+ struct ethhdr *eth;
+
+ if (unlikely(ecd->state == EC_DEVICE_STATE_SENT)) {
+ printk(KERN_WARNING "EtherCAT: Warning - Trying to send frame while last "
+ " was not received!\n");
+ }
+
+ // Clear transmit socket buffer and reserve
+ // space for Ethernet-II header
+ skb_trim(ecd->tx_skb, 0);
+ skb_reserve(ecd->tx_skb, ETH_HLEN);
+
+ // Copy data to socket buffer
+ frame_data = skb_put(ecd->tx_skb, length);
+ memcpy(frame_data, data, length);
+
+ // Add Ethernet-II-Header
+ if (unlikely((eth = (struct ethhdr *)
+ skb_push(ecd->tx_skb, ETH_HLEN)) == NULL)) {
+ printk(KERN_ERR "EtherCAT: device_send -"
+ " Could not allocate Ethernet-II header!\n");
+ return -1;
+ }
+
+ // Protocol type
+ eth->h_proto = htons(0x88A4);
+ // Hardware address
+ memcpy(eth->h_source, ecd->dev->dev_addr, ecd->dev->addr_len);
+ // Broadcast address
+ memset(eth->h_dest, 0xFF, ecd->dev->addr_len);
+
+ rdtscl(ecd->tx_time); // Get CPU cycles
+
+ // Start sending of frame
+ ecd->state = EC_DEVICE_STATE_SENT;
+ ecd->dev->hard_start_xmit(ecd->tx_skb, ecd->dev);
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Holt einen empfangenen Rahmen von der Netzwerkkarte.
+
+ Zuerst wird geprüft, ob überhaupt ein Rahmen empfangen
+ wurde. Wenn ja, wird dieser in den angegebenen
+ Speicherbereich kopiert.
+
+ @param ecd EtherCAT-Gerät
+ @param data Zeiger auf den Speicherbereich, in den die
+ empfangenen Daten kopiert werden sollen
+
+ @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
+*/
+
+int ec_device_receive(ec_device_t *ecd, unsigned char *data)
+{
+ if (unlikely(ecd->state != EC_DEVICE_STATE_RECEIVED)) {
+ if (likely(ecd->error_reported)) {
+ printk(KERN_ERR "EtherCAT: receive - Nothing received!\n");
+ ecd->error_reported = 1;
+ }
+ return -1;
+ }
+
+ if (unlikely(ecd->rx_data_length > EC_FRAME_SIZE)) {
+ if (likely(ecd->error_reported)) {
+ printk(KERN_ERR "EtherCAT: receive - "
+ " Reveived frame is too long (%i Bytes)!\n",
+ ecd->rx_data_length);
+ ecd->error_reported = 1;
+ }
+ return -1;
+ }
+
+ if (unlikely(ecd->error_reported)) {
+ ecd->error_reported = 0;
+ }
+
+ memcpy(data, ecd->rx_data, ecd->rx_data_length);
+
+ return ecd->rx_data_length;
+}
+
+/*****************************************************************************/
+
+/**
+ Ruft die Interrupt-Routine der Netzwerkkarte auf.
+
+ @param ecd EtherCAT-Gerät
+
+ @return Anzahl der kopierten Bytes bei Erfolg, sonst < 0
+*/
+
+void ec_device_call_isr(ec_device_t *ecd)
+{
+ if (likely(ecd->isr)) ecd->isr(0, ecd->dev, NULL);
+}
+
+/*****************************************************************************/
+
+/**
+ Gibt alle Informationen über das Device-Objekt aus.
+
+ @param ecd EtherCAT-Gerät
+*/
+
+void ec_device_debug(ec_device_t *ecd)
+{
+ printk(KERN_DEBUG "---EtherCAT device information begin---\n");
+
+ if (ecd)
+ {
+ printk(KERN_DEBUG "Assigned net_device: %X\n",
+ (unsigned) ecd->dev);
+ printk(KERN_DEBUG "Transmit socket buffer: %X\n",
+ (unsigned) ecd->tx_skb);
+ printk(KERN_DEBUG "Receive socket buffer: %X\n",
+ (unsigned) ecd->rx_skb);
+ printk(KERN_DEBUG "Time of last transmission: %u\n",
+ (unsigned) ecd->tx_time);
+ printk(KERN_DEBUG "Time of last receive: %u\n",
+ (unsigned) ecd->rx_time);
+ printk(KERN_DEBUG "Number of transmit interrupts: %u\n",
+ (unsigned) ecd->tx_intr_cnt);
+ printk(KERN_DEBUG "Number of receive interrupts: %u\n",
+ (unsigned) ecd->rx_intr_cnt);
+ printk(KERN_DEBUG "Total Number of interrupts: %u\n",
+ (unsigned) ecd->intr_cnt);
+ printk(KERN_DEBUG "Actual device state: %i\n",
+ (int) ecd->state);
+ printk(KERN_DEBUG "Receive buffer: %X\n",
+ (unsigned) ecd->rx_data);
+ printk(KERN_DEBUG "Receive buffer fill state: %u/%u\n",
+ (unsigned) ecd->rx_data_length, EC_FRAME_SIZE);
+ }
+ else
+ {
+ printk(KERN_DEBUG "Device is NULL!\n");
+ }
+
+ printk(KERN_DEBUG "---EtherCAT device information end---\n");
+}
+
+/******************************************************************************
+ *
+ * Treiberschnittstelle
+ *
+ *****************************************************************************/
+
+void EtherCAT_dev_state(ec_device_t *ecd, ec_device_state_t state)
+{
+ if (state == EC_DEVICE_STATE_TIMEOUT && ecd->state != EC_DEVICE_STATE_SENT) {
+ printk(KERN_WARNING "EtherCAT: Wrong status at timeout: %i\n", ecd->state);
+ }
+
+ ecd->state = state;
+}
+
+/*****************************************************************************/
+
+int EtherCAT_dev_is_ec(ec_device_t *ecd, struct net_device *dev)
+{
+ return ecd->dev == dev;
+}
+
+/*****************************************************************************/
+
+int EtherCAT_dev_receive(ec_device_t *ecd, void *data, unsigned int size)
+{
+ if (ecd->state != EC_DEVICE_STATE_SENT)
+ {
+ printk(KERN_WARNING "EtherCAT: Received frame while not in SENT state!\n");
+ return -1;
+ }
+
+ // Copy received data to ethercat-device buffer, skip Ethernet-II header
+ memcpy(ecd->rx_data, data, size);
+ ecd->rx_data_length = size;
+ ecd->state = EC_DEVICE_STATE_RECEIVED;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+EXPORT_SYMBOL(EtherCAT_dev_is_ec);
+EXPORT_SYMBOL(EtherCAT_dev_state);
+EXPORT_SYMBOL(EtherCAT_dev_receive);
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/device.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * d e v i c e . h
+ *
+ * Struktur für ein EtherCAT-Gerät.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_DEVICE_H_
+#define _EC_DEVICE_H_
+
+#include <linux/interrupt.h>
+
+#include "globals.h"
+#include "../include/EtherCAT_dev.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Gerät.
+
+ Ein EtherCAT-Gerät ist eine Netzwerkkarte, die vom
+ EtherCAT-Master dazu verwendet wird, um Frames zu senden
+ und zu empfangen.
+*/
+
+struct ec_device
+{
+ struct net_device *dev; /**< Zeiger auf das reservierte net_device */
+ unsigned int open; /**< Das net_device ist geoeffnet. */
+ struct sk_buff *tx_skb; /**< Zeiger auf Transmit-Socketbuffer */
+ struct sk_buff *rx_skb; /**< Zeiger auf Receive-Socketbuffer */
+ unsigned long tx_time; /**< Zeit des letzten Sendens */
+ unsigned long rx_time; /**< Zeit des letzten Empfangs */
+ unsigned long tx_intr_cnt; /**< Anzahl Tx-Interrupts */
+ unsigned long rx_intr_cnt; /**< Anzahl Rx-Interrupts */
+ unsigned long intr_cnt; /**< Anzahl Interrupts */
+ volatile ec_device_state_t state; /**< Gesendet, Empfangen,
+ Timeout, etc. */
+ unsigned char rx_data[EC_FRAME_SIZE]; /**< Puffer für
+ empfangene Rahmen */
+ volatile unsigned int rx_data_length; /**< Länge des zuletzt
+ empfangenen Rahmens */
+ irqreturn_t (*isr)(int, void *, struct pt_regs *); /**< Adresse der ISR */
+ struct module *module; /**< Zeiger auf das Modul, das das Gerät zur
+ Verfügung stellt. */
+ int error_reported; /**< Zeigt an, ob ein Fehler im zyklischen Code
+ bereits gemeldet wurde. */
+};
+
+/*****************************************************************************/
+
+int ec_device_init(ec_device_t *);
+void ec_device_clear(ec_device_t *);
+int ec_device_open(ec_device_t *);
+int ec_device_close(ec_device_t *);
+void ec_device_call_isr(ec_device_t *);
+int ec_device_send(ec_device_t *, unsigned char *, unsigned int);
+int ec_device_receive(ec_device_t *, unsigned char *);
+
+/*****************************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/domain.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * d o m a i n . c
+ *
+ * Methoden für Gruppen von EtherCAT-Slaves.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "domain.h"
+
+/*****************************************************************************/
+
+/**
+ Konstruktor einer EtherCAT-Domäne.
+
+ @param pd Zeiger auf die zu initialisierende Domäne
+*/
+
+void ec_domain_init(ec_domain_t *dom)
+{
+ dom->number = 0;
+ dom->data_size = 0;
+ dom->logical_offset = 0;
+ dom->response_count = 0;
+
+ memset(dom->data, 0x00, EC_FRAME_SIZE);
+}
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/domain.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * d o m a i n . h
+ *
+ * Struktur für eine Gruppe von EtherCAT-Slaves.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_DOMAIN_H_
+#define _EC_DOMAIN_H_
+
+#include "globals.h"
+#include "slave.h"
+#include "command.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Domäne
+
+ Verwaltet die Prozessdaten und das hierfür nötige Kommando einer bestimmten
+ Menge von Slaves.
+*/
+
+typedef struct ec_domain
+{
+ unsigned int number; /*<< Domänen-Identifikation */
+ ec_command_t command; /**< Kommando zum Senden und Empfangen der
+ Prozessdaten */
+ unsigned char data[EC_FRAME_SIZE]; /**< Prozessdaten-Array */
+ unsigned int data_size; /**< Größe der Prozessdaten */
+ unsigned int logical_offset; /**< Logische Basisaddresse */
+ unsigned int response_count; /**< Anzahl antwortender Slaves */
+}
+ec_domain_t;
+
+/*****************************************************************************/
+
+void ec_domain_init(ec_domain_t *);
+
+/*****************************************************************************/
+
+#endif
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/globals.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * g l o b a l s . h
+ *
+ * Globale Definitionen und Makros für das EtherCAT-Protokoll.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_GLOBALS_
+#define _EC_GLOBALS_
+
+/*****************************************************************************/
+
+/**
+ Maximale Größe eines EtherCAT-Frames
+*/
+#define EC_FRAME_SIZE 1500
+
+/**
+ Maximale Anzahl der Prozessdatendomänen in einem Master
+*/
+#define EC_MAX_DOMAINS 10
+
+/**
+ NULL-Define, falls noch nicht definiert.
+*/
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Kommando-Typ
+*/
+
+typedef enum
+{
+ EC_COMMAND_NONE = 0x00, /**< Dummy */
+ EC_COMMAND_APRD = 0x01, /**< Auto-increment physical read */
+ EC_COMMAND_APWR = 0x02, /**< Auto-increment physical write */
+ EC_COMMAND_NPRD = 0x04, /**< Node-addressed physical read */
+ EC_COMMAND_NPWR = 0x05, /**< Node-addressed physical write */
+ EC_COMMAND_BRD = 0x07, /**< Broadcast read */
+ EC_COMMAND_BWR = 0x08, /**< Broadcast write */
+ EC_COMMAND_LRW = 0x0C /**< Logical read/write */
+}
+ec_command_type_t;
+
+/*****************************************************************************/
+
+/**
+ Zustand eines EtherCAT-Slaves
+*/
+
+typedef enum
+{
+ EC_SLAVE_STATE_UNKNOWN = 0x00, /**< Status unbekannt */
+ EC_SLAVE_STATE_INIT = 0x01, /**< Init-Zustand (Keine Mailbox-
+ Kommunikation, Kein I/O) */
+ EC_SLAVE_STATE_PREOP = 0x02, /**< Pre-Operational (Mailbox-
+ Kommunikation, Kein I/O) */
+ EC_SLAVE_STATE_SAVEOP = 0x04, /**< Save-Operational (Mailbox-
+ Kommunikation und Input Update) */
+ EC_SLAVE_STATE_OP = 0x08, /**< Operational, (Mailbox-
+ Kommunikation und Input/Output Update) */
+ EC_ACK = 0x10 /**< Acknoledge-Bit beim Zustandswechsel
+ (dies ist kein eigener Zustand) */
+}
+ec_slave_state_t;
+
+/*****************************************************************************/
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/master.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,1114 @@
+/******************************************************************************
+ *
+ * m a s t e r . c
+ *
+ * Methoden für einen EtherCAT-Master.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "globals.h"
+#include "master.h"
+#include "device.h"
+#include "command.h"
+
+/*****************************************************************************/
+
+// Prototypen
+
+int ec_simple_send(ec_master_t *, ec_command_t *);
+int ec_simple_receive(ec_master_t *, ec_command_t *);
+void ec_output_debug_data(const ec_master_t *);
+int ec_read_slave_information(ec_master_t *, unsigned short, unsigned short,
+ unsigned int *);
+void ec_output_lost_frames(ec_master_t *);
+
+/*****************************************************************************/
+
+/**
+ Konstruktor des EtherCAT-Masters.
+
+ @param master Zeiger auf den zu initialisierenden EtherCAT-Master
+*/
+
+void ec_master_init(ec_master_t *master)
+{
+ master->bus_slaves = NULL;
+ master->bus_slaves_count = 0;
+ master->device_registered = 0;
+ master->command_index = 0x00;
+ master->tx_data_length = 0;
+ master->rx_data_length = 0;
+ master->domain_count = 0;
+ master->debug_level = 0;
+ master->bus_time = 0;
+ master->frames_lost = 0;
+ master->t_lost_output = 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Destruktor eines EtherCAT-Masters.
+
+ Entfernt alle Kommandos aus der Liste, löscht den Zeiger
+ auf das Slave-Array und gibt die Prozessdaten frei.
+
+ @param master Zeiger auf den zu löschenden Master
+*/
+
+void ec_master_clear(ec_master_t *master)
+{
+ if (master->bus_slaves) {
+ kfree(master->bus_slaves);
+ master->bus_slaves = NULL;
+ }
+
+ ec_device_clear(&master->device);
+
+ master->domain_count = 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Öffnet das EtherCAT-Geraet des Masters.
+
+ @param master Der EtherCAT-Master
+
+ @return 0, wenn alles o.k., < 0, wenn das Geraet nicht geoeffnet werden
+ konnte.
+*/
+
+int ec_master_open(ec_master_t *master)
+{
+ if (!master->device_registered) {
+ printk(KERN_ERR "EtherCAT: No device registered!\n");
+ return -1;
+ }
+
+ if (ec_device_open(&master->device) < 0) {
+ printk(KERN_ERR "EtherCAT: Could not open device!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Schliesst das EtherCAT-Geraet, auf dem der Master arbeitet.
+
+ @param master Der EtherCAT-Master
+ @param device Das EtherCAT-Geraet
+*/
+
+void ec_master_close(ec_master_t *master)
+{
+ if (!master->device_registered) {
+ printk(KERN_WARNING "EtherCAT: Warning -"
+ " Trying to close an unregistered device!\n");
+ return;
+ }
+
+ if (ec_device_close(&master->device) < 0) {
+ printk(KERN_WARNING "EtherCAT: Warning - Could not close device!\n");
+ }
+}
+
+/*****************************************************************************/
+
+/**
+ Sendet ein einzelnes Kommando in einem Frame und
+ wartet auf dessen Empfang.
+
+ @param master EtherCAT-Master
+ @param cmd Kommando zum Senden/Empfangen
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_simple_send_receive(ec_master_t *master, ec_command_t *cmd)
+{
+ unsigned int tries_left;
+
+ if (unlikely(ec_simple_send(master, cmd) < 0))
+ return -1;
+
+ tries_left = 20;
+
+ do
+ {
+ udelay(1);
+ ec_device_call_isr(&master->device);
+ tries_left--;
+ }
+ while (unlikely(master->device.state == EC_DEVICE_STATE_SENT && tries_left));
+
+ if (unlikely(ec_simple_receive(master, cmd) < 0))
+ return -1;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Sendet ein einzelnes Kommando in einem Frame.
+
+ @param master EtherCAT-Master
+ @param cmd Kommando zum Senden
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_simple_send(ec_master_t *master, ec_command_t *cmd)
+{
+ unsigned int length, framelength, i;
+
+ if (unlikely(master->debug_level > 0)) {
+ printk(KERN_DEBUG "EtherCAT: ec_simple_send\n");
+ }
+
+ if (unlikely(cmd->state != EC_COMMAND_STATE_READY)) {
+ printk(KERN_WARNING "EtherCAT: cmd not in ready state!\n");
+ }
+
+ length = cmd->data_length + 12;
+ framelength = length + 2;
+
+ if (unlikely(framelength > EC_FRAME_SIZE)) {
+ printk(KERN_ERR "EtherCAT: Frame too long (%i)!\n", framelength);
+ return -1;
+ }
+
+ if (framelength < 46) framelength = 46;
+
+ if (unlikely(master->debug_level > 0)) {
+ printk(KERN_DEBUG "EtherCAT: Frame length: %i\n", framelength);
+ }
+
+ master->tx_data[0] = length & 0xFF;
+ master->tx_data[1] = ((length & 0x700) >> 8) | 0x10;
+
+ cmd->index = master->command_index;
+ master->command_index = (master->command_index + 1) % 0x0100;
+
+ if (unlikely(master->debug_level > 0)) {
+ printk(KERN_DEBUG "EtherCAT: Sending command index %i\n", cmd->index);
+ }
+
+ cmd->state = EC_COMMAND_STATE_SENT;
+
+ master->tx_data[2 + 0] = cmd->type;
+ master->tx_data[2 + 1] = cmd->index;
+ master->tx_data[2 + 2] = cmd->address.raw[0];
+ master->tx_data[2 + 3] = cmd->address.raw[1];
+ master->tx_data[2 + 4] = cmd->address.raw[2];
+ master->tx_data[2 + 5] = cmd->address.raw[3];
+ master->tx_data[2 + 6] = cmd->data_length & 0xFF;
+ master->tx_data[2 + 7] = (cmd->data_length & 0x700) >> 8;
+ master->tx_data[2 + 8] = 0x00;
+ master->tx_data[2 + 9] = 0x00;
+
+ if (likely(cmd->type == EC_COMMAND_APWR
+ || cmd->type == EC_COMMAND_NPWR
+ || cmd->type == EC_COMMAND_BWR
+ || cmd->type == EC_COMMAND_LRW)) // Write commands
+ {
+ for (i = 0; i < cmd->data_length; i++)
+ master->tx_data[2 + 10 + i] = cmd->data[i];
+ }
+ else // Read commands
+ {
+ for (i = 0; i < cmd->data_length; i++) master->tx_data[2 + 10 + i] = 0x00;
+ }
+
+ master->tx_data[2 + 10 + cmd->data_length] = 0x00;
+ master->tx_data[2 + 11 + cmd->data_length] = 0x00;
+
+ // Pad with zeros
+ for (i = cmd->data_length + 12 + 2; i < 46; i++) master->tx_data[i] = 0x00;
+
+ master->tx_data_length = framelength;
+
+ if (unlikely(master->debug_level > 0)) {
+ printk(KERN_DEBUG "EtherCAT: Device send...\n");
+ }
+
+ // Send frame
+ if (unlikely(ec_device_send(&master->device, master->tx_data,
+ framelength) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not send!\n");
+ return -1;
+ }
+
+ if (unlikely(master->debug_level > 0)) {
+ printk(KERN_DEBUG "EtherCAT: ec_simple_send done.\n");
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Wartet auf den Empfang eines einzeln gesendeten
+ Kommandos.
+
+ @param master EtherCAT-Master
+ @param cmd Gesendetes Kommando
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_simple_receive(ec_master_t *master, ec_command_t *cmd)
+{
+ unsigned int length;
+ int ret;
+ unsigned char command_type, command_index;
+
+ if (unlikely((ret = ec_device_receive(&master->device, master->rx_data)) < 0))
+ return -1;
+
+ master->rx_data_length = (unsigned int) ret;
+
+ if (unlikely(master->rx_data_length < 2)) {
+ printk(KERN_ERR "EtherCAT: Received frame with incomplete EtherCAT"
+ " header!\n");
+ ec_output_debug_data(master);
+ return -1;
+ }
+
+ // Länge des gesamten Frames prüfen
+ length = ((master->rx_data[1] & 0x07) << 8)
+ | (master->rx_data[0] & 0xFF);
+
+ if (unlikely(length > master->rx_data_length)) {
+ printk(KERN_ERR "EtherCAT: Received corrupted frame (length does"
+ " not match)!\n");
+ ec_output_debug_data(master);
+ return -1;
+ }
+
+ command_type = master->rx_data[2];
+ command_index = master->rx_data[2 + 1];
+ length = (master->rx_data[2 + 6] & 0xFF)
+ | ((master->rx_data[2 + 7] & 0x07) << 8);
+
+ if (unlikely(master->rx_data_length - 2 < length + 12)) {
+ printk(KERN_ERR "EtherCAT: Received frame with"
+ " incomplete command data!\n");
+ ec_output_debug_data(master);
+ return -1;
+ }
+
+ if (likely(cmd->state == EC_COMMAND_STATE_SENT
+ && cmd->type == command_type
+ && cmd->index == command_index
+ && cmd->data_length == length))
+ {
+ cmd->state = EC_COMMAND_STATE_RECEIVED;
+
+ // Empfangene Daten in Kommandodatenspeicher kopieren
+ memcpy(cmd->data, master->rx_data + 2 + 10, length);
+
+ // Working-Counter setzen
+ cmd->working_counter
+ = ((master->rx_data[length + 2 + 10] & 0xFF)
+ | ((master->rx_data[length + 2 + 11] & 0xFF) << 8));
+
+ if (unlikely(master->debug_level > 1)) {
+ ec_output_debug_data(master);
+ }
+ }
+ else
+ {
+ printk(KERN_WARNING "EtherCAT: WARNING - Send/Receive anomaly!\n");
+ ec_output_debug_data(master);
+ }
+
+ master->device.state = EC_DEVICE_STATE_READY;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Durchsucht den Bus nach Slaves.
+
+ @param master Der EtherCAT-Master
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_scan_for_slaves(ec_master_t *master)
+{
+ ec_command_t cmd;
+ ec_slave_t *cur;
+ unsigned int i, j;
+ unsigned char data[2];
+
+ // Determine number of slaves on bus
+
+ ec_command_broadcast_read(&cmd, 0x0000, 4);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ master->bus_slaves_count = cmd.working_counter;
+ printk("EtherCAT: Found %i slaves on bus.\n", master->bus_slaves_count);
+
+ if (!master->bus_slaves_count) return 0;
+
+ if (!(master->bus_slaves = (ec_slave_t *) kmalloc(master->bus_slaves_count
+ * sizeof(ec_slave_t),
+ GFP_KERNEL))) {
+ printk(KERN_ERR "EtherCAT: Could not allocate memory for bus slaves!\n");
+ return -1;
+ }
+
+ // For every slave in the list
+ for (i = 0; i < master->bus_slaves_count; i++)
+ {
+ cur = master->bus_slaves + i;
+
+ ec_slave_init(cur);
+
+ // Read base data
+
+ ec_command_read(&cmd, cur->station_address, 0x0000, 4);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Slave %i did not respond"
+ " while reading base data!\n", i);
+ return -1;
+ }
+
+ // Get base data
+
+ cur->type = cmd.data[0];
+ cur->revision = cmd.data[1];
+ cur->build = cmd.data[2] | (cmd.data[3] << 8);
+
+ // Read identification from "Slave Information Interface" (SII)
+
+ if (unlikely(ec_read_slave_information(master, cur->station_address,
+ 0x0008, &cur->vendor_id) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not read SII vendor id!\n");
+ return -1;
+ }
+
+ if (unlikely(ec_read_slave_information(master, cur->station_address,
+ 0x000A, &cur->product_code) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not read SII product code!\n");
+ return -1;
+ }
+
+ if (unlikely(ec_read_slave_information(master, cur->station_address,
+ 0x000C,
+ &cur->revision_number) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not read SII revision number!\n");
+ return -1;
+ }
+
+ if (unlikely(ec_read_slave_information(master, cur->station_address,
+ 0x000E,
+ &cur->serial_number) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not read SII serial number!\n");
+ return -1;
+ }
+
+ // Search for identification in "database"
+
+ for (j = 0; j < slave_ident_count; j++)
+ {
+ if (unlikely(slave_idents[j].vendor_id == cur->vendor_id
+ && slave_idents[j].product_code == cur->product_code))
+ {
+ cur->desc = slave_idents[j].desc;
+ break;
+ }
+ }
+
+ if (unlikely(!cur->desc)) {
+ printk(KERN_ERR "EtherCAT: Unknown slave device (vendor %X, code %X) at "
+ " position %i.\n", cur->vendor_id, cur->product_code, i);
+ return -1;
+ }
+
+ // Set ring position
+ cur->ring_position = -i;
+ cur->station_address = i + 1;
+
+ // Write station address
+
+ data[0] = cur->station_address & 0x00FF;
+ data[1] = (cur->station_address & 0xFF00) >> 8;
+
+ ec_command_position_write(&cmd, cur->ring_position, 0x0010, 2, data);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Slave %i did not repond"
+ " while writing station address!\n", i);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Liest Daten aus dem Slave-Information-Interface
+ eines EtherCAT-Slaves.
+
+ @param master EtherCAT-Master
+ @param node_address Knotenadresse des Slaves
+ @param offset Adresse des zu lesenden SII-Registers
+ @param target Zeiger auf einen 4 Byte großen Speicher
+ zum Ablegen der Daten
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_read_slave_information(ec_master_t *master,
+ unsigned short int node_address,
+ unsigned short int offset,
+ unsigned int *target)
+{
+ ec_command_t cmd;
+ unsigned char data[10];
+ unsigned int tries_left;
+
+ // Initiate read operation
+
+ data[0] = 0x00;
+ data[1] = 0x01;
+ data[2] = offset & 0xFF;
+ data[3] = (offset & 0xFF00) >> 8;
+ data[4] = 0x00;
+ data[5] = 0x00;
+
+ ec_command_write(&cmd, node_address, 0x502, 6, data);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: SII-read - Slave %04X did not respond!\n",
+ node_address);
+ return -1;
+ }
+
+ // Der Slave legt die Informationen des Slave-Information-Interface
+ // in das Datenregister und löscht daraufhin ein Busy-Bit. Solange
+ // den Status auslesen, bis das Bit weg ist.
+
+ tries_left = 100;
+ while (likely(tries_left))
+ {
+ udelay(10);
+
+ ec_command_read(&cmd, node_address, 0x502, 10);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) != 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: SII-read status -"
+ " Slave %04X did not respond!\n", node_address);
+ return -1;
+ }
+
+ if (likely((cmd.data[1] & 0x81) == 0)) {
+ memcpy(target, cmd.data + 6, 4);
+ break;
+ }
+
+ tries_left--;
+ }
+
+ if (unlikely(!tries_left)) {
+ printk(KERN_WARNING "EtherCAT: SSI-read. Slave %04X timed out!\n",
+ node_address);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Ändert den Zustand eines Slaves (asynchron).
+
+ Führt eine (asynchrone) Zustandsänderung bei einem Slave durch.
+
+ @param master EtherCAT-Master
+ @param slave Slave, dessen Zustand geändert werden soll
+ @param state_and_ack Neuer Zustand, evtl. mit gesetztem
+ Acknowledge-Flag
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int ec_state_change(ec_master_t *master, ec_slave_t *slave,
+ unsigned char state_and_ack)
+{
+ ec_command_t cmd;
+ unsigned char data[2];
+ unsigned int tries_left;
+
+ data[0] = state_and_ack;
+ data[1] = 0x00;
+
+ ec_command_write(&cmd, slave->station_address, 0x0120, 2, data);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not set state %02X - Unable to send!\n",
+ state_and_ack);
+ return -1;
+ }
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Could not set state %02X - Device \"%s %s\""
+ " (%d) did not respond!\n", state_and_ack, slave->desc->vendor_name,
+ slave->desc->product_name, slave->ring_position * (-1));
+ return -1;
+ }
+
+ slave->requested_state = state_and_ack & 0x0F;
+
+ tries_left = 100;
+ while (likely(tries_left))
+ {
+ udelay(10);
+
+ ec_command_read(&cmd, slave->station_address, 0x0130, 2);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) != 0)) {
+ printk(KERN_ERR "EtherCAT: Could not check state %02X - Unable to"
+ " send!\n", state_and_ack);
+ return -1;
+ }
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Could not check state %02X - Device did not"
+ " respond!\n", state_and_ack);
+ return -1;
+ }
+
+ if (unlikely(cmd.data[0] & 0x10)) { // State change error
+ printk(KERN_ERR "EtherCAT: Could not set state %02X - Device refused"
+ " state change (code %02X)!\n", state_and_ack, cmd.data[0]);
+ return -1;
+ }
+
+ if (likely(cmd.data[0] == (state_and_ack & 0x0F))) {
+ // State change successful
+ break;
+ }
+
+ tries_left--;
+ }
+
+ if (unlikely(!tries_left)) {
+ printk(KERN_ERR "EtherCAT: Could not check state %02X - Timeout while"
+ " checking!\n", state_and_ack);
+ return -1;
+ }
+
+ slave->current_state = state_and_ack & 0x0F;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Gibt Frame-Inhalte zwecks Debugging aus.
+
+ @param master EtherCAT-Master
+*/
+
+void ec_output_debug_data(const ec_master_t *master)
+{
+ unsigned int i;
+
+ printk(KERN_DEBUG "EtherCAT: tx_data content (%i Bytes):\n",
+ master->tx_data_length);
+
+ printk(KERN_DEBUG);
+ for (i = 0; i < master->tx_data_length; i++)
+ {
+ printk("%02X ", master->tx_data[i]);
+ if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG);
+ }
+ printk("\n");
+
+ printk(KERN_DEBUG "EtherCAT: rx_data content (%i Bytes):\n",
+ master->rx_data_length);
+
+ printk(KERN_DEBUG);
+ for (i = 0; i < master->rx_data_length; i++)
+ {
+ printk("%02X ", master->rx_data[i]);
+ if ((i + 1) % 16 == 0) printk("\n" KERN_DEBUG);
+ }
+ printk("\n");
+}
+
+/*****************************************************************************/
+
+/**
+ Gibt von Zeit zu Zeit die Anzahl verlorener Frames aus.
+
+ @param master EtherCAT-Master
+*/
+
+void ec_output_lost_frames(ec_master_t *master)
+{
+ unsigned long int t;
+
+ if (master->frames_lost) {
+ rdtscl(t);
+ if ((t - master->t_lost_output) / cpu_khz > 1000) {
+ printk(KERN_ERR "EtherCAT: %u frame(s) LOST!\n", master->frames_lost);
+ master->frames_lost = 0;
+ master->t_lost_output = t;
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * Echtzeitschnittstelle
+ *
+ *****************************************************************************/
+
+/**
+ Registriert einen Slave beim Master.
+
+ @param master Der EtherCAT-Master
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+void *EtherCAT_rt_register_slave(ec_master_t *master, unsigned int bus_index,
+ const char *vendor_name,
+ const char *product_name, unsigned int domain)
+{
+ ec_slave_t *slave;
+ ec_domain_t *dom;
+ unsigned int j;
+
+ if (bus_index >= master->bus_slaves_count) {
+ printk(KERN_ERR "EtherCAT: Illegal bus index! (%i / %i)\n", bus_index,
+ master->bus_slaves_count);
+ return NULL;
+ }
+
+ slave = master->bus_slaves + bus_index;
+
+ if (slave->process_data) {
+ printk(KERN_ERR "EtherCAT: Slave %i is already registered!\n", bus_index);
+ return NULL;
+ }
+
+ if (strcmp(vendor_name, slave->desc->vendor_name) ||
+ strcmp(product_name, slave->desc->product_name)) {
+ printk(KERN_ERR "Invalid Slave Type! Requested: \"%s %s\", present: \"%s"
+ "%s\".\n", vendor_name, product_name, slave->desc->vendor_name,
+ slave->desc->product_name);
+ return NULL;
+ }
+
+ // Check, if process data domain already exists...
+ dom = NULL;
+ for (j = 0; j < master->domain_count; j++) {
+ if (domain == master->domains[j].number) {
+ dom = master->domains + j;
+ }
+ }
+
+ // Create process data domain
+ if (!dom) {
+ if (master->domain_count > EC_MAX_DOMAINS - 1) {
+ printk(KERN_ERR "EtherCAT: Too many domains!\n");
+ return NULL;
+ }
+
+ dom = master->domains + master->domain_count;
+ ec_domain_init(dom);
+ dom->number = domain;
+ dom->logical_offset = master->domain_count * EC_FRAME_SIZE;
+ master->domain_count++;
+ }
+
+ if (dom->data_size + slave->desc->process_data_size > EC_FRAME_SIZE - 14) {
+ printk(KERN_ERR "EtherCAT: Oversized domain %i: %i / %i Bytes!\n",
+ dom->number, dom->data_size + slave->desc->process_data_size,
+ EC_FRAME_SIZE - 14);
+ return NULL;
+ }
+
+ slave->process_data = dom->data + dom->data_size;
+ dom->data_size += slave->desc->process_data_size;
+
+ return slave->process_data;
+}
+
+/*****************************************************************************/
+
+/**
+ Konfiguriert einen Slave und setzt den Operational-Zustand.
+
+ Führt eine komplette Konfiguration eines Slaves durch,
+ setzt Sync-Manager und FMMU's, führt die entsprechenden
+ Zustandsübergänge durch, bis der Slave betriebsbereit ist.
+
+ @param master EtherCAT-Master
+ @param slave Zu aktivierender Slave
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_rt_activate_slaves(ec_master_t *master)
+{
+ unsigned int i;
+ ec_slave_t *slave;
+ ec_command_t cmd;
+ const ec_slave_desc_t *desc;
+ unsigned char fmmu[16];
+ unsigned char data[256];
+
+ for (i = 0; i < master->bus_slaves_count; i++)
+ {
+ slave = master->bus_slaves + i;
+ desc = slave->desc;
+
+ if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_INIT) != 0))
+ return -1;
+
+ // Resetting FMMU's
+
+ memset(data, 0x00, 256);
+
+ ec_command_write(&cmd, slave->station_address, 0x0600, 256, data);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Resetting FMMUs - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+
+ // Resetting Sync Manager channels
+
+ if (desc->type != EC_NOSYNC_SLAVE)
+ {
+ memset(data, 0x00, 256);
+
+ ec_command_write(&cmd, slave->station_address, 0x0800, 256, data);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Resetting SMs - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ // Init Mailbox communication
+
+ if (desc->type == EC_MAILBOX_SLAVE)
+ {
+ if (desc->sm0)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0800, 8,
+ desc->sm0);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ if (desc->sm1)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0808, 8,
+ desc->sm1);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM1 -"
+ " Slave %04X did not respond!\n",
+ slave->station_address);
+ return -1;
+ }
+ }
+ }
+
+ // Change state to PREOP
+
+ if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_PREOP) != 0))
+ return -1;
+
+ // Set FMMU's
+
+ if (desc->fmmu0)
+ {
+ if (unlikely(!slave->process_data)) {
+ printk(KERN_ERR "EtherCAT: Warning - Slave %04X is not assigned to any"
+ " process data object!\n", slave->station_address);
+ return -1;
+ }
+
+ memcpy(fmmu, desc->fmmu0, 16);
+
+ fmmu[0] = slave->logical_address & 0x000000FF;
+ fmmu[1] = (slave->logical_address & 0x0000FF00) >> 8;
+ fmmu[2] = (slave->logical_address & 0x00FF0000) >> 16;
+ fmmu[3] = (slave->logical_address & 0xFF000000) >> 24;
+
+ ec_command_write(&cmd, slave->station_address, 0x0600, 16, fmmu);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting FMMU0 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ // Set Sync Managers
+
+ if (desc->type != EC_MAILBOX_SLAVE)
+ {
+ if (desc->sm0)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0800, 8,
+ desc->sm0);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM0 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ if (desc->sm1)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0808, 8,
+ desc->sm1);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM1 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+ }
+
+ if (desc->sm2)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0810, 8, desc->sm2);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM2 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ if (desc->sm3)
+ {
+ ec_command_write(&cmd, slave->station_address, 0x0818, 8, desc->sm3);
+
+ if (unlikely(ec_simple_send_receive(master, &cmd) < 0))
+ return -1;
+
+ if (unlikely(cmd.working_counter != 1)) {
+ printk(KERN_ERR "EtherCAT: Setting SM3 - Slave %04X did not"
+ " respond!\n", slave->station_address);
+ return -1;
+ }
+ }
+
+ // Change state to SAVEOP
+ if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_SAVEOP) != 0))
+ return -1;
+
+ // Change state to OP
+ if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_OP) != 0))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Setzt einen Slave zurück in den Init-Zustand.
+
+ @param master EtherCAT-Master
+ @param slave Zu deaktivierender Slave
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_rt_deactivate_slaves(ec_master_t *master)
+{
+ ec_slave_t *slave;
+ unsigned int i;
+
+ for (i = 0; i < master->bus_slaves_count; i++)
+ {
+ slave = master->bus_slaves + 1;
+
+ if (unlikely(ec_state_change(master, slave, EC_SLAVE_STATE_INIT) != 0))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Sendet und empfängt Prozessdaten der angegebenen Domäne
+
+ @param master EtherCAT-Master
+ domain Domäne
+ timeout_us Timeout in Mikrosekunden
+
+ @return 0 bei Erfolg, sonst < 0
+*/
+
+int EtherCAT_rt_domain_cycle(ec_master_t *master, unsigned int domain,
+ unsigned int timeout_us)
+{
+ unsigned int i;
+ ec_domain_t *dom;
+ unsigned long start_ticks, end_ticks, timeout_ticks;
+
+ ec_output_lost_frames(master); // Evtl. verlorene Frames ausgeben
+
+ // Domäne bestimmen
+ dom = NULL;
+ for (i = 0; i < master->domain_count; i++) {
+ if (master->domains[i].number == domain) {
+ dom = master->domains + i;
+ break;
+ }
+ }
+
+ if (unlikely(!dom)) {
+ printk(KERN_ERR "EtherCAT: No such domain: %i!\n", domain);
+ return -1;
+ }
+
+ ec_command_logical_read_write(&dom->command, dom->logical_offset,
+ dom->data_size, dom->data);
+
+ rdtscl(start_ticks); // Sendezeit nehmen
+
+ if (unlikely(ec_simple_send(master, &dom->command) < 0)) {
+ printk(KERN_ERR "EtherCAT: Could not send process data command!\n");
+ return -1;
+ }
+
+ timeout_ticks = timeout_us * cpu_khz / 1000;
+
+ // Warten
+ do {
+ ec_device_call_isr(&master->device);
+ rdtscl(end_ticks); // Empfangszeit nehmen
+ }
+ while (unlikely(master->device.state == EC_DEVICE_STATE_SENT
+ && end_ticks - start_ticks < timeout_ticks));
+
+ master->bus_time = (end_ticks - start_ticks) * 1000 / cpu_khz;
+
+ if (unlikely(end_ticks - start_ticks >= timeout_ticks)) {
+ master->device.state = EC_DEVICE_STATE_READY;
+ master->frames_lost++;
+ ec_output_lost_frames(master);
+ return -1;
+ }
+
+ if (unlikely(ec_simple_receive(master, &dom->command) < 0)) {
+ printk(KERN_ERR "EtherCAT: Could not receive cyclic command!\n");
+ return -1;
+ }
+
+ if (unlikely(dom->command.state != EC_COMMAND_STATE_RECEIVED)) {
+ printk(KERN_WARNING "EtherCAT: Process data command not received!\n");
+ return -1;
+ }
+
+ if (dom->command.working_counter != dom->response_count) {
+ dom->response_count = dom->command.working_counter;
+ printk(KERN_INFO "EtherCAT: Domain %i State change - %i slaves"
+ " responding.\n", dom->number, dom->response_count);
+ }
+
+ // Daten vom Kommando in den Prozessdatenspeicher kopieren
+ memcpy(dom->data, dom->command.data, dom->data_size);
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+EXPORT_SYMBOL(EtherCAT_rt_register_slave);
+EXPORT_SYMBOL(EtherCAT_rt_activate_slaves);
+EXPORT_SYMBOL(EtherCAT_rt_deactivate_slaves);
+EXPORT_SYMBOL(EtherCAT_rt_domain_cycle);
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/master.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * m a s t e r . h
+ *
+ * Struktur für einen EtherCAT-Master.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_MASTER_H_
+#define _EC_MASTER_H_
+
+#include "device.h"
+#include "slave.h"
+#include "command.h"
+#include "domain.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Master
+
+ Verwaltet die EtherCAT-Slaves und kommuniziert mit
+ dem zugewiesenen EtherCAT-Gerät.
+*/
+
+typedef struct ec_master
+{
+ ec_slave_t *bus_slaves; /**< Array von Slaves auf dem Bus */
+ unsigned int bus_slaves_count; /**< Anzahl Slaves auf dem Bus */
+ ec_device_t device; /**< EtherCAT-Gerät */
+ unsigned int device_registered; /**< Ein Geraet hat sich registriert. */
+ unsigned char command_index; /**< Aktueller Kommando-Index */
+ unsigned char tx_data[EC_FRAME_SIZE]; /**< Statischer Speicher
+ für zu sendende Daten */
+ unsigned int tx_data_length; /**< Länge der Daten im Sendespeicher */
+ unsigned char rx_data[EC_FRAME_SIZE]; /**< Statische Speicher für
+ eine Kopie des Rx-Buffers
+ im EtherCAT-Gerät */
+ unsigned int rx_data_length; /**< Länge der Daten im Empfangsspeicher */
+ ec_domain_t domains[EC_MAX_DOMAINS]; /** Prozessdatendomänen */
+ unsigned int domain_count;
+ int debug_level; /**< Debug-Level im Master-Code */
+ unsigned int bus_time; /**< Letzte Bus-Zeit in Mikrosekunden */
+ unsigned int frames_lost; /**< Anzahl verlorene Frames */
+ unsigned long t_lost_output; /*<< Timer-Ticks bei der letzten Ausgabe von
+ verlorenen Frames */
+}
+ec_master_t;
+
+/*****************************************************************************/
+
+// Private Methods
+
+// Master creation and deletion
+void ec_master_init(ec_master_t *);
+void ec_master_clear(ec_master_t *);
+
+// Registration of devices
+int ec_master_open(ec_master_t *);
+void ec_master_close(ec_master_t *);
+
+// Slave management
+int ec_scan_for_slaves(ec_master_t *);
+
+/*****************************************************************************/
+
+#endif
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/module.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * m o d u l e . c
+ *
+ * EtherCAT-Master-Treiber
+ *
+ * Autoren: Wilhelm Hagemeister, Florian Pose
+ *
+ * $Id$
+ *
+ * (C) Copyright IgH 2005
+ * Ingenieurgemeinschaft IgH
+ * Heinz-Bäcker Str. 34
+ * D-45356 Essen
+ * Tel.: +49 201/61 99 31
+ * Fax.: +49 201/61 98 36
+ * E-mail: sp@igh-essen.com
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "master.h"
+#include "device.h"
+
+/*****************************************************************************/
+
+int __init ec_init_module(void);
+void __exit ec_cleanup_module(void);
+
+/*****************************************************************************/
+
+#define LIT(X) #X
+#define STR(X) LIT(X)
+
+#define COMPILE_INFO "Revision " STR(EC_REV) \
+ ", compiled by " STR(EC_USER) \
+ " at " STR(EC_DATE)
+
+/*****************************************************************************/
+
+int ec_master_count = 1;
+ec_master_t *ec_masters = NULL;
+int *ec_masters_reserved = NULL;
+
+/*****************************************************************************/
+
+MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>,"
+ "Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION ("EtherCAT master driver module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(COMPILE_INFO);
+
+module_param(ec_master_count, int, 1);
+MODULE_PARM_DESC(ec_master_count, "Number of EtherCAT master to initialize.");
+
+/*****************************************************************************/
+
+/**
+ Init-Funktion des EtherCAT-Master-Treibermodules
+
+ Initialisiert soviele Master, wie im Parameter ec_master_count
+ angegeben wurde (Default ist 1).
+
+ @returns 0, wenn alles o.k., -1 bei ungueltiger Anzahl Master
+ oder zu wenig Speicher.
+*/
+
+int __init ec_init_module(void)
+{
+ unsigned int i;
+
+ printk(KERN_ERR "EtherCAT: Master driver, %s\n", COMPILE_INFO);
+
+ if (ec_master_count < 1) {
+ printk(KERN_ERR "EtherCAT: Error - Illegal"
+ " ec_master_count: %i\n", ec_master_count);
+ return -1;
+ }
+
+ printk(KERN_ERR "EtherCAT: Initializing %i EtherCAT master(s)...\n",
+ ec_master_count);
+
+ if ((ec_masters =
+ (ec_master_t *) kmalloc(sizeof(ec_master_t)
+ * ec_master_count,
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "EtherCAT: Could not allocate"
+ " memory for EtherCAT master(s)!\n");
+ return -1;
+ }
+
+ if ((ec_masters_reserved =
+ (int *) kmalloc(sizeof(int) * ec_master_count,
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "EtherCAT: Could not allocate"
+ " memory for reservation flags!\n");
+ kfree(ec_masters);
+ return -1;
+ }
+
+ for (i = 0; i < ec_master_count; i++)
+ {
+ ec_master_init(&ec_masters[i]);
+ ec_masters_reserved[i] = 0;
+ }
+
+ printk(KERN_ERR "EtherCAT: Master driver initialized.\n");
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+/**
+ Cleanup-Funktion des EtherCAT-Master-Treibermoduls
+
+ Entfernt alle Master-Instanzen.
+*/
+
+void __exit ec_cleanup_module(void)
+{
+ unsigned int i;
+
+ printk(KERN_ERR "EtherCAT: Cleaning up master driver...\n");
+
+ if (ec_masters)
+ {
+ for (i = 0; i < ec_master_count; i++)
+ {
+ if (ec_masters_reserved[i]) {
+ printk(KERN_WARNING "EtherCAT: Warning -"
+ " Master %i is still in use!\n", i);
+ }
+
+ ec_master_clear(&ec_masters[i]);
+ }
+
+ kfree(ec_masters);
+ }
+
+ printk(KERN_ERR "EtherCAT: Master driver cleaned up.\n");
+}
+
+/******************************************************************************
+ *
+ * Treiberschnittstelle
+ *
+ *****************************************************************************/
+
+/**
+ Setzt das EtherCAT-Geraet, auf dem der Master arbeitet.
+
+
+ @param master Der EtherCAT-Master
+ @param device Das EtherCAT-Geraet
+ @return 0, wenn alles o.k.,
+ < 0, wenn bereits ein Geraet registriert
+ oder das Geraet nicht geoeffnet werden konnte.
+*/
+
+ec_device_t *EtherCAT_dev_register(unsigned int master_index,
+ struct net_device *dev,
+ irqreturn_t (*isr)(int, void *,
+ struct pt_regs *),
+ struct module *module)
+{
+ ec_device_t *ecd;
+
+ if (master_index >= ec_master_count) {
+ printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", master_index);
+ return NULL;
+ }
+
+ if (!dev) {
+ printk("EtherCAT: Device is NULL!\n");
+ return NULL;
+ }
+
+ if (ec_masters[master_index].device_registered) {
+ printk(KERN_ERR "EtherCAT: Master %i already has a device!\n",
+ master_index);
+ return NULL;
+ }
+
+ ecd = &ec_masters[master_index].device;
+
+ if (ec_device_init(ecd) < 0) {
+ return NULL;
+ }
+
+ ecd->dev = dev;
+ ecd->tx_skb->dev = dev;
+ ecd->rx_skb->dev = dev;
+ ecd->isr = isr;
+ ecd->module = module;
+
+ return ecd;
+}
+
+/*****************************************************************************/
+
+/**
+ Loescht das EtherCAT-Geraet, auf dem der Master arbeitet.
+
+ @param master Der EtherCAT-Master
+ @param device Das EtherCAT-Geraet
+*/
+
+void EtherCAT_dev_unregister(unsigned int master_index)
+{
+ if (master_index >= ec_master_count) {
+ printk(KERN_WARNING "EtherCAT: Master %i does not exist!\n", master_index);
+ return;
+ }
+
+ ec_masters[master_index].device_registered = 0;
+ ec_device_clear(&ec_masters[master_index].device);
+}
+
+/******************************************************************************
+ *
+ * Echtzeitschnittstelle
+ *
+ *****************************************************************************/
+
+/**
+ Reserviert einen bestimmten EtherCAT-Master und das zugehörige Gerät.
+
+ Gibt einen Zeiger auf den reservierten EtherCAT-Master zurueck.
+
+ @param index Index des gewuenschten Masters
+ @returns Zeiger auf EtherCAT-Master oder NULL, wenn Parameter ungueltig.
+*/
+
+ec_master_t *EtherCAT_rt_request_master(int index)
+{
+ ec_master_t *master;
+
+ if (index < 0 || index >= ec_master_count) {
+ printk(KERN_ERR "EtherCAT: Master %i does not exist!\n", index);
+ goto req_return;
+ }
+
+ if (ec_masters_reserved[index]) {
+ printk(KERN_ERR "EtherCAT: Master %i already in use!\n", index);
+ goto req_return;
+ }
+
+ master = &ec_masters[index];
+
+ if (!master->device_registered) {
+ printk(KERN_ERR "EtherCAT: Master %i has no device assigned yet!\n",
+ index);
+ goto req_return;
+ }
+
+ if (!try_module_get(master->device.module)) {
+ printk(KERN_ERR "EtherCAT: Could not reserve device module!\n");
+ goto req_return;
+ }
+
+ if (ec_master_open(master) < 0) {
+ printk(KERN_ERR "EtherCAT: Could not open device!\n");
+ goto req_module_put;
+ }
+
+ if (ec_scan_for_slaves(master) != 0) {
+ printk(KERN_ERR "EtherCAT: Could not scan for slaves!\n");
+ goto req_close;
+ }
+
+ ec_masters_reserved[index] = 1;
+ printk(KERN_INFO "EtherCAT: Reserved master %i.\n", index);
+
+ return master;
+
+ req_close:
+ ec_master_close(master);
+
+ req_module_put:
+ module_put(master->device.module);
+
+ req_return:
+ return NULL;
+}
+
+/*****************************************************************************/
+
+/**
+ Gibt einen zuvor angeforderten EtherCAT-Master wieder frei.
+
+ @param master Zeiger auf den freizugebenden EtherCAT-Master.
+*/
+
+void EtherCAT_rt_release_master(ec_master_t *master)
+{
+ unsigned int i;
+
+ for (i = 0; i < ec_master_count; i++)
+ {
+ if (&ec_masters[i] == master)
+ {
+ if (!master->device_registered) {
+ printk(KERN_WARNING "EtherCAT: Could not release device"
+ "module because of no device!\n");
+ return;
+ }
+
+ ec_master_close(master);
+ module_put(master->device.module);
+ ec_masters_reserved[i] = 0;
+
+ printk(KERN_INFO "EtherCAT: Released master %i.\n", i);
+
+ return;
+ }
+ }
+
+ printk(KERN_WARNING "EtherCAT: Master %X was never requested!\n",
+ (unsigned int) master);
+}
+
+/*****************************************************************************/
+
+module_init(ec_init_module);
+module_exit(ec_cleanup_module);
+
+EXPORT_SYMBOL(EtherCAT_dev_register);
+EXPORT_SYMBOL(EtherCAT_dev_unregister);
+EXPORT_SYMBOL(EtherCAT_rt_request_master);
+EXPORT_SYMBOL(EtherCAT_rt_release_master);
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,200 @@
+/******************************************************************************
+ *
+ * s l a v e . c
+ *
+ * Methoden für einen EtherCAT-Slave.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "slave.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Slave-Konstruktor.
+
+ Initialisiert einen EtherCAT-Slave.
+
+ ACHTUNG! Dieser Konstruktor wird quasi nie aufgerufen. Bitte immer das
+ Makro ECAT_INIT_SLAVE() in ec_slave.h anpassen!
+
+ @param slave Zeiger auf den zu initialisierenden Slave
+*/
+
+void ec_slave_init(ec_slave_t *slave)
+{
+ slave->type = 0;
+ slave->revision = 0;
+ slave->build = 0;
+ slave->ring_position = 0;
+ slave->station_address = 0;
+ slave->vendor_id = 0;
+ slave->product_code = 0;
+ slave->revision_number = 0;
+ slave->serial_number = 0;
+ slave->desc = NULL;
+ slave->logical_address = 0;
+ slave->current_state = EC_SLAVE_STATE_UNKNOWN;
+ slave->requested_state = EC_SLAVE_STATE_UNKNOWN;
+ slave->process_data = NULL;
+ slave->domain = 0;
+ slave->error_reported = 0;
+}
+
+/*****************************************************************************/
+
+#if 0
+/**
+ Liest einen bestimmten Kanal des Slaves als Integer-Wert.
+
+ Prüft zuerst, ob der entsprechende Slave eine
+ bekannte Beschreibung besitzt, ob dort eine
+ read()-Funktion hinterlegt ist und ob die angegebene
+ Kanalnummer gültig ist. Wenn ja, wird der dekodierte
+ Wert zurückgegeben, sonst ist der Wert 0.
+
+ @param slave EtherCAT-Slave
+ @param channel Kanalnummer
+
+ @return Gelesener Wert bzw. 0
+*/
+
+int EtherCAT_read_value(EtherCAT_slave_t *slave,
+ unsigned int channel)
+{
+ if (unlikely(!slave->desc)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Reading failed on slave %04X (addr %0X)"
+ " - Slave has no description.\n",
+ slave->station_address, (unsigned int) slave);
+ slave->error_reported = 1;
+ }
+ return 0;
+ }
+
+ if (unlikely(!slave->desc->read)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Reading failed on slave %04X (addr %0X)"
+ " - Slave type (%s %s) has no read method.\n",
+ slave->station_address, (unsigned int) slave,
+ slave->desc->vendor_name, slave->desc->product_name);
+ slave->error_reported = 1;
+ }
+ return 0;
+ }
+
+ if (unlikely(channel >= slave->desc->channel_count)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Reading failed on slave %4X (addr %0X)"
+ " - Type (%s %s) has no channel %i.\n",
+ slave->station_address, (unsigned int) slave,
+ slave->desc->vendor_name, slave->desc->product_name,
+ channel);
+ slave->error_reported = 1;
+ }
+ return 0;
+ }
+
+ if (unlikely(!slave->process_data)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Reading failed on slave %4X (addr %0X)"
+ " - Slave does not belong to any process data object!\n",
+ slave->station_address, (unsigned int) slave);
+ slave->error_reported = 1;
+ }
+ return 0;
+ }
+
+ if (unlikely(slave->error_reported))
+ slave->error_reported = 0;
+
+ return slave->desc->read(slave->process_data, channel);
+}
+
+/*****************************************************************************/
+
+/**
+ Schreibt einen bestimmten Kanal des Slaves als Integer-Wert .
+
+ Prüft zuerst, ob der entsprechende Slave eine
+ bekannte Beschreibung besitzt, ob dort eine
+ write()-Funktion hinterlegt ist und ob die angegebene
+ Kanalnummer gültig ist. Wenn ja, wird der Wert entsprechend
+ kodiert und geschrieben.
+
+ @param slave EtherCAT-Slave
+ @param channel Kanalnummer
+ @param value Zu schreibender Wert
+*/
+
+void EtherCAT_write_value(EtherCAT_slave_t *slave,
+ unsigned int channel,
+ int value)
+{
+ if (unlikely(!slave->desc)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Writing failed on slave %04X (addr %0X)"
+ " - Slave has no description.\n",
+ slave->station_address, (unsigned int) slave);
+ slave->error_reported = 1;
+ }
+ return;
+ }
+
+ if (unlikely(!slave->desc->write)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Writing failed on slave %04X (addr %0X)"
+ " - Type (%s %s) has no write method.\n",
+ slave->station_address, (unsigned int) slave,
+ slave->desc->vendor_name, slave->desc->product_name);
+ slave->error_reported = 1;
+ }
+ return;
+ }
+
+ if (unlikely(channel >= slave->desc->channel_count)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Writing failed on slave %4X (addr %0X)"
+ " - Type (%s %s) has no channel %i.\n",
+ slave->station_address, (unsigned int) slave,
+ slave->desc->vendor_name, slave->desc->product_name,
+ channel);
+ slave->error_reported = 1;
+ }
+ return;
+ }
+
+ if (unlikely(!slave->process_data)) {
+ if (likely(slave->error_reported)) {
+ printk(KERN_WARNING "EtherCAT: Writing failed on slave %4X (addr %0X)"
+ " - Slave does not belong to any process data object!\n",
+ slave->station_address, (unsigned int) slave);
+ slave->error_reported = 1;
+ }
+ return;
+ }
+
+ if (unlikely(slave->error_reported))
+ slave->error_reported = 0;
+
+ slave->desc->write(slave->process_data, channel, value);
+}
+
+/*****************************************************************************/
+
+EXPORT_SYMBOL(EtherCAT_write_value);
+EXPORT_SYMBOL(EtherCAT_read_value);
+#endif
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/slave.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * s l a v e . h
+ *
+ * Struktur für einen EtherCAT-Slave.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_SLAVE_H_
+#define _EC_SLAVE_H_
+
+#include "types.h"
+
+/*****************************************************************************/
+
+/**
+ EtherCAT-Slave
+
+ Achtung: Bei Änderungen dieser Struktur immer das Define
+ ECAT_INIT_SLAVE anpassen!
+*/
+
+typedef struct
+{
+ // Base data
+ unsigned char type; /**< Slave-Typ */
+ unsigned char revision; /**< Revision */
+ unsigned short build; /**< Build-Nummer */
+
+ // Addresses
+ short ring_position; /**< (Negative) Position des Slaves im Bus */
+ unsigned short station_address; /**< Konfigurierte Slave-Adresse */
+
+ // Slave information interface
+ unsigned int vendor_id; /**< Identifikationsnummer des Herstellers */
+ unsigned int product_code; /**< Herstellerspezifischer Produktcode */
+ unsigned int revision_number; /**< Revisionsnummer */
+ unsigned int serial_number; /**< Seriennummer der Klemme */
+
+ const ec_slave_desc_t *desc; /**< Zeiger auf die Beschreibung
+ des Slave-Typs */
+
+ unsigned int logical_address; /**< Konfigurierte, logische adresse */
+
+ ec_slave_state_t current_state; /**< Aktueller Zustand */
+ ec_slave_state_t requested_state; /**< Angeforderter Zustand */
+
+ unsigned char *process_data; /**< Zeiger auf den Speicherbereich
+ innerhalb eines Prozessdatenobjekts */
+ unsigned int domain; /**< Prozessdatendomäne */
+ int error_reported; /**< Ein Zugriffsfehler wurde bereits gemeldet */
+}
+ec_slave_t;
+
+#define EC_INIT_SLAVE(TYPE, DOMAIN) {0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ TYPE, 0, ECAT_STATE_UNKNOWN, \
+ EC_STATE_UNKNOWN, NULL, DOMAIN, 0}
+
+/*****************************************************************************/
+
+// Slave construction and deletion
+void ec_slave_init(ec_slave_t *);
+
+#if 0
+int EtherCAT_read_value(EtherCAT_slave_t *, unsigned int);
+void EtherCAT_write_value(EtherCAT_slave_t *, unsigned int, int);
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:2 ***
+;;; End: ***
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/types.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,186 @@
+/******************************************************************************
+ *
+ * t y p e s . c
+ *
+ * EtherCAT-Slave-Typen.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+
+#include "globals.h"
+#include "types.h"
+
+/*****************************************************************************/
+
+/* Konfigurationen der Sync-Manager */
+
+unsigned char sm0_multi[] = {0x00, 0x18, 0xF6, 0x00, 0x26, 0x00, 0x01, 0x00};
+unsigned char sm1_multi[] = {0xF6, 0x18, 0xF6, 0x00, 0x22, 0x00, 0x01, 0x00};
+
+unsigned char sm0_1014[] = {0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
+
+unsigned char sm0_2004[] = {0x00, 0x0F, 0x01, 0x00, 0x46, 0x00, 0x01, 0x00};
+
+unsigned char sm2_31xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00};
+unsigned char sm3_31xx[] = {0x00, 0x11, 0x06, 0x00, 0x20, 0x00, 0x01, 0x00};
+
+unsigned char sm2_41xx[] = {0x00, 0x10, 0x04, 0x00, 0x24, 0x00, 0x01, 0x00};
+
+/* Konfigurationen der Memory-Management-Units */
+
+unsigned char fmmu0_1014[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+ 0x00, 0x10, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_2004[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
+ 0x00, 0x0F, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_31xx[] = {0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07,
+ 0x00, 0x11, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00};
+
+unsigned char fmmu0_41xx[] = {0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07,
+ 0x00, 0x10, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00};
+
+/*****************************************************************************/
+
+/* Lese- und Schreibfunktionen */
+
+int read_1014(unsigned char *data, unsigned int channel)
+{
+ return (data[0] >> channel) & 0x01;
+}
+
+void write_2004(unsigned char *data, unsigned int channel, int value)
+{
+ if (value) {
+ data[0] |= (1 << channel);
+ }
+ else {
+ data[0] &= ~(1 << channel);
+ }
+}
+
+int read_31xx(unsigned char *data, unsigned int channel)
+{
+ return (short int) ((data[channel * 3 + 2] << 8) | data[channel * 3 + 1]);
+}
+
+void write_41xx(unsigned char *data, unsigned int channel, int value)
+{
+ data[channel * 3 + 1] = (value & 0xFF00) >> 8;
+ data[channel * 3 + 2] = value & 0xFF;
+}
+
+/*****************************************************************************/
+
+/* Klemmen-Objekte */
+
+ec_slave_desc_t Beckhoff_EK1100[] =
+{{
+ "Beckhoff", "EK1100", "Bus Coupler",
+ EC_NOSYNC_SLAVE,
+ NULL, NULL, NULL, NULL,
+ NULL,
+ 0, 0,
+ NULL, NULL
+}};
+
+ec_slave_desc_t Beckhoff_EL1014[] =
+{{
+ "Beckhoff", "EL1014", "4x Digital Input",
+ EC_SIMPLE_SLAVE,
+ sm0_1014, NULL, NULL, NULL,
+ fmmu0_1014,
+ 1, 4,
+ read_1014, NULL
+}};
+
+ec_slave_desc_t Beckhoff_EL2004[] =
+{{
+ "Beckhoff", "EL2004", "4x Digital Output",
+ EC_SIMPLE_SLAVE,
+ sm0_2004, NULL, NULL, NULL,
+ fmmu0_2004,
+ 1, 4,
+ NULL, write_2004
+}};
+
+ec_slave_desc_t Beckhoff_EL3102[] =
+{{
+ "Beckhoff", "EL3102", "2x Analog Input diff.",
+ EC_MAILBOX_SLAVE,
+ sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+ fmmu0_31xx,
+ 6, 2,
+ read_31xx, NULL
+}};
+
+ec_slave_desc_t Beckhoff_EL3162[] =
+{{
+ "Beckhoff", "EL3162", "2x Analog Input",
+ EC_MAILBOX_SLAVE,
+ sm0_multi, sm1_multi, sm2_31xx, sm3_31xx,
+ fmmu0_31xx,
+ 6, 2,
+ read_31xx, NULL
+}};
+
+ec_slave_desc_t Beckhoff_EL4102[] =
+{{
+ "Beckhoff", "EL4102", "2x Analog Output",
+ EC_MAILBOX_SLAVE,
+ sm0_multi, sm1_multi, sm2_41xx, NULL,
+ fmmu0_41xx,
+ 4, 2,
+ NULL, write_41xx
+}};
+
+ec_slave_desc_t Beckhoff_EL4132[] =
+{{
+ "Beckhoff", "EL4132", "2x Analog Output diff.",
+ EC_MAILBOX_SLAVE,
+ sm0_multi, sm1_multi, sm2_41xx, NULL,
+ fmmu0_41xx,
+ 4, 2,
+ NULL, write_41xx
+}};
+
+ec_slave_desc_t Beckhoff_EL5001[] =
+{{
+ "Beckhoff", "EL5001", "SSI-Interface",
+ EC_SIMPLE_SLAVE,
+ NULL, NULL, NULL, NULL, // Noch nicht eingepflegt...
+ NULL,
+ 0, 0,
+ NULL, NULL
+}};
+
+/*****************************************************************************/
+
+/**
+ Beziehung zwischen Identifikationsnummern und Klemmen-Objekt.
+
+ Diese Tabelle stellt die Beziehungen zwischen bestimmten Kombinationen
+ aus Vendor-IDs und Product-Codes und der entsprechenden Klemme her.
+ Neue Klemmen müssen hier eingetragen werden.
+*/
+
+ec_slave_ident_t slave_idents[] =
+{
+ {0x00000002, 0x03F63052, Beckhoff_EL1014},
+ {0x00000002, 0x044C2C52, Beckhoff_EK1100},
+ {0x00000002, 0x07D43052, Beckhoff_EL2004},
+ {0x00000002, 0x0C1E3052, Beckhoff_EL3102},
+ {0x00000002, 0x0C5A3052, Beckhoff_EL3162},
+ {0x00000002, 0x10063052, Beckhoff_EL4102},
+ {0x00000002, 0x10243052, Beckhoff_EL4132},
+ {0x00000002, 0x13893052, Beckhoff_EL5001}
+};
+
+unsigned int slave_ident_count = sizeof(slave_idents)
+ / sizeof(ec_slave_ident_t);
+
+
+/*****************************************************************************/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/master/types.h Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * t y p e s . h
+ *
+ * EtherCAT-Slave-Typen.
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#ifndef _EC_TYPES_H_
+#define _EC_TYPES_H_
+
+/*****************************************************************************/
+
+/**
+ Typ eines EtherCAT-Slaves.
+
+ Dieser Typ muss für die Konfiguration bekannt sein. Der
+ Master entscheidet danach, ober bspw. Mailboxes konfigurieren,
+ oder Sync-Manager setzen soll.
+*/
+
+typedef enum
+{
+ EC_SIMPLE_SLAVE, EC_MAILBOX_SLAVE, EC_NOSYNC_SLAVE
+}
+ec_slave_type_t;
+
+/*****************************************************************************/
+
+/**
+ Beschreibung eines EtherCAT-Slave-Typs.
+
+ Diese Beschreibung dient zur Konfiguration einer bestimmten
+ Slave-Art. Sie enthält die Konfigurationsdaten für die
+ Slave-internen Sync-Manager und FMMU's.
+*/
+
+typedef struct slave_desc
+{
+ const char *vendor_name; /**< Name des Herstellers */
+ const char *product_name; /**< Name des Slaves-Typs */
+ const char *product_desc; /**< Genauere Beschreibung des Slave-Typs */
+
+ const ec_slave_type_t type; /**< Art des Slave-Typs */
+
+ const unsigned char *sm0; /**< Konfigurationsdaten des
+ ersten Sync-Managers */
+ const unsigned char *sm1; /**< Konfigurationsdaten des
+ zweiten Sync-Managers */
+ const unsigned char *sm2; /**< Konfigurationsdaten des
+ dritten Sync-Managers */
+ const unsigned char *sm3; /**< Konfigurationsdaten des
+ vierten Sync-Managers */
+
+ const unsigned char *fmmu0; /**< Konfigurationsdaten
+ der ersten FMMU */
+
+ const unsigned int process_data_size; /**< Länge der Prozessdaten in Bytes */
+ const unsigned int channel_count; /**< Anzahl der Kanäle */
+
+ int (*read) (unsigned char *, unsigned int); /**< Funktion zum Dekodieren
+ und Lesen der Kanaldaten */
+ void (*write) (unsigned char *, unsigned int, int); /**< Funktion zum
+ Kodieren und Schreiben
+ der Kanaldaten */
+}
+ec_slave_desc_t;
+
+/*****************************************************************************/
+
+/**
+ Identifikation eines Slave-Typs.
+
+ Diese Struktur wird zur 1:n-Zuordnung von Hersteller- und
+ Produktcodes zu den einzelnen Slave-Typen verwendet.
+*/
+
+typedef struct slave_ident
+{
+ const unsigned int vendor_id; /**< Hersteller-Code */
+ const unsigned int product_code; /**< Herstellerspezifischer Produktcode */
+ const ec_slave_desc_t *desc; /**< Zeiger auf den dazugehörigen
+ Slave-Typ */
+}
+ec_slave_ident_t;
+
+extern ec_slave_ident_t slave_idents[]; /**< Statisches Array der
+ Slave-Identifikationen */
+extern unsigned int slave_ident_count; /**< Anzahl der vorhandenen
+ Slave-Identifikationen */
+
+/*****************************************************************************/
+
+#endif
--- a/mini/Makefile Fri Jan 13 15:47:44 2006 +0000
+++ b/mini/Makefile Tue Jan 17 18:28:15 2006 +0000
@@ -13,9 +13,9 @@
#----------------------------------------------------------------
# Kbuild-Abschnitt
-obj-m := ec_mini_mod.o
+obj-m := ec_mini.o
-ec_mini_mod-objs := ec_mini.o
+ec_mini-objs := mini.o
#----------------------------------------------------------------
--- a/mini/ec_mini.c Fri Jan 13 15:47:44 2006 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-/******************************************************************************
- *
- * ec_mini.c
- *
- * Minimalmodul für EtherCAT
- *
- * $Id$
- *
- *****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-
-#include "../drivers/ec_master.h"
-#include "../drivers/ec_device.h"
-#include "../drivers/ec_types.h"
-#include "../drivers/ec_module.h"
-
-/*****************************************************************************/
-
-// Auskommentieren, wenn keine zyklischen Daten erwuenscht
-#define ECAT_CYCLIC_DATA
-
-/*****************************************************************************/
-
-static EtherCAT_master_t *ecat_master = NULL;
-
-static EtherCAT_slave_t ecat_slaves[] =
-{
-#if 0
- // Block 1
- ECAT_INIT_SLAVE(Beckhoff_EK1100, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL4102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3162, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
-
- ECAT_INIT_SLAVE(Beckhoff_EL4102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL4102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL4102, 1),
-
- ECAT_INIT_SLAVE(Beckhoff_EL3162, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3162, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3162, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3102, 1),
-
-#endif
-
-#if 1
- // Block 2
- ECAT_INIT_SLAVE(Beckhoff_EK1100, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL4102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3162, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL3102, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
-
- // Block 3
- ECAT_INIT_SLAVE(Beckhoff_EK1100, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL2004, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1),
- ECAT_INIT_SLAVE(Beckhoff_EL1014, 1)
-#endif
-};
-
-#define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t))
-
-#ifdef ECAT_CYCLIC_DATA
-
-int value;
-int dig1;
-
-struct timer_list timer;
-unsigned long last_start_jiffies;
-
-#endif // ECAT_CYCLIC_DATA
-
-/******************************************************************************
- *
- * Function: next2004
- *
- *****************************************************************************/
-
-#ifdef ECAT_CYCLIC_DATA
-
-static int next2004(int *wrap)
-{
- static int i = 0;
- unsigned int j = 0;
-
- *wrap = 0;
-
- for (j = 0; j < ECAT_SLAVES_COUNT; j++)
- {
- i++;
-
- i %= ECAT_SLAVES_COUNT;
-
- if (i == 0) *wrap = 1;
-
- if (ecat_slaves[i].desc == Beckhoff_EL2004)
- {
- return i;
- }
- }
-
- return -1;
-}
-#endif
-
-/******************************************************************************
- *
- * Function: run
- *
- * Beschreibung: Zyklischer Prozess
- *
- *****************************************************************************/
-
-#ifdef ECAT_CYCLIC_DATA
-
-static void run(unsigned long data)
-{
- static int ms = 0;
- static int cnt = 0;
- static unsigned long int k = 0;
- static int firstrun = 1;
-
- static int klemme = 0;
- static int kanal = 0;
- static int up_down = 0;
- int wrap = 0;
-
- ms++;
- ms %= 1000;
-
- if (firstrun) klemme = next2004(&wrap);
-
- if (cnt++ > 20)
- {
- cnt = 0;
-
- if (++kanal > 3)
- {
- kanal = 0;
- klemme = next2004(&wrap);
-
- if (wrap == 1)
- {
- if (up_down == 1) up_down = 0;
- else up_down = 1;
- }
- }
- }
-
- if (klemme >= 0)
- EtherCAT_write_value(&ecat_slaves[klemme], kanal, up_down);
-
- // Prozessdaten lesen und schreiben
- rdtscl(k);
- EtherCAT_process_data_cycle(ecat_master, 1, 100);
- firstrun = 0;
-
- timer.expires += HZ / 1000;
- add_timer(&timer);
-}
-
-#endif // ECAT_CYCLIC_DATA
-
-/******************************************************************************
- *
- * Function: init
- *
- *****************************************************************************/
-
-int __init init_module()
-{
- unsigned int i;
-
- printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
-
- if ((ecat_master = EtherCAT_request(0)) == NULL) {
- printk(KERN_ERR "EtherCAT master 0 not available!\n");
- goto out_return;
- }
-
- printk("Checking EtherCAT slaves.\n");
-
- if (EtherCAT_check_slaves(ecat_master, ecat_slaves,
- ECAT_SLAVES_COUNT) != 0) {
- printk(KERN_ERR "EtherCAT: Could not init slaves!\n");
- goto out_release_master;
- }
-
- printk("Activating all EtherCAT slaves.\n");
-
- for (i = 0; i < ECAT_SLAVES_COUNT; i++) {
- if (EtherCAT_activate_slave(ecat_master, &ecat_slaves[i]) != 0) {
- printk(KERN_ERR "EtherCAT: Could not activate slave %i!\n", i);
- goto out_release_master;
- }
- }
-
-#ifdef ECAT_CYCLIC_DATA
- printk("Starting cyclic sample thread.\n");
-
- init_timer(&timer);
-
- timer.function = run;
- timer.data = 0;
- timer.expires = jiffies+10; // Das erste Mal sofort feuern
- last_start_jiffies = timer.expires;
- add_timer(&timer);
-
- printk("Initialised sample thread.\n");
-#endif
-
- printk(KERN_INFO "=== Minimal EtherCAT environment started. ===\n");
-
- return 0;
-
- out_release_master:
- EtherCAT_release(ecat_master);
-
- out_return:
- return -1;
-}
-
-/******************************************************************************
- *
- * Function: cleanup
- *
- *****************************************************************************/
-
-void __exit cleanup_module()
-{
- unsigned int i;
-
- printk(KERN_INFO "=== Stopping Minimal EtherCAT environment... ===\n");
-
- if (ecat_master)
- {
-#ifdef ECAT_CYCLIC_DATA
- del_timer_sync(&timer);
-#endif // ECAT_CYCLIC_DATA
-
- printk(KERN_INFO "Deactivating slaves.\n");
-
- for (i = 0; i < ECAT_SLAVES_COUNT; i++) {
- EtherCAT_deactivate_slave(ecat_master, &ecat_slaves[i]);
- }
-
- EtherCAT_release(ecat_master);
- }
-
- printk(KERN_INFO "=== Minimal EtherCAT environment stopped. ===\n");
-}
-
-/*****************************************************************************/
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
-MODULE_DESCRIPTION ("Minimal EtherCAT environment");
-
-module_init(init_module);
-module_exit(cleanup_module);
-
-/*****************************************************************************/
-
-/* Emacs-Konfiguration
-;;; Local Variables: ***
-;;; c-basic-offset:4 ***
-;;; End: ***
-*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mini/mini.c Tue Jan 17 18:28:15 2006 +0000
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * m i n i . c
+ *
+ * Minimalmodul für EtherCAT
+ *
+ * $Id$
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include "../include/EtherCAT_rt.h"
+
+/*****************************************************************************/
+
+// Auskommentieren, wenn keine zyklischen Daten erwuenscht
+#define ECAT_CYCLIC_DATA
+
+/*****************************************************************************/
+
+ec_master_t *master = NULL;
+
+#ifdef ECAT_CYCLIC_DATA
+
+int value;
+int dig1;
+
+struct timer_list timer;
+unsigned long last_start_jiffies;
+
+#endif // ECAT_CYCLIC_DATA
+
+/******************************************************************************
+ *
+ * Function: run
+ *
+ * Beschreibung: Zyklischer Prozess
+ *
+ *****************************************************************************/
+
+#ifdef ECAT_CYCLIC_DATA
+
+static void run(unsigned long data)
+{
+ static int ms = 0;
+ static unsigned long int k = 0;
+ static int firstrun = 1;
+
+ ms++;
+ ms %= 1000;
+
+#if 0
+ if (klemme >= 0)
+ EtherCAT_write_value(&ecat_slaves[klemme], kanal, up_down);
+#endif
+
+ // Prozessdaten lesen und schreiben
+ rdtscl(k);
+ EtherCAT_rt_domain_cycle(master, 1, 100);
+ firstrun = 0;
+
+ timer.expires += HZ / 1000;
+ add_timer(&timer);
+}
+
+#endif // ECAT_CYCLIC_DATA
+
+/******************************************************************************
+ *
+ * Function: init
+ *
+ *****************************************************************************/
+
+int __init init_mini_module(void)
+{
+ printk(KERN_INFO "=== Starting Minimal EtherCAT environment... ===\n");
+
+ if ((master = EtherCAT_rt_request_master(0)) == NULL) {
+ printk(KERN_ERR "EtherCAT master 0 not available!\n");
+ goto out_return;
+ }
+
+ //check_slaves();
+
+ printk("Activating all EtherCAT slaves.\n");
+
+ if (EtherCAT_rt_activate_slaves(master) != 0) {
+ printk(KERN_ERR "EtherCAT: Could not activate slaves!\n");
+ goto out_release_master;
+ }
+
+#ifdef ECAT_CYCLIC_DATA
+ printk("Starting cyclic sample thread.\n");
+
+ init_timer(&timer);
+
+ timer.function = run;
+ timer.data = 0;
+ timer.expires = jiffies+10; // Das erste Mal sofort feuern
+ last_start_jiffies = timer.expires;
+ add_timer(&timer);
+
+ printk("Initialised sample thread.\n");
+#endif
+
+ printk(KERN_INFO "=== Minimal EtherCAT environment started. ===\n");
+
+ return 0;
+
+ out_release_master:
+ EtherCAT_rt_release_master(master);
+
+ out_return:
+ return -1;
+}
+
+/******************************************************************************
+ *
+ * Function: cleanup
+ *
+ *****************************************************************************/
+
+void __exit cleanup_mini_module(void)
+{
+ printk(KERN_INFO "=== Stopping Minimal EtherCAT environment... ===\n");
+
+ if (master)
+ {
+#ifdef ECAT_CYCLIC_DATA
+ del_timer_sync(&timer);
+#endif // ECAT_CYCLIC_DATA
+
+ printk(KERN_INFO "Deactivating slaves.\n");
+
+ EtherCAT_rt_deactivate_slaves(master);
+ EtherCAT_rt_release_master(master);
+ }
+
+ printk(KERN_INFO "=== Minimal EtherCAT environment stopped. ===\n");
+}
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Florian Pose <fp@igh-essen.com>");
+MODULE_DESCRIPTION ("Minimal EtherCAT environment");
+
+module_init(init_mini_module);
+module_exit(cleanup_mini_module);
+
+/*****************************************************************************/
+
+/* Emacs-Konfiguration
+;;; Local Variables: ***
+;;; c-basic-offset:4 ***
+;;; End: ***
+*/
--- a/rt/msr_module.c Fri Jan 13 15:47:44 2006 +0000
+++ b/rt/msr_module.c Tue Jan 17 18:28:15 2006 +0000
@@ -32,10 +32,7 @@
#include "msr_jitter.h"
// EtherCAT
-#include "../drivers/ec_master.h"
-#include "../drivers/ec_device.h"
-#include "../drivers/ec_types.h"
-#include "../drivers/ec_module.h"
+#include "../include/EtherCAT_rt.h"
// Defines/Makros
#define TSC2US(T1, T2) ((T2 - T1) * 1000UL / cpu_khz)
@@ -54,16 +51,18 @@
// EtherCAT
-static EtherCAT_master_t *ecat_master = NULL;
+ec_master_t *master = NULL;
static unsigned int ecat_bus_time = 0;
static unsigned int ecat_timeouts = 0;
-static EtherCAT_slave_t ecat_slaves[] =
+#if 0
+static ec_slave_t slaves[] =
{
// Block 1
ECAT_INIT_SLAVE(Beckhoff_EK1100, 0),
ECAT_INIT_SLAVE(Beckhoff_EL3102, 0)
};
+#endif
#define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t))
@@ -87,20 +86,22 @@
// Prozessdaten lesen
msr_jitter_run(MSR_ABTASTFREQUENZ);
+#if 0
if (debug_counter == 0) {
- ecat_master->debug_level = 2;
- }
-
- // Prozessdaten schreiben
-
- if (EtherCAT_process_data_cycle(ecat_master, 0, 40) < 0)
- ecat_timeouts++;
-
+ master->debug_level = 2;
+ }
+#endif
+
+ // Prozessdaten lesen und schreiben
+ EtherCAT_rt_domain_cycle(master, 0, 40);
+
+#if 0
if (debug_counter == 0) {
- ecat_master->debug_level = 0;
- }
-
- value = EtherCAT_read_value(&ecat_slaves[1], 0);
+ master->debug_level = 0;
+ }
+#endif
+
+ // value = EtherCAT_read_value(&ecat_slaves[1], 0);
debug_counter++;
if (debug_counter >= MSR_ABTASTFREQUENZ * 5) debug_counter = 0;
@@ -183,9 +184,8 @@
* the init/clean material
*****************************************************************************/
-int __init init_module()
-{
- unsigned int i;
+int __init init_rt_module(void)
+{
struct ipipe_domain_attr attr; //ipipe
// Als allererstes die RT-lib initialisieren
@@ -200,25 +200,24 @@
printk(KERN_INFO "=== Starting EtherCAT environment... ===\n");
- if ((ecat_master = EtherCAT_request(0)) == NULL) {
+ if ((master = EtherCAT_rt_request_master(0)) == NULL) {
printk(KERN_ERR "EtherCAT master 0 not available!\n");
goto out_msr_cleanup;
}
+#if 0
printk("Checking EtherCAT slaves.\n");
-
- if (EtherCAT_check_slaves(ecat_master, ecat_slaves, ECAT_SLAVES_COUNT) != 0) {
+ if (EtherCAT_check_slaves(master, ecat_slaves, ECAT_SLAVES_COUNT) != 0) {
printk(KERN_ERR "EtherCAT: Could not init slaves!\n");
goto out_release_master;
}
+#endif
printk("Activating all EtherCAT slaves.\n");
- for (i = 0; i < ECAT_SLAVES_COUNT; i++) {
- if (EtherCAT_activate_slave(ecat_master, ecat_slaves + i) < 0) {
- printk(KERN_ERR "EtherCAT: Could not activate slave %i!\n", i);
- goto out_release_master;
- }
+ if (EtherCAT_rt_activate_slaves(master) < 0) {
+ printk(KERN_ERR "EtherCAT: Could not activate slaves!\n");
+ goto out_release_master;
}
do_gettimeofday(&process_time);
@@ -234,7 +233,7 @@
return 0;
out_release_master:
- EtherCAT_release(ecat_master);
+ EtherCAT_rt_release_master(master);
out_msr_cleanup:
msr_rtlib_cleanup();
@@ -245,28 +244,24 @@
/*****************************************************************************/
-void __exit cleanup_module()
-{
- unsigned int i;
-
+void __exit cleanup_rt_module(void)
+{
msr_print_info("msk_modul: unloading...");
ipipe_tune_timer(1000000000UL / HZ, 0); //alten Timertakt wieder herstellen
ipipe_unregister_domain(&this_domain);
- if (ecat_master)
+ if (master)
{
printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n");
printk(KERN_INFO "Deactivating slaves.\n");
- for (i = 0; i < ECAT_SLAVES_COUNT; i++) {
- if (EtherCAT_deactivate_slave(ecat_master, ecat_slaves + i) < 0) {
- printk(KERN_WARNING "Warning - Could not deactivate slave!\n");
- }
+ if (EtherCAT_rt_deactivate_slaves(master) < 0) {
+ printk(KERN_WARNING "Warning - Could not deactivate slaves!\n");
}
- EtherCAT_release(ecat_master);
+ EtherCAT_rt_release_master(master);
printk(KERN_INFO "=== EtherCAT environment stopped. ===\n");
}
@@ -282,7 +277,7 @@
MODULE_AUTHOR ("Wilhelm Hagemeister <hm@igh-essen.com>");
MODULE_DESCRIPTION ("EtherCAT test environment");
-module_init(init_module);
-module_exit(cleanup_module);
-
-/*****************************************************************************/
+module_init(init_rt_module);
+module_exit(cleanup_rt_module);
+
+/*****************************************************************************/