linux/drivers/net/ethernet/smsc/smc91c92_cs.c

/*======================================================================

    A PCMCIA ethernet driver for SMC91c92-based cards.

    This driver supports Megahertz PCMCIA ethernet cards; and
    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
    multifunction cards.

    Copyright (C) 1999 David A. Hinds -- [email protected]

    smc91c92_cs.c 1.122 2002/10/25 06:26:39

    This driver contains code written by Donald Becker
    ([email protected]), Rowan Hughes ([email protected]),
    David Hinds ([email protected]), and Erik Stahlman
    ([email protected]).  Donald wrote the SMC 91c92 code using parts of
    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
    incorporated some parts of his driver here.  I (Dave) wrote most
    of the PCMCIA glue code, and the Ositech support code.  Kelly
    Stephens ([email protected]) added support for the Motorola
    Mariner, with help from Allen Brost.

    This software may be used and distributed according to the terms of
    the GNU General Public License, incorporated herein by reference.

======================================================================*/

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/jiffies.h>
#include <linux/firmware.h>

#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/ss.h>

#include <asm/io.h>
#include <linux/uaccess.h>

/*====================================================================*/

static const char *if_names[] =;

/* Firmware name */
#define FIRMWARE_NAME

/* Module parameters */

MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_FIRMWARE();

#define INT_MODULE_PARM(n, v)

/*
  Transceiver/media type.
   0 = auto
   1 = 10baseT (and autoselect if #define AUTOSELECT),
   2 = AUI/10base2,
*/
INT_MODULE_PARM(if_port, 0);


#define DRV_NAME
#define DRV_VERSION

/*====================================================================*/

/* Operational parameter that usually are not changed. */

/* Time in jiffies before concluding Tx hung */
#define TX_TIMEOUT

/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
#define INTR_WORK

/* Times to check the check the chip before concluding that it doesn't
   currently have room for another Tx packet. */
#define MEMORY_WAIT_TIME

struct smc_private {};

/* Special definitions for Megahertz multifunction cards */
#define MEGAHERTZ_ISR

/* Special function registers for Motorola Mariner */
#define MOT_LAN
#define MOT_UART
#define MOT_EEPROM

#define MOT_NORMAL

/* Special function registers for Ositech cards */
#define OSITECH_AUI_CTL
#define OSITECH_PWRDOWN
#define OSITECH_RESET
#define OSITECH_ISR
#define OSITECH_AUI_PWR
#define OSITECH_RESET_ISR

#define OSI_AUI_PWR
#define OSI_LAN_PWRDOWN
#define OSI_MODEM_PWRDOWN
#define OSI_LAN_RESET
#define OSI_MODEM_RESET

/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
#define BANK_SELECT
#define SMC_SELECT_BANK(x)

/* Bank 0 registers. */
#define TCR
#define TCR_CLEAR
#define TCR_ENABLE
#define TCR_PAD_EN
#define TCR_MONCSN
#define TCR_FDUPLX
#define TCR_NORMAL

#define EPH
#define EPH_TX_SUC
#define EPH_SNGLCOL
#define EPH_MULCOL
#define EPH_LTX_MULT
#define EPH_16COL
#define EPH_SQET
#define EPH_LTX_BRD
#define EPH_TX_DEFR
#define EPH_LAT_COL
#define EPH_LOST_CAR
#define EPH_EXC_DEF
#define EPH_CTR_ROL
#define EPH_RX_OVRN
#define EPH_LINK_OK
#define EPH_TX_UNRN
#define MEMINFO
#define MEMCFG

/* Bank 1 registers. */
#define CONFIG
#define CFG_MII_SELECT
#define CFG_NO_WAIT
#define CFG_FULL_STEP
#define CFG_SET_SQLCH
#define CFG_AUI_SELECT
#define CFG_16BIT
#define CFG_DIS_LINK
#define CFG_STATIC
#define CFG_IRQ_SEL_1
#define CFG_IRQ_SEL_0
#define BASE_ADDR
#define ADDR0
#define GENERAL
#define CONTROL
#define CTL_STORE
#define CTL_RELOAD
#define CTL_EE_SELECT
#define CTL_TE_ENABLE
#define CTL_CR_ENABLE
#define CTL_LE_ENABLE
#define CTL_AUTO_RELEASE
#define CTL_POWERDOWN

/* Bank 2 registers. */
#define MMU_CMD
#define MC_ALLOC
#define MC_RESET
#define MC_RELEASE
#define MC_FREEPKT
#define MC_ENQUEUE
#define PNR_ARR
#define FIFO_PORTS
#define FP_RXEMPTY
#define POINTER
#define PTR_AUTO_INC
#define PTR_READ
#define PTR_AUTOINC
#define PTR_RCV
#define DATA_1
#define INTERRUPT
#define IM_RCV_INT
#define IM_TX_INT
#define IM_TX_EMPTY_INT
#define IM_ALLOC_INT
#define IM_RX_OVRN_INT
#define IM_EPH_INT

#define RCR
enum RxCfg {};
#define RCR_SOFTRESET
#define RCR_STRIP_CRC
#define RCR_ENABLE
#define RCR_ALMUL
#define RCR_PROMISC

/* the normal settings for the RCR register : */
#define RCR_NORMAL
#define RCR_CLEAR
#define COUNTER

/* BANK 3 -- not the same values as in smc9194! */
#define MULTICAST0
#define MULTICAST2
#define MULTICAST4
#define MULTICAST6
#define MGMT
#define REVISION

/* Transmit status bits. */
#define TS_SUCCESS
#define TS_16COL
#define TS_LATCOL
#define TS_LOSTCAR

/* Receive status bits. */
#define RS_ALGNERR
#define RS_BADCRC
#define RS_ODDFRAME
#define RS_TOOLONG
#define RS_TOOSHORT
#define RS_MULTICAST
#define RS_ERRORS

#define set_bits(v, p)
#define mask_bits(v, p)

/*====================================================================*/

static void smc91c92_detach(struct pcmcia_device *p_dev);
static int smc91c92_config(struct pcmcia_device *link);
static void smc91c92_release(struct pcmcia_device *link);

static int smc_open(struct net_device *dev);
static int smc_close(struct net_device *dev);
static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue);
static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
					struct net_device *dev);
static irqreturn_t smc_interrupt(int irq, void *dev_id);
static void smc_rx(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static int s9k_config(struct net_device *dev, struct ifmap *map);
static void smc_set_xcvr(struct net_device *dev, int if_port);
static void smc_reset(struct net_device *dev);
static void media_check(struct timer_list *t);
static void mdio_sync(unsigned int addr);
static int mdio_read(struct net_device *dev, int phy_id, int loc);
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
static int smc_link_ok(struct net_device *dev);
static const struct ethtool_ops ethtool_ops;

static const struct net_device_ops smc_netdev_ops =;

static int smc91c92_probe(struct pcmcia_device *link)
{} /* smc91c92_attach */

static void smc91c92_detach(struct pcmcia_device *link)
{} /* smc91c92_detach */

/*====================================================================*/

static int cvt_ascii_address(struct net_device *dev, char *s)
{}

/*====================================================================

    Configuration stuff for Megahertz cards

    mhz_3288_power() is used to power up a 3288's ethernet chip.
    mhz_mfc_config() handles socket setup for multifunction (1144
    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
    address.

======================================================================*/

static int mhz_3288_power(struct pcmcia_device *link)
{}

static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data)
{}

static int mhz_mfc_config(struct pcmcia_device *link)
{}

static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
			      tuple_t *tuple,
			      void *priv)
{
	struct net_device *dev = priv;
	cisparse_t parse;
	u8 *buf;

	if (pcmcia_parse_tuple(tuple, &parse))
		return -EINVAL;

	buf = parse.version_1.str + parse.version_1.ofs[3];

	if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
		return 0;

	return -EINVAL;
};

static int mhz_setup(struct pcmcia_device *link)
{
    struct net_device *dev = link->priv;
    size_t len;
    u8 *buf;
    int rc;

    /* Read the station address from the CIS.  It is stored as the last
       (fourth) string in the Version 1 Version/ID tuple. */
    if ((link->prod_id[3]) &&
	(cvt_ascii_address(dev, link->prod_id[3]) == 0))
	    return 0;

    /* Workarounds for broken cards start here. */
    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
	    return 0;

    /* Another possibility: for the EM3288, in a special tuple */
    rc = -1;
    len = pcmcia_get_tuple(link, 0x81, &buf);
    if (buf && len >= 13) {
	    buf[12] = '\0';
	    if (cvt_ascii_address(dev, buf) == 0)
		    rc = 0;
    }
    kfree(buf);

    return rc;
};

/*======================================================================

    Configuration stuff for the Motorola Mariner

    mot_config() writes directly to the Mariner configuration
    registers because the CIS is just bogus.

======================================================================*/

static void mot_config(struct pcmcia_device *link)
{}

static int mot_setup(struct pcmcia_device *link)
{}

/*====================================================================*/

static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{}

static int smc_config(struct pcmcia_device *link)
{}


static int smc_setup(struct pcmcia_device *link)
{}

/*====================================================================*/

static int osi_config(struct pcmcia_device *link)
{}

static int osi_load_firmware(struct pcmcia_device *link)
{}

static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
			  tuple_t *tuple,
			  void *priv)
{
	struct net_device *dev = priv;

	if (tuple->TupleDataLen < 8)
		return -EINVAL;
	if (tuple->TupleData[0] != 0x04)
		return -EINVAL;

	eth_hw_addr_set(dev, &tuple->TupleData[2]);
	return 0;
};


static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
{}

static int smc91c92_suspend(struct pcmcia_device *link)
{}

static int smc91c92_resume(struct pcmcia_device *link)
{}


/*======================================================================

    This verifies that the chip is some SMC91cXX variant, and returns
    the revision code if successful.  Otherwise, it returns -ENODEV.

======================================================================*/

static int check_sig(struct pcmcia_device *link)
{}

static int smc91c92_config(struct pcmcia_device *link)
{} /* smc91c92_config */

static void smc91c92_release(struct pcmcia_device *link)
{}

/*======================================================================

    MII interface support for SMC91cXX based cards
======================================================================*/

#define MDIO_SHIFT_CLK
#define MDIO_DATA_OUT
#define MDIO_DIR_WRITE
#define MDIO_DATA_WRITE0
#define MDIO_DATA_WRITE1
#define MDIO_DATA_READ

static void mdio_sync(unsigned int addr)
{}

static int mdio_read(struct net_device *dev, int phy_id, int loc)
{}

static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
{}

/*======================================================================

    The driver core code, most of which should be common with a
    non-PCMCIA implementation.

======================================================================*/

#ifdef PCMCIA_DEBUG
static void smc_dump(struct net_device *dev)
{
    unsigned int ioaddr = dev->base_addr;
    u_short i, w, save;
    save = inw(ioaddr + BANK_SELECT);
    for (w = 0; w < 4; w++) {
	SMC_SELECT_BANK(w);
	netdev_dbg(dev, "bank %d: ", w);
	for (i = 0; i < 14; i += 2)
	    pr_cont(" %04x", inw(ioaddr + i));
	pr_cont("\n");
    }
    outw(save, ioaddr + BANK_SELECT);
}
#endif

static int smc_open(struct net_device *dev)
{} /* smc_open */

/*====================================================================*/

static int smc_close(struct net_device *dev)
{} /* smc_close */

/*======================================================================

   Transfer a packet to the hardware and trigger the packet send.
   This may be called at either from either the Tx queue code
   or the interrupt handler.

======================================================================*/

static void smc_hardware_send_packet(struct net_device * dev)
{}

/*====================================================================*/

static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue)
{}

static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
					struct net_device *dev)
{}

/*======================================================================

    Handle a Tx anomalous event.  Entered while in Window 2.

======================================================================*/

static void smc_tx_err(struct net_device * dev)
{}

/*====================================================================*/

static void smc_eph_irq(struct net_device *dev)
{}

/*====================================================================*/

static irqreturn_t smc_interrupt(int irq, void *dev_id)
{}

/*====================================================================*/

static void smc_rx(struct net_device *dev)
{}

/*======================================================================

    Set the receive mode.

    This routine is used by both the protocol level to notify us of
    promiscuous/multicast mode changes, and by the open/reset code to
    initialize the Rx registers.  We always set the multicast list and
    leave the receiver running.

======================================================================*/

static void set_rx_mode(struct net_device *dev)
{}

/*======================================================================

    Senses when a card's config changes. Here, it's coax or TP.

======================================================================*/

static int s9k_config(struct net_device *dev, struct ifmap *map)
{}

/*======================================================================

    Reset the chip, reloading every register that might be corrupted.

======================================================================*/

/*
  Set transceiver type, perhaps to something other than what the user
  specified in dev->if_port.
*/
static void smc_set_xcvr(struct net_device *dev, int if_port)
{}

static void smc_reset(struct net_device *dev)
{}

/*======================================================================

    Media selection timer routine

======================================================================*/

static void media_check(struct timer_list *t)
{}

static int smc_link_ok(struct net_device *dev)
{}

static void smc_netdev_get_ecmd(struct net_device *dev,
				struct ethtool_link_ksettings *ecmd)
{}

static int smc_netdev_set_ecmd(struct net_device *dev,
			       const struct ethtool_link_ksettings *ecmd)
{}

static int check_if_running(struct net_device *dev)
{}

static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{}

static int smc_get_link_ksettings(struct net_device *dev,
				  struct ethtool_link_ksettings *ecmd)
{}

static int smc_set_link_ksettings(struct net_device *dev,
				  const struct ethtool_link_ksettings *ecmd)
{}

static u32 smc_get_link(struct net_device *dev)
{}

static int smc_nway_reset(struct net_device *dev)
{}

static const struct ethtool_ops ethtool_ops =;

static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{}

static const struct pcmcia_device_id smc91c92_ids[] =;
MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);

static struct pcmcia_driver smc91c92_cs_driver =;
module_pcmcia_driver();