smc91c92_cs.c 61.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*======================================================================

    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 -- dahinds@users.sourceforge.net

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

    This driver contains code written by Donald Becker
    (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
    David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
    (erik@vt.edu).  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 (kstephen@holli.com) 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.

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

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.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>
44
#include <linux/jiffies.h>
45
#include <linux/firmware.h>
L
Linus Torvalds 已提交
46 47 48 49 50 51 52

#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
53
#include <pcmcia/ss.h>
L
Linus Torvalds 已提交
54 55 56 57 58 59 60

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

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

61
static const char *if_names[] = { "auto", "10baseT", "10base2"};
L
Linus Torvalds 已提交
62

63 64 65
/* Firmware name */
#define FIRMWARE_NAME		"ositech/Xilinx7OD.bin"

L
Linus Torvalds 已提交
66 67 68 69
/* Module parameters */

MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
MODULE_LICENSE("GPL");
70
MODULE_FIRMWARE(FIRMWARE_NAME);
L
Linus Torvalds 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83

#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)

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


#define DRV_NAME	"smc91c92_cs"
84
#define DRV_VERSION	"1.123"
L
Linus Torvalds 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

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

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

/* Time in jiffies before concluding Tx hung */
#define TX_TIMEOUT		((400*HZ)/1000)

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

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

struct smc_private {
101
	struct pcmcia_device	*p_dev;
L
Linus Torvalds 已提交
102 103 104
    spinlock_t			lock;
    u_short			manfid;
    u_short			cardid;
105

L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    dev_node_t			node;
    struct sk_buff		*saved_skb;
    int				packets_waiting;
    void			__iomem *base;
    u_short			cfg;
    struct timer_list		media;
    int				watchdog, tx_err;
    u_short			media_status;
    u_short			fast_poll;
    u_short			link_status;
    struct mii_if_info		mii_if;
    int				duplex;
    int				rx_ovrn;
};

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

/* Special function registers for Motorola Mariner */
#define MOT_LAN			0x0000
#define MOT_UART		0x0020
#define MOT_EEPROM		0x20

#define MOT_NORMAL \
(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)

/* Special function registers for Ositech cards */
#define OSITECH_AUI_CTL		0x0c
#define OSITECH_PWRDOWN		0x0d
#define OSITECH_RESET		0x0e
#define OSITECH_ISR		0x0f
#define OSITECH_AUI_PWR		0x0c
#define OSITECH_RESET_ISR	0x0e

#define OSI_AUI_PWR		0x40
#define OSI_LAN_PWRDOWN		0x02
#define OSI_MODEM_PWRDOWN	0x01
#define OSI_LAN_RESET		0x02
#define OSI_MODEM_RESET		0x01

/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
#define	BANK_SELECT		14		/* Window select register. */
#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }

/* Bank 0 registers. */
#define	TCR 		0	/* transmit control register */
#define	 TCR_CLEAR	0	/* do NOTHING */
#define  TCR_ENABLE	0x0001	/* if this is 1, we can transmit */
#define	 TCR_PAD_EN	0x0080	/* pads short packets to 64 bytes */
#define  TCR_MONCSN	0x0400  /* Monitor Carrier. */
#define  TCR_FDUPLX	0x0800  /* Full duplex mode. */
#define	 TCR_NORMAL TCR_ENABLE | TCR_PAD_EN

#define EPH		2	/* Ethernet Protocol Handler report. */
#define  EPH_TX_SUC	0x0001
#define  EPH_SNGLCOL	0x0002
#define  EPH_MULCOL	0x0004
#define  EPH_LTX_MULT	0x0008
#define  EPH_16COL	0x0010
#define  EPH_SQET	0x0020
#define  EPH_LTX_BRD	0x0040
#define  EPH_TX_DEFR	0x0080
#define  EPH_LAT_COL	0x0200
#define  EPH_LOST_CAR	0x0400
#define  EPH_EXC_DEF	0x0800
#define  EPH_CTR_ROL	0x1000
#define  EPH_RX_OVRN	0x2000
#define  EPH_LINK_OK	0x4000
#define  EPH_TX_UNRN	0x8000
#define MEMINFO		8	/* Memory Information Register */
#define MEMCFG		10	/* Memory Configuration Register */

/* Bank 1 registers. */
#define CONFIG			0
#define  CFG_MII_SELECT		0x8000	/* 91C100 only */
#define  CFG_NO_WAIT		0x1000
#define  CFG_FULL_STEP		0x0400
#define  CFG_SET_SQLCH		0x0200
#define  CFG_AUI_SELECT	 	0x0100
#define  CFG_16BIT		0x0080
#define  CFG_DIS_LINK		0x0040
#define  CFG_STATIC		0x0030
#define  CFG_IRQ_SEL_1		0x0004
#define  CFG_IRQ_SEL_0		0x0002
#define BASE_ADDR		2
#define	ADDR0			4
#define	GENERAL			10
#define	CONTROL			12
#define  CTL_STORE		0x0001
#define  CTL_RELOAD		0x0002
#define  CTL_EE_SELECT		0x0004
#define  CTL_TE_ENABLE		0x0020
#define  CTL_CR_ENABLE		0x0040
#define  CTL_LE_ENABLE		0x0080
#define  CTL_AUTO_RELEASE	0x0800
#define	 CTL_POWERDOWN		0x2000

/* Bank 2 registers. */
#define MMU_CMD		0
#define	 MC_ALLOC	0x20  	/* or with number of 256 byte packets */
#define	 MC_RESET	0x40
#define  MC_RELEASE  	0x80  	/* remove and release the current rx packet */
#define  MC_FREEPKT  	0xA0  	/* Release packet in PNR register */
#define  MC_ENQUEUE	0xC0 	/* Enqueue the packet for transmit */
#define	PNR_ARR		2
#define FIFO_PORTS	4
#define  FP_RXEMPTY	0x8000
#define	POINTER		6
#define  PTR_AUTO_INC	0x0040
#define  PTR_READ	0x2000
#define	 PTR_AUTOINC 	0x4000
#define	 PTR_RCV	0x8000
#define	DATA_1		8
#define	INTERRUPT	12
#define  IM_RCV_INT		0x1
#define	 IM_TX_INT		0x2
#define	 IM_TX_EMPTY_INT	0x4
#define	 IM_ALLOC_INT		0x8
#define	 IM_RX_OVRN_INT		0x10
#define	 IM_EPH_INT		0x20

#define	RCR		4
enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
	     RxEnable = 0x0100, RxStripCRC = 0x0200};
#define  RCR_SOFTRESET	0x8000 	/* resets the chip */
#define	 RCR_STRIP_CRC	0x200	/* strips CRC */
#define  RCR_ENABLE	0x100	/* IFF this is set, we can receive packets */
#define  RCR_ALMUL	0x4 	/* receive all multicast packets */
#define	 RCR_PROMISC	0x2	/* enable promiscuous mode */

/* the normal settings for the RCR register : */
#define	 RCR_NORMAL	(RCR_STRIP_CRC | RCR_ENABLE)
#define  RCR_CLEAR	0x0		/* set it to a base state */
#define	COUNTER		6

/* BANK 3 -- not the same values as in smc9194! */
#define	MULTICAST0	0
#define	MULTICAST2	2
#define	MULTICAST4	4
#define	MULTICAST6	6
#define MGMT    	8
#define REVISION	0x0a

/* Transmit status bits. */
#define TS_SUCCESS 0x0001
#define TS_16COL   0x0010
#define TS_LATCOL  0x0200
#define TS_LOSTCAR 0x0400

/* Receive status bits. */
#define RS_ALGNERR	0x8000
#define RS_BADCRC	0x2000
#define RS_ODDFRAME	0x1000
#define RS_TOOLONG	0x0800
#define RS_TOOSHORT	0x0400
#define RS_MULTICAST	0x0001
#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)

#define set_bits(v, p) outw(inw(p)|(v), (p))
#define mask_bits(v, p) outw(inw(p)&(v), (p))

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

269
static void smc91c92_detach(struct pcmcia_device *p_dev);
270
static int smc91c92_config(struct pcmcia_device *link);
271
static void smc91c92_release(struct pcmcia_device *link);
L
Linus Torvalds 已提交
272 273 274 275 276

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);
277 278
static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
					struct net_device *dev);
279
static irqreturn_t smc_interrupt(int irq, void *dev_id);
L
Linus Torvalds 已提交
280 281 282 283 284 285
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(u_long arg);
286
static void mdio_sync(unsigned int addr);
L
Linus Torvalds 已提交
287 288 289
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);
290
static const struct ethtool_ops ethtool_ops;
L
Linus Torvalds 已提交
291

292 293 294 295 296 297 298 299 300 301 302 303 304
static const struct net_device_ops smc_netdev_ops = {
	.ndo_open		= smc_open,
	.ndo_stop		= smc_close,
	.ndo_start_xmit		= smc_start_xmit,
	.ndo_tx_timeout 	= smc_tx_timeout,
	.ndo_set_config 	= s9k_config,
	.ndo_set_multicast_list = set_rx_mode,
	.ndo_do_ioctl		= &smc_ioctl,
	.ndo_change_mtu		= eth_change_mtu,
	.ndo_set_mac_address 	= eth_mac_addr,
	.ndo_validate_addr	= eth_validate_addr,
};

L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312
/*======================================================================

  smc91c92_attach() creates an "instance" of the driver, allocating
  local data structures for one device.  The device is registered
  with Card Services.

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

313
static int smc91c92_probe(struct pcmcia_device *link)
L
Linus Torvalds 已提交
314 315 316 317
{
    struct smc_private *smc;
    struct net_device *dev;

318
    dev_dbg(&link->dev, "smc91c92_attach()\n");
L
Linus Torvalds 已提交
319 320 321 322

    /* Create new ethernet device */
    dev = alloc_etherdev(sizeof(struct smc_private));
    if (!dev)
323
	return -ENOMEM;
L
Linus Torvalds 已提交
324
    smc = netdev_priv(dev);
325
    smc->p_dev = link;
L
Linus Torvalds 已提交
326 327 328 329 330 331
    link->priv = dev;

    spin_lock_init(&smc->lock);
    link->io.NumPorts1 = 16;
    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
    link->io.IOAddrLines = 4;
332
    link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
L
Linus Torvalds 已提交
333 334 335 336 337 338 339
    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
    link->irq.Handler = &smc_interrupt;
    link->irq.Instance = dev;
    link->conf.Attributes = CONF_ENABLE_IRQ;
    link->conf.IntType = INT_MEMORY_AND_IO;

    /* The SMC91c92-specific entries in the device structure. */
340
    dev->netdev_ops = &smc_netdev_ops;
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349
    SET_ETHTOOL_OPS(dev, &ethtool_ops);
    dev->watchdog_timeo = TX_TIMEOUT;

    smc->mii_if.dev = dev;
    smc->mii_if.mdio_read = mdio_read;
    smc->mii_if.mdio_write = mdio_write;
    smc->mii_if.phy_id_mask = 0x1f;
    smc->mii_if.reg_num_mask = 0x1f;

350
    return smc91c92_config(link);
L
Linus Torvalds 已提交
351 352 353 354 355 356 357 358 359 360 361
} /* smc91c92_attach */

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

    This deletes a driver "instance".  The device is de-registered
    with Card Services.  If it has been released, all local data
    structures are freed.  Otherwise, the structures will be freed
    when the device is released.

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

362
static void smc91c92_detach(struct pcmcia_device *link)
L
Linus Torvalds 已提交
363 364 365
{
    struct net_device *dev = link->priv;

366
    dev_dbg(&link->dev, "smc91c92_detach\n");
L
Linus Torvalds 已提交
367

368
    if (link->dev_node)
L
Linus Torvalds 已提交
369 370
	unregister_netdev(dev);

371
    smc91c92_release(link);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

    free_netdev(dev);
} /* smc91c92_detach */

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

static int cvt_ascii_address(struct net_device *dev, char *s)
{
    int i, j, da, c;

    if (strlen(s) != 12)
	return -1;
    for (i = 0; i < 6; i++) {
	da = 0;
	for (j = 0; j < 2; j++) {
	    c = *s++;
	    da <<= 4;
	    da += ((c >= '0') && (c <= '9')) ?
		(c - '0') : ((c & 0x0f) + 9);
	}
	dev->dev_addr[i] = da;
    }
    return 0;
}

397
/*====================================================================
L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405 406 407

    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.

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

408
static int mhz_3288_power(struct pcmcia_device *link)
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
{
    struct net_device *dev = link->priv;
    struct smc_private *smc = netdev_priv(dev);
    u_char tmp;

    /* Read the ISR twice... */
    readb(smc->base+MEGAHERTZ_ISR);
    udelay(5);
    readb(smc->base+MEGAHERTZ_ISR);

    /* Pause 200ms... */
    mdelay(200);

    /* Now read and write the COR... */
    tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
    udelay(5);
    writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);

    return 0;
}

430 431
static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
				cistpl_cftable_entry_t *cf,
432
				cistpl_cftable_entry_t *dflt,
433
				unsigned int vcc,
434 435 436 437 438 439 440 441 442 443 444 445 446 447
				void *priv_data)
{
	int k;
	p_dev->io.BasePort2 = cf->io.win[0].base;
	for (k = 0; k < 0x400; k += 0x10) {
		if (k & 0x80)
			continue;
		p_dev->io.BasePort1 = k ^ 0x300;
		if (!pcmcia_request_io(p_dev, &p_dev->io))
			return 0;
	}
	return -ENODEV;
}

448
static int mhz_mfc_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
449 450 451 452 453
{
    struct net_device *dev = link->priv;
    struct smc_private *smc = netdev_priv(dev);
    win_req_t req;
    memreq_t mem;
454
    int i;
L
Linus Torvalds 已提交
455 456 457 458 459 460 461 462 463 464 465

    link->conf.Attributes |= CONF_ENABLE_SPKR;
    link->conf.Status = CCSR_AUDIO_ENA;
    link->irq.Attributes =
	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
    link->io.IOAddrLines = 16;
    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
    link->io.NumPorts2 = 8;

    /* The Megahertz combo cards have modem-like CIS entries, so
       we have to explicitly try a bunch of port combinations. */
466
    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
467 468
	    return -ENODEV;

L
Linus Torvalds 已提交
469 470 471 472 473 474
    dev->base_addr = link->io.BasePort1;

    /* Allocate a memory window, for accessing the ISR */
    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
    req.Base = req.Size = 0;
    req.AccessSpeed = 0;
475
    i = pcmcia_request_window(link, &req, &link->win);
D
Dominik Brodowski 已提交
476
    if (i != 0)
477 478
	    return -ENODEV;

L
Linus Torvalds 已提交
479 480 481 482
    smc->base = ioremap(req.Base, req.Size);
    mem.CardOffset = mem.Page = 0;
    if (smc->manfid == MANFID_MOTOROLA)
	mem.CardOffset = link->conf.ConfigBase;
483
    i = pcmcia_map_mem_page(link, link->win, &mem);
L
Linus Torvalds 已提交
484

D
Dominik Brodowski 已提交
485
    if ((i == 0)
L
Linus Torvalds 已提交
486 487 488 489
	&& (smc->manfid == MANFID_MEGAHERTZ)
	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
	mhz_3288_power(link);

490
    return 0;
L
Linus Torvalds 已提交
491 492
}

493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
			      tuple_t *tuple,
			      void *priv)
{
	struct net_device *dev = priv;
	cisparse_t parse;

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

	if ((parse.version_1.ns > 3) &&
	    (cvt_ascii_address(dev,
			       (parse.version_1.str + parse.version_1.ofs[3]))))
		return 0;

	return -EINVAL;
};

511
static int mhz_setup(struct pcmcia_device *link)
L
Linus Torvalds 已提交
512 513
{
    struct net_device *dev = link->priv;
514 515
    size_t len;
    u8 *buf;
516 517
    int rc;

518 519 520 521 522 523 524
    /* 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. */
525
    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
526 527
    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
	    return 0;
L
Linus Torvalds 已提交
528 529

    /* Another possibility: for the EM3288, in a special tuple */
530
    rc = -1;
531 532 533 534 535 536 537 538 539 540
    len = pcmcia_get_tuple(link, 0x81, &buf);
    if (buf && len >= 13) {
	    buf[12] = '\0';
	    if (cvt_ascii_address(dev, buf))
		    rc = 0;
    }
    kfree(buf);

    return rc;
};
L
Linus Torvalds 已提交
541 542 543 544 545 546 547 548 549 550

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

    Configuration stuff for the Motorola Mariner

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

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

551
static void mot_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
552 553 554
{
    struct net_device *dev = link->priv;
    struct smc_private *smc = netdev_priv(dev);
555 556
    unsigned int ioaddr = dev->base_addr;
    unsigned int iouart = link->io.BasePort2;
L
Linus Torvalds 已提交
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571

    /* Set UART base address and force map with COR bit 1 */
    writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
    writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
    writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);

    /* Set SMC base address and force map with COR bit 1 */
    writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
    writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
    writeb(MOT_NORMAL,           smc->base + MOT_LAN + CISREG_COR);

    /* Wait for things to settle down */
    mdelay(100);
}

572
static int mot_setup(struct pcmcia_device *link)
L
Linus Torvalds 已提交
573 574
{
    struct net_device *dev = link->priv;
575
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
    int i, wait, loop;
    u_int addr;

    /* Read Ethernet address from Serial EEPROM */

    for (i = 0; i < 3; i++) {
	SMC_SELECT_BANK(2);
	outw(MOT_EEPROM + i, ioaddr + POINTER);
	SMC_SELECT_BANK(1);
	outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);

	for (loop = wait = 0; loop < 200; loop++) {
	    udelay(10);
	    wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
	    if (wait == 0) break;
	}
	
	if (wait)
	    return -1;
	
	addr = inw(ioaddr + GENERAL);
	dev->dev_addr[2*i]   = addr & 0xff;
	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
    }

    return 0;
}

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

606 607
static int smc_configcheck(struct pcmcia_device *p_dev,
			   cistpl_cftable_entry_t *cf,
608
			   cistpl_cftable_entry_t *dflt,
609
			   unsigned int vcc,
610 611 612 613 614 615 616
			   void *priv_data)
{
	p_dev->io.BasePort1 = cf->io.win[0].base;
	p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
	return pcmcia_request_io(p_dev, &p_dev->io);
}

617
static int smc_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
618 619 620 621 622
{
    struct net_device *dev = link->priv;
    int i;

    link->io.NumPorts1 = 16;
623 624 625
    i = pcmcia_loop_config(link, smc_configcheck, NULL);
    if (!i)
	    dev->base_addr = link->io.BasePort1;
626

L
Linus Torvalds 已提交
627 628 629
    return i;
}

630

631
static int smc_setup(struct pcmcia_device *link)
L
Linus Torvalds 已提交
632 633 634 635
{
    struct net_device *dev = link->priv;

    /* Check for a LAN function extension tuple */
636 637 638
    if (!pcmcia_get_mac_from_cis(link, dev))
	    return 0;

L
Linus Torvalds 已提交
639
    /* Try the third string in the Version 1 Version/ID tuple. */
640
    if (link->prod_id[2]) {
641 642
	    if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
		    return 0;
643
    }
644
    return -1;
L
Linus Torvalds 已提交
645 646 647 648
}

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

649
static int osi_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
650 651
{
    struct net_device *dev = link->priv;
652
    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
L
Linus Torvalds 已提交
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
    int i, j;

    link->conf.Attributes |= CONF_ENABLE_SPKR;
    link->conf.Status = CCSR_AUDIO_ENA;
    link->irq.Attributes =
	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
    link->io.NumPorts1 = 64;
    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
    link->io.NumPorts2 = 8;
    link->io.IOAddrLines = 16;

    /* Enable Hard Decode, LAN, Modem */
    link->conf.ConfigIndex = 0x23;

    for (i = j = 0; j < 4; j++) {
	link->io.BasePort2 = com[j];
669
	i = pcmcia_request_io(link, &link->io);
D
Dominik Brodowski 已提交
670 671
	if (i == 0)
		break;
L
Linus Torvalds 已提交
672
    }
D
Dominik Brodowski 已提交
673
    if (i != 0) {
L
Linus Torvalds 已提交
674 675 676
	/* Fallback: turn off hard decode */
	link->conf.ConfigIndex = 0x03;
	link->io.NumPorts2 = 0;
677
	i = pcmcia_request_io(link, &link->io);
L
Linus Torvalds 已提交
678 679 680 681 682
    }
    dev->base_addr = link->io.BasePort1 + 0x10;
    return i;
}

683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
static int osi_load_firmware(struct pcmcia_device *link)
{
	const struct firmware *fw;
	int i, err;

	err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
	if (err) {
		pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
		return err;
	}

	/* Download the Seven of Diamonds firmware */
	for (i = 0; i < fw->size; i++) {
	    outb(fw->data[i], link->io.BasePort1 + 2);
	    udelay(50);
	}
	release_firmware(fw);
	return err;
}

703 704 705
static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
			  tuple_t *tuple,
			  void *priv)
L
Linus Torvalds 已提交
706
{
707 708
	struct net_device *dev = priv;
	int i;
L
Linus Torvalds 已提交
709

710 711 712 713 714 715 716 717
	if (tuple->TupleDataLen < 8)
		return -EINVAL;
	if (tuple->TupleData[0] != 0x04)
		return -EINVAL;
	for (i = 0; i < 6; i++)
		dev->dev_addr[i] = tuple->TupleData[i+2];
	return 0;
};
718 719


720 721 722 723
static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
{
    struct net_device *dev = link->priv;
    int rc;
L
Linus Torvalds 已提交
724 725

    /* Read the station address from tuple 0x90, subtuple 0x04 */
726 727
    if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
	    return -1;
L
Linus Torvalds 已提交
728 729 730 731 732

    if (((manfid == MANFID_OSITECH) &&
	 (cardid == PRODID_OSITECH_SEVEN)) ||
	((manfid == MANFID_PSION) &&
	 (cardid == PRODID_PSION_NET100))) {
733 734
	rc = osi_load_firmware(link);
	if (rc)
735
		return rc;
L
Linus Torvalds 已提交
736 737 738 739 740
    } else if (manfid == MANFID_OSITECH) {
	/* Make sure both functions are powered up */
	set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
	/* Now, turn on the interrupt for both card functions */
	set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
741
	dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
L
Linus Torvalds 已提交
742 743 744
	      inw(link->io.BasePort1 + OSITECH_AUI_PWR),
	      inw(link->io.BasePort1 + OSITECH_RESET_ISR));
    }
745
    return 0;
L
Linus Torvalds 已提交
746 747
}

748
static int smc91c92_suspend(struct pcmcia_device *link)
749 750 751
{
	struct net_device *dev = link->priv;

752
	if (link->open)
753
		netif_device_detach(dev);
754 755 756 757

	return 0;
}

758
static int smc91c92_resume(struct pcmcia_device *link)
759 760 761 762 763
{
	struct net_device *dev = link->priv;
	struct smc_private *smc = netdev_priv(dev);
	int i;

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
	if ((smc->manfid == MANFID_MEGAHERTZ) &&
	    (smc->cardid == PRODID_MEGAHERTZ_EM3288))
		mhz_3288_power(link);
	if (smc->manfid == MANFID_MOTOROLA)
		mot_config(link);
	if ((smc->manfid == MANFID_OSITECH) &&
	    (smc->cardid != PRODID_OSITECH_SEVEN)) {
		/* Power up the card and enable interrupts */
		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
	}
	if (((smc->manfid == MANFID_OSITECH) &&
	     (smc->cardid == PRODID_OSITECH_SEVEN)) ||
	    ((smc->manfid == MANFID_PSION) &&
	     (smc->cardid == PRODID_PSION_NET100))) {
779 780 781 782
		i = osi_load_firmware(link);
		if (i) {
			pr_err("smc91c92_cs: Failed to load firmware\n");
			return i;
783 784
		}
	}
785 786 787 788
	if (link->open) {
		smc_reset(dev);
		netif_device_attach(dev);
	}
789 790 791 792 793

	return 0;
}


L
Linus Torvalds 已提交
794 795 796 797 798 799 800
/*======================================================================

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

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

801
static int check_sig(struct pcmcia_device *link)
L
Linus Torvalds 已提交
802 803
{
    struct net_device *dev = link->priv;
804
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
    int width;
    u_short s;

    SMC_SELECT_BANK(1);
    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
	/* Try powering up the chip */
	outw(0, ioaddr + CONTROL);
	mdelay(55);
    }

    /* Try setting bus width */
    width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO);
    s = inb(ioaddr + CONFIG);
    if (width)
	s |= CFG_16BIT;
    else
	s &= ~CFG_16BIT;
    outb(s, ioaddr + CONFIG);

    /* Check Base Address Register to make sure bus width is OK */
    s = inw(ioaddr + BASE_ADDR);
    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
	((s >> 8) != (s & 0xff))) {
	SMC_SELECT_BANK(3);
	s = inw(ioaddr + REVISION);
	return (s & 0xff);
    }

    if (width) {
834 835 836 837 838
	    modconf_t mod = {
		    .Attributes = CONF_IO_CHANGE_WIDTH,
	    };
	    printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");

839 840 841
	    smc91c92_suspend(link);
	    pcmcia_modify_configuration(link, &mod);
	    smc91c92_resume(link);
842
	    return check_sig(link);
L
Linus Torvalds 已提交
843 844 845 846 847 848 849 850 851 852 853 854
    }
    return -ENODEV;
}

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

    smc91c92_config() is scheduled to run after a CARD_INSERTION event
    is received, to configure the PCMCIA socket, and to make the
    ethernet device available to the system.

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

855
static int smc91c92_config(struct pcmcia_device *link)
L
Linus Torvalds 已提交
856 857 858 859 860
{
    struct net_device *dev = link->priv;
    struct smc_private *smc = netdev_priv(dev);
    char *name;
    int i, j, rev;
861
    unsigned int ioaddr;
L
Linus Torvalds 已提交
862 863
    u_long mir;

864
    dev_dbg(&link->dev, "smc91c92_config\n");
L
Linus Torvalds 已提交
865

866 867
    smc->manfid = link->manf_id;
    smc->cardid = link->card_id;
L
Linus Torvalds 已提交
868 869 870 871 872 873 874 875 876 877 878 879

    if ((smc->manfid == MANFID_OSITECH) &&
	(smc->cardid != PRODID_OSITECH_SEVEN)) {
	i = osi_config(link);
    } else if ((smc->manfid == MANFID_MOTOROLA) ||
	       ((smc->manfid == MANFID_MEGAHERTZ) &&
		((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
		 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
	i = mhz_mfc_config(link);
    } else {
	i = smc_config(link);
    }
880 881
    if (i)
	    goto config_failed;
L
Linus Torvalds 已提交
882

883
    i = pcmcia_request_irq(link, &link->irq);
884 885
    if (i)
	    goto config_failed;
886
    i = pcmcia_request_configuration(link, &link->conf);
887 888
    if (i)
	    goto config_failed;
L
Linus Torvalds 已提交
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965

    if (smc->manfid == MANFID_MOTOROLA)
	mot_config(link);

    dev->irq = link->irq.AssignedIRQ;

    if ((if_port >= 0) && (if_port <= 2))
	dev->if_port = if_port;
    else
	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");

    switch (smc->manfid) {
    case MANFID_OSITECH:
    case MANFID_PSION:
	i = osi_setup(link, smc->manfid, smc->cardid); break;
    case MANFID_SMC:
    case MANFID_NEW_MEDIA:
	i = smc_setup(link); break;
    case 0x128: /* For broken Megahertz cards */
    case MANFID_MEGAHERTZ:
	i = mhz_setup(link); break;
    case MANFID_MOTOROLA:
    default: /* get the hw address from EEPROM */
	i = mot_setup(link); break;
    }

    if (i != 0) {
	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
	goto config_undo;
    }

    smc->duplex = 0;
    smc->rx_ovrn = 0;

    rev = check_sig(link);
    name = "???";
    if (rev > 0)
	switch (rev >> 4) {
	case 3: name = "92"; break;
	case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
	case 5: name = "95"; break;
	case 7: name = "100"; break;
	case 8: name = "100-FD"; break;
	case 9: name = "110"; break;
	}

    ioaddr = dev->base_addr;
    if (rev > 0) {
	u_long mcr;
	SMC_SELECT_BANK(0);
	mir = inw(ioaddr + MEMINFO) & 0xff;
	if (mir == 0xff) mir++;
	/* Get scale factor for memory size */
	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
	mir *= 128 * (1<<((mcr >> 9) & 7));
	SMC_SELECT_BANK(1);
	smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
	smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
	if (smc->manfid == MANFID_OSITECH)
	    smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
	if ((rev >> 4) >= 7)
	    smc->cfg |= CFG_MII_SELECT;
    } else
	mir = 0;

    if (smc->cfg & CFG_MII_SELECT) {
	SMC_SELECT_BANK(3);

	for (i = 0; i < 32; i++) {
	    j = mdio_read(dev, i, 1);
	    if ((j != 0) && (j != 0xffff)) break;
	}
	smc->mii_if.phy_id = (i < 32) ? i : -1;

	SMC_SELECT_BANK(0);
    }

966
    link->dev_node = &smc->node;
967
    SET_NETDEV_DEV(dev, &handle_to_dev(link));
L
Linus Torvalds 已提交
968 969 970

    if (register_netdev(dev) != 0) {
	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
971
	link->dev_node = NULL;
L
Linus Torvalds 已提交
972 973 974 975 976 977
	goto config_undo;
    }

    strcpy(smc->node.dev_name, dev->name);

    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
J
Johannes Berg 已提交
978
	   "hw_addr %pM\n",
979
	   dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
J
Johannes Berg 已提交
980
	   dev->dev_addr);
L
Linus Torvalds 已提交
981 982 983 984 985 986 987 988 989 990 991 992

    if (rev > 0) {
	if (mir & 0x3ff)
	    printk(KERN_INFO "  %lu byte", mir);
	else
	    printk(KERN_INFO "  %lu kb", mir>>10);
	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
	       "MII" : if_names[dev->if_port]);
    }

    if (smc->cfg & CFG_MII_SELECT) {
	if (smc->mii_if.phy_id != -1) {
993
	    dev_dbg(&link->dev, "  MII transceiver at index %d, status %x.\n",
L
Linus Torvalds 已提交
994 995 996 997 998
		  smc->mii_if.phy_id, j);
	} else {
    	    printk(KERN_NOTICE "  No MII transceivers found!\n");
	}
    }
999
    return 0;
L
Linus Torvalds 已提交
1000 1001 1002

config_undo:
    unregister_netdev(dev);
1003
config_failed:
L
Linus Torvalds 已提交
1004
    smc91c92_release(link);
1005
    return -ENODEV;
L
Linus Torvalds 已提交
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
} /* smc91c92_config */

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

    After a card is removed, smc91c92_release() will unregister the net
    device, and release the PCMCIA configuration.  If the device is
    still open, this will be postponed until it is closed.

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

1016
static void smc91c92_release(struct pcmcia_device *link)
L
Linus Torvalds 已提交
1017
{
1018
	dev_dbg(&link->dev, "smc91c92_release\n");
1019 1020 1021 1022 1023
	if (link->win) {
		struct net_device *dev = link->priv;
		struct smc_private *smc = netdev_priv(dev);
		iounmap(smc->base);
	}
1024
	pcmcia_disable_device(link);
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
}

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

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

#define MDIO_SHIFT_CLK		0x04
#define MDIO_DATA_OUT		0x01
#define MDIO_DIR_WRITE		0x08
#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
#define MDIO_DATA_READ		0x02

1039
static void mdio_sync(unsigned int addr)
L
Linus Torvalds 已提交
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
{
    int bits;
    for (bits = 0; bits < 32; bits++) {
	outb(MDIO_DATA_WRITE1, addr);
	outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
    }
}

static int mdio_read(struct net_device *dev, int phy_id, int loc)
{
1050
    unsigned int addr = dev->base_addr + MGMT;
L
Linus Torvalds 已提交
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
    int i, retval = 0;

    mdio_sync(addr);
    for (i = 13; i >= 0; i--) {
	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
	outb(dat, addr);
	outb(dat | MDIO_SHIFT_CLK, addr);
    }
    for (i = 19; i > 0; i--) {
	outb(0, addr);
	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
	outb(MDIO_SHIFT_CLK, addr);
    }
    return (retval>>1) & 0xffff;
}

static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
{
1070
    unsigned int addr = dev->base_addr + MGMT;
L
Linus Torvalds 已提交
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
    int i;

    mdio_sync(addr);
    for (i = 31; i >= 0; i--) {
	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
	outb(dat, addr);
	outb(dat | MDIO_SHIFT_CLK, addr);
    }
    for (i = 1; i >= 0; i--) {
	outb(0, addr);
	outb(MDIO_SHIFT_CLK, addr);
    }
}

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

    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)
{
1096
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
    u_short i, w, save;
    save = inw(ioaddr + BANK_SELECT);
    for (w = 0; w < 4; w++) {
	SMC_SELECT_BANK(w);
	printk(KERN_DEBUG "bank %d: ", w);
	for (i = 0; i < 14; i += 2)
	    printk(" %04x", inw(ioaddr + i));
	printk("\n");
    }
    outw(save, ioaddr + BANK_SELECT);
}
#endif

static int smc_open(struct net_device *dev)
{
    struct smc_private *smc = netdev_priv(dev);
1113
    struct pcmcia_device *link = smc->p_dev;
L
Linus Torvalds 已提交
1114

1115
    dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
L
Linus Torvalds 已提交
1116
	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
1117 1118
#ifdef PCMCIA_DEBUG
    smc_dump(dev);
L
Linus Torvalds 已提交
1119 1120 1121
#endif

    /* Check that the PCMCIA card is still here. */
1122
    if (!pcmcia_dev_present(link))
L
Linus Torvalds 已提交
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
	return -ENODEV;
    /* Physical device present signature. */
    if (check_sig(link) < 0) {
	printk("smc91c92_cs: Yikes!  Bad chip signature!\n");
	return -ENODEV;
    }
    link->open++;

    netif_start_queue(dev);
    smc->saved_skb = NULL;
    smc->packets_waiting = 0;

    smc_reset(dev);
    init_timer(&smc->media);
    smc->media.function = &media_check;
    smc->media.data = (u_long) dev;
    smc->media.expires = jiffies + HZ;
    add_timer(&smc->media);

    return 0;
} /* smc_open */

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

static int smc_close(struct net_device *dev)
{
    struct smc_private *smc = netdev_priv(dev);
1150
    struct pcmcia_device *link = smc->p_dev;
1151
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1152

1153
    dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
L
Linus Torvalds 已提交
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
	  dev->name, inw(ioaddr + BANK_SELECT));

    netif_stop_queue(dev);

    /* Shut off all interrupts, and turn off the Tx and Rx sections.
       Don't bother to check for chip present. */
    SMC_SELECT_BANK(2);	/* Nominally paranoia, but do no assume... */
    outw(0, ioaddr + INTERRUPT);
    SMC_SELECT_BANK(0);
    mask_bits(0xff00, ioaddr + RCR);
    mask_bits(0xff00, ioaddr + TCR);

    /* Put the chip into power-down mode. */
    SMC_SELECT_BANK(1);
    outw(CTL_POWERDOWN, ioaddr + CONTROL );

    link->open--;
    del_timer_sync(&smc->media);

    return 0;
} /* 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)
{
    struct smc_private *smc = netdev_priv(dev);
    struct sk_buff *skb = smc->saved_skb;
1188
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
    u_char packet_no;

    if (!skb) {
	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
	return;
    }

    /* There should be a packet slot waiting. */
    packet_no = inw(ioaddr + PNR_ARR) >> 8;
    if (packet_no & 0x80) {
	/* If not, there is a hardware problem!  Likely an ejected card. */
	printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
	       " failed, status %#2.2x.\n", dev->name, packet_no);
	dev_kfree_skb_irq(skb);
	smc->saved_skb = NULL;
	netif_start_queue(dev);
	return;
    }

1208
    dev->stats.tx_bytes += skb->len;
L
Linus Torvalds 已提交
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
    /* The card should use the just-allocated buffer. */
    outw(packet_no, ioaddr + PNR_ARR);
    /* point to the beginning of the packet */
    outw(PTR_AUTOINC , ioaddr + POINTER);

    /* Send the packet length (+6 for status, length and ctl byte)
       and the status word (set to zeros). */
    {
	u_char *buf = skb->data;
	u_int length = skb->len; /* The chip will pad to ethernet min. */

1220
	pr_debug("%s: Trying to xmit packet of length %d.\n",
L
Linus Torvalds 已提交
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
	      dev->name, length);
	
	/* send the packet length: +6 for status word, length, and ctl */
	outw(0, ioaddr + DATA_1);
	outw(length + 6, ioaddr + DATA_1);
	outsw(ioaddr + DATA_1, buf, length >> 1);
	
	/* The odd last byte, if there is one, goes in the control word. */
	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
    }

    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
	 (inw(ioaddr + INTERRUPT) & 0xff00),
	 ioaddr + INTERRUPT);

    /* The chip does the rest of the work. */
    outw(MC_ENQUEUE , ioaddr + MMU_CMD);

    smc->saved_skb = NULL;
    dev_kfree_skb_irq(skb);
    dev->trans_start = jiffies;
    netif_start_queue(dev);
    return;
}

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

static void smc_tx_timeout(struct net_device *dev)
{
    struct smc_private *smc = netdev_priv(dev);
1252
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1253 1254 1255 1256

    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
	   "Tx_status %2.2x status %4.4x.\n",
	   dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
1257
    dev->stats.tx_errors++;
L
Linus Torvalds 已提交
1258 1259 1260 1261 1262 1263
    smc_reset(dev);
    dev->trans_start = jiffies;
    smc->saved_skb = NULL;
    netif_wake_queue(dev);
}

1264 1265
static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
					struct net_device *dev)
L
Linus Torvalds 已提交
1266 1267
{
    struct smc_private *smc = netdev_priv(dev);
1268
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1269 1270
    u_short num_pages;
    short time_out, ir;
1271
    unsigned long flags;
L
Linus Torvalds 已提交
1272 1273 1274

    netif_stop_queue(dev);

1275
    pr_debug("%s: smc_start_xmit(length = %d) called,"
L
Linus Torvalds 已提交
1276 1277 1278 1279
	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));

    if (smc->saved_skb) {
	/* THIS SHOULD NEVER HAPPEN. */
1280
	dev->stats.tx_aborted_errors++;
L
Linus Torvalds 已提交
1281 1282
	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
	       dev->name);
1283
	return NETDEV_TX_BUSY;
L
Linus Torvalds 已提交
1284 1285 1286 1287 1288 1289 1290 1291 1292
    }
    smc->saved_skb = skb;

    num_pages = skb->len >> 8;

    if (num_pages > 7) {
	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
	dev_kfree_skb (skb);
	smc->saved_skb = NULL;
1293
	dev->stats.tx_dropped++;
1294
	return NETDEV_TX_OK;		/* Do not re-queue this packet. */
L
Linus Torvalds 已提交
1295 1296 1297 1298
    }
    /* A packet is now waiting. */
    smc->packets_waiting++;

1299
    spin_lock_irqsave(&smc->lock, flags);
L
Linus Torvalds 已提交
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
    SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */

    /* need MC_RESET to keep the memory consistent. errata? */
    if (smc->rx_ovrn) {
	outw(MC_RESET, ioaddr + MMU_CMD);
	smc->rx_ovrn = 0;
    }

    /* Allocate the memory; send the packet now if we win. */
    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
	ir = inw(ioaddr+INTERRUPT);
	if (ir & IM_ALLOC_INT) {
	    /* Acknowledge the interrupt, send the packet. */
	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
	    smc_hardware_send_packet(dev);	/* Send the packet now.. */
1316
	    spin_unlock_irqrestore(&smc->lock, flags);
1317
	    return NETDEV_TX_OK;
L
Linus Torvalds 已提交
1318 1319 1320 1321
	}
    }

    /* Otherwise defer until the Tx-space-allocated interrupt. */
1322
    pr_debug("%s: memory allocation deferred.\n", dev->name);
L
Linus Torvalds 已提交
1323
    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
1324
    spin_unlock_irqrestore(&smc->lock, flags);
L
Linus Torvalds 已提交
1325

1326
    return NETDEV_TX_OK;
L
Linus Torvalds 已提交
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
}

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

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

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

static void smc_tx_err(struct net_device * dev)
{
    struct smc_private *smc = netdev_priv(dev);
1338
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
    int tx_status;

    /* select this as the packet to read from */
    outw(packet_no, ioaddr + PNR_ARR);

    /* read the first word from this packet */
    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);

    tx_status = inw(ioaddr + DATA_1);

1351 1352 1353
    dev->stats.tx_errors++;
    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
L
Linus Torvalds 已提交
1354
    if (tx_status & TS_16COL) {
1355
	dev->stats.tx_aborted_errors++;
L
Linus Torvalds 已提交
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
	smc->tx_err++;
    }

    if (tx_status & TS_SUCCESS) {
	printk(KERN_NOTICE "%s: Successful packet caused error "
	       "interrupt?\n", dev->name);
    }
    /* re-enable transmit */
    SMC_SELECT_BANK(0);
    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
    SMC_SELECT_BANK(2);

    outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */

    /* one less packet waiting for me */
    smc->packets_waiting--;

    outw(saved_packet, ioaddr + PNR_ARR);
    return;
}

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

static void smc_eph_irq(struct net_device *dev)
{
    struct smc_private *smc = netdev_priv(dev);
1382
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1383 1384 1385 1386
    u_short card_stats, ephs;

    SMC_SELECT_BANK(0);
    ephs = inw(ioaddr + EPH);
1387
    pr_debug("%s: Ethernet protocol handler interrupt, status"
L
Linus Torvalds 已提交
1388 1389 1390 1391
	  " %4.4x.\n", dev->name, ephs);
    /* Could be a counter roll-over warning: update stats. */
    card_stats = inw(ioaddr + COUNTER);
    /* single collisions */
1392
    dev->stats.collisions += card_stats & 0xF;
L
Linus Torvalds 已提交
1393 1394
    card_stats >>= 4;
    /* multiple collisions */
1395
    dev->stats.collisions += card_stats & 0xF;
L
Linus Torvalds 已提交
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
#if 0 		/* These are for when linux supports these statistics */
    card_stats >>= 4;			/* deferred */
    card_stats >>= 4;			/* excess deferred */
#endif
    /* If we had a transmit error we must re-enable the transmitter. */
    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);

    /* Clear a link error interrupt. */
    SMC_SELECT_BANK(1);
    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
	 ioaddr + CONTROL);
    SMC_SELECT_BANK(2);
}

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

1413
static irqreturn_t smc_interrupt(int irq, void *dev_id)
L
Linus Torvalds 已提交
1414 1415 1416
{
    struct net_device *dev = dev_id;
    struct smc_private *smc = netdev_priv(dev);
1417
    unsigned int ioaddr;
L
Linus Torvalds 已提交
1418 1419 1420 1421 1422 1423 1424 1425 1426
    u_short saved_bank, saved_pointer, mask, status;
    unsigned int handled = 1;
    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */

    if (!netif_device_present(dev))
	return IRQ_NONE;

    ioaddr = dev->base_addr;

1427
    pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
L
Linus Torvalds 已提交
1428 1429
	  irq, ioaddr);

1430
    spin_lock(&smc->lock);
L
Linus Torvalds 已提交
1431 1432 1433 1434 1435
    smc->watchdog = 0;
    saved_bank = inw(ioaddr + BANK_SELECT);
    if ((saved_bank & 0xff00) != 0x3300) {
	/* The device does not exist -- the card could be off-line, or
	   maybe it has been ejected. */
1436
	pr_debug("%s: SMC91c92 interrupt %d for non-existent"
L
Linus Torvalds 已提交
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
	      "/ejected device.\n", dev->name, irq);
	handled = 0;
	goto irq_done;
    }

    SMC_SELECT_BANK(2);
    saved_pointer = inw(ioaddr + POINTER);
    mask = inw(ioaddr + INTERRUPT) >> 8;
    /* clear all interrupts */
    outw(0, ioaddr + INTERRUPT);

    do { /* read the status flag, and mask it */
	status = inw(ioaddr + INTERRUPT) & 0xff;
1450
	pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
L
Linus Torvalds 已提交
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
	      status, mask);
	if ((status & mask) == 0) {
	    if (bogus_cnt == INTR_WORK)
		handled = 0;
	    break;
	}
	if (status & IM_RCV_INT) {
	    /* Got a packet(s). */
	    smc_rx(dev);
	}
	if (status & IM_TX_INT) {
	    smc_tx_err(dev);
	    outw(IM_TX_INT, ioaddr + INTERRUPT);
	}
	status &= mask;
	if (status & IM_TX_EMPTY_INT) {
	    outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
	    mask &= ~IM_TX_EMPTY_INT;
1469
	    dev->stats.tx_packets += smc->packets_waiting;
L
Linus Torvalds 已提交
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
	    smc->packets_waiting = 0;
	}
	if (status & IM_ALLOC_INT) {
	    /* Clear this interrupt so it doesn't happen again */
	    mask &= ~IM_ALLOC_INT;
	
	    smc_hardware_send_packet(dev);
	
	    /* enable xmit interrupts based on this */
	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
	
	    /* and let the card send more packets to me */
	    netif_wake_queue(dev);
	}
	if (status & IM_RX_OVRN_INT) {
1485 1486
	    dev->stats.rx_errors++;
	    dev->stats.rx_fifo_errors++;
L
Linus Torvalds 已提交
1487 1488 1489 1490 1491 1492 1493 1494
	    if (smc->duplex)
		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
	}
	if (status & IM_EPH_INT)
	    smc_eph_irq(dev);
    } while (--bogus_cnt);

1495
    pr_debug("  Restoring saved registers mask %2.2x bank %4.4x"
L
Linus Torvalds 已提交
1496 1497 1498 1499 1500 1501 1502
	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);

    /* restore state register */
    outw((mask<<8), ioaddr + INTERRUPT);
    outw(saved_pointer, ioaddr + POINTER);
    SMC_SELECT_BANK(saved_bank);

1503
    pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
L
Linus Torvalds 已提交
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527

irq_done:

    if ((smc->manfid == MANFID_OSITECH) &&
	(smc->cardid != PRODID_OSITECH_SEVEN)) {
	/* Retrigger interrupt if needed */
	mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
	set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
    }
    if (smc->manfid == MANFID_MOTOROLA) {
	u_char cor;
	cor = readb(smc->base + MOT_UART + CISREG_COR);
	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
	writeb(cor, smc->base + MOT_UART + CISREG_COR);
	cor = readb(smc->base + MOT_LAN + CISREG_COR);
	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
	writeb(cor, smc->base + MOT_LAN + CISREG_COR);
    }
#ifdef DOES_NOT_WORK
    if (smc->base != NULL) { /* Megahertz MFC's */
	readb(smc->base+MEGAHERTZ_ISR);
	readb(smc->base+MEGAHERTZ_ISR);
    }
#endif
1528
    spin_unlock(&smc->lock);
L
Linus Torvalds 已提交
1529 1530 1531 1532 1533 1534 1535
    return IRQ_RETVAL(handled);
}

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

static void smc_rx(struct net_device *dev)
{
1536
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
    int rx_status;
    int packet_length;	/* Caution: not frame length, rather words
			   to transfer from the chip. */

    /* Assertion: we are in Window 2. */

    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
	       dev->name);
	return;
    }

    /*  Reset the read pointer, and read the status and packet length. */
    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
    rx_status = inw(ioaddr + DATA_1);
    packet_length = inw(ioaddr + DATA_1) & 0x07ff;

1554
    pr_debug("%s: Receive status %4.4x length %d.\n",
L
Linus Torvalds 已提交
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
	  dev->name, rx_status, packet_length);

    if (!(rx_status & RS_ERRORS)) {		
	/* do stuff to make a new packet */
	struct sk_buff *skb;
	
	/* Note: packet_length adds 5 or 6 extra bytes here! */
	skb = dev_alloc_skb(packet_length+2);
	
	if (skb == NULL) {
1565
	    pr_debug("%s: Low memory, packet dropped.\n", dev->name);
1566
	    dev->stats.rx_dropped++;
L
Linus Torvalds 已提交
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
	    outw(MC_RELEASE, ioaddr + MMU_CMD);
	    return;
	}
	
	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
	skb_reserve(skb, 2);
	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
	     (packet_length+1)>>1);
	skb->protocol = eth_type_trans(skb, dev);
	
	netif_rx(skb);
	dev->last_rx = jiffies;
1579 1580
	dev->stats.rx_packets++;
	dev->stats.rx_bytes += packet_length;
L
Linus Torvalds 已提交
1581
	if (rx_status & RS_MULTICAST)
1582
	    dev->stats.multicast++;
L
Linus Torvalds 已提交
1583 1584
    } else {
	/* error ... */
1585
	dev->stats.rx_errors++;
L
Linus Torvalds 已提交
1586
	
1587
	if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
L
Linus Torvalds 已提交
1588
	if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
1589 1590
	    dev->stats.rx_length_errors++;
	if (rx_status & RS_BADCRC)	dev->stats.rx_crc_errors++;
L
Linus Torvalds 已提交
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
    }
    /* Let the MMU free the memory of this packet. */
    outw(MC_RELEASE, ioaddr + MMU_CMD);

    return;
}

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

    Calculate values for the hardware multicast filter hash table.

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

static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
			       u_char *multicast_table)
{
    struct dev_mc_list	*mc_addr;

K
Komuro 已提交
1609
    for (mc_addr = addrs;  mc_addr && count-- > 0;  mc_addr = mc_addr->next) {
L
Linus Torvalds 已提交
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
	u_int position = ether_crc(6, mc_addr->dmi_addr);
#ifndef final_version		/* Verify multicast address. */
	if ((mc_addr->dmi_addr[0] & 1) == 0)
	    continue;
#endif
	multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
    }
}

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

    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)
{
1632
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
    struct smc_private *smc = netdev_priv(dev);
    u_int multicast_table[ 2 ] = { 0, };
    unsigned long flags;
    u_short rx_cfg_setting;

    if (dev->flags & IFF_PROMISC) {
	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
    } else if (dev->flags & IFF_ALLMULTI)
	rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
    else {
	if (dev->mc_count)  {
	    fill_multicast_tbl(dev->mc_count, dev->mc_list,
			       (u_char *)multicast_table);
	}
	rx_cfg_setting = RxStripCRC | RxEnable;
    }

    /* Load MC table and Rx setting into the chip without interrupts. */
    spin_lock_irqsave(&smc->lock, flags);
    SMC_SELECT_BANK(3);
    outl(multicast_table[0], ioaddr + MULTICAST0);
    outl(multicast_table[1], ioaddr + MULTICAST4);
    SMC_SELECT_BANK(0);
    outw(rx_cfg_setting, ioaddr + RCR);
    SMC_SELECT_BANK(2);
    spin_unlock_irqrestore(&smc->lock, flags);

    return;
}

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

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

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

static int s9k_config(struct net_device *dev, struct ifmap *map)
{
    struct smc_private *smc = netdev_priv(dev);
    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
	if (smc->cfg & CFG_MII_SELECT)
	    return -EOPNOTSUPP;
	else if (map->port > 2)
	    return -EINVAL;
	dev->if_port = map->port;
	printk(KERN_INFO "%s: switched to %s port\n",
	       dev->name, if_names[dev->if_port]);
	smc_reset(dev);
    }
    return 0;
}

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

    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)
{
    struct smc_private *smc = netdev_priv(dev);
1698
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
    u_short saved_bank;

    saved_bank = inw(ioaddr + BANK_SELECT);
    SMC_SELECT_BANK(1);
    if (if_port == 2) {
	outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
	if ((smc->manfid == MANFID_OSITECH) &&
	    (smc->cardid != PRODID_OSITECH_SEVEN))
	    set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
	smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
    } else {
	outw(smc->cfg, ioaddr + CONFIG);
	if ((smc->manfid == MANFID_OSITECH) &&
	    (smc->cardid != PRODID_OSITECH_SEVEN))
	    mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
	smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
    }
    SMC_SELECT_BANK(saved_bank);
}

static void smc_reset(struct net_device *dev)
{
1721
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1722 1723 1724
    struct smc_private *smc = netdev_priv(dev);
    int i;

1725
    pr_debug("%s: smc91c92 reset called.\n", dev->name);
L
Linus Torvalds 已提交
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740

    /* The first interaction must be a write to bring the chip out
       of sleep mode. */
    SMC_SELECT_BANK(0);
    /* Reset the chip. */
    outw(RCR_SOFTRESET, ioaddr + RCR);
    udelay(10);

    /* Clear the transmit and receive configuration registers. */
    outw(RCR_CLEAR, ioaddr + RCR);
    outw(TCR_CLEAR, ioaddr + TCR);

    /* Set the Window 1 control, configuration and station addr registers.
       No point in writing the I/O base register ;-> */
    SMC_SELECT_BANK(1);
A
Andreas Mohr 已提交
1741
    /* Automatically release successfully transmitted packets,
L
Linus Torvalds 已提交
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
       Accept link errors, counter and Tx error interrupts. */
    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
	 ioaddr + CONTROL);
    smc_set_xcvr(dev, dev->if_port);
    if ((smc->manfid == MANFID_OSITECH) &&
	(smc->cardid != PRODID_OSITECH_SEVEN))
	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
	     ioaddr - 0x10 + OSITECH_AUI_PWR);

    /* Fill in the physical address.  The databook is wrong about the order! */
    for (i = 0; i < 6; i += 2)
	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
	     ioaddr + ADDR0 + i);

    /* Reset the MMU */
    SMC_SELECT_BANK(2);
    outw(MC_RESET, ioaddr + MMU_CMD);
    outw(0, ioaddr + INTERRUPT);

    /* Re-enable the chip. */
    SMC_SELECT_BANK(0);
    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
    set_rx_mode(dev);

    if (smc->cfg & CFG_MII_SELECT) {
	SMC_SELECT_BANK(3);

	/* Reset MII */
	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);

	/* Advertise 100F, 100H, 10F, 10H */
	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);

	/* Restart MII autonegotiation */
	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
    }

    /* Enable interrupts. */
    SMC_SELECT_BANK(2);
    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
	 ioaddr + INTERRUPT);
}

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

    Media selection timer routine

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

static void media_check(u_long arg)
{
    struct net_device *dev = (struct net_device *) arg;
    struct smc_private *smc = netdev_priv(dev);
1798
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1799 1800
    u_short i, media, saved_bank;
    u_short link;
1801 1802 1803
    unsigned long flags;

    spin_lock_irqsave(&smc->lock, flags);
L
Linus Torvalds 已提交
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827

    saved_bank = inw(ioaddr + BANK_SELECT);

    if (!netif_device_present(dev))
	goto reschedule;

    SMC_SELECT_BANK(2);

    /* need MC_RESET to keep the memory consistent. errata? */
    if (smc->rx_ovrn) {
	outw(MC_RESET, ioaddr + MMU_CMD);
	smc->rx_ovrn = 0;
    }
    i = inw(ioaddr + INTERRUPT);
    SMC_SELECT_BANK(0);
    media = inw(ioaddr + EPH) & EPH_LINK_OK;
    SMC_SELECT_BANK(1);
    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;

    /* Check for pending interrupt with watchdog flag set: with
       this, we can limp along even if the interrupt is blocked */
    if (smc->watchdog++ && ((i>>8) & i)) {
	if (!smc->fast_poll)
	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
1828
	smc_interrupt(dev->irq, dev);
L
Linus Torvalds 已提交
1829 1830 1831 1832 1833 1834 1835
	smc->fast_poll = HZ;
    }
    if (smc->fast_poll) {
	smc->fast_poll--;
	smc->media.expires = jiffies + HZ/100;
	add_timer(&smc->media);
	SMC_SELECT_BANK(saved_bank);
1836
	spin_unlock_irqrestore(&smc->lock, flags);
L
Linus Torvalds 已提交
1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
	return;
    }

    if (smc->cfg & CFG_MII_SELECT) {
	if (smc->mii_if.phy_id < 0)
	    goto reschedule;

	SMC_SELECT_BANK(3);
	link = mdio_read(dev, smc->mii_if.phy_id, 1);
	if (!link || (link == 0xffff)) {
  	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
	    smc->mii_if.phy_id = -1;
	    goto reschedule;
	}

	link &= 0x0004;
	if (link != smc->link_status) {
	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
		(link) ? "found" : "lost");
	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
			   ? TCR_FDUPLX : 0);
	    if (link) {
	        printk(KERN_INFO "%s: autonegotiation complete: "
		       "%sbaseT-%cD selected\n", dev->name,
		       ((p & 0x0180) ? "100" : "10"),
		       (smc->duplex ? 'F' : 'H'));
	    }
	    SMC_SELECT_BANK(0);
	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
	    smc->link_status = link;
	}
	goto reschedule;
    }

    /* Ignore collisions unless we've had no rx's recently */
1873
    if (time_after(jiffies, dev->last_rx + HZ)) {
L
Linus Torvalds 已提交
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
	if (smc->tx_err || (smc->media_status & EPH_16COL))
	    media |= EPH_16COL;
    }
    smc->tx_err = 0;

    if (media != smc->media_status) {
	if ((media & smc->media_status & 1) &&
	    ((smc->media_status ^ media) & EPH_LINK_OK))
	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
		   (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
	else if ((media & smc->media_status & 2) &&
		 ((smc->media_status ^ media) & EPH_16COL))
	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,
		   (media & EPH_16COL ? "problem" : "ok"));
	if (dev->if_port == 0) {
	    if (media & 1) {
		if (media & EPH_LINK_OK)
		    printk(KERN_INFO "%s: flipped to 10baseT\n",
			   dev->name);
		else
		    smc_set_xcvr(dev, 2);
	    } else {
		if (media & EPH_16COL)
		    smc_set_xcvr(dev, 1);
		else
		    printk(KERN_INFO "%s: flipped to 10base2\n",
			   dev->name);
	    }
	}
	smc->media_status = media;
    }

reschedule:
    smc->media.expires = jiffies + HZ;
    add_timer(&smc->media);
    SMC_SELECT_BANK(saved_bank);
1910
    spin_unlock_irqrestore(&smc->lock, flags);
L
Linus Torvalds 已提交
1911 1912 1913 1914
}

static int smc_link_ok(struct net_device *dev)
{
1915
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
    struct smc_private *smc = netdev_priv(dev);

    if (smc->cfg & CFG_MII_SELECT) {
	return mii_link_ok(&smc->mii_if);
    } else {
        SMC_SELECT_BANK(0);
	return inw(ioaddr + EPH) & EPH_LINK_OK;
    }
}

static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
    u16 tmp;
1929
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950

    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
		
    SMC_SELECT_BANK(1);
    tmp = inw(ioaddr + CONFIG);
    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
    ecmd->transceiver = XCVR_INTERNAL;
    ecmd->speed = SPEED_10;
    ecmd->phy_address = ioaddr + MGMT;

    SMC_SELECT_BANK(0);
    tmp = inw(ioaddr + TCR);
    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;

    return 0;
}

static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
    u16 tmp;
1951
    unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993

    if (ecmd->speed != SPEED_10)
    	return -EINVAL;
    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
    	return -EINVAL;
    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
	return -EINVAL;
    if (ecmd->transceiver != XCVR_INTERNAL)
    	return -EINVAL;

    if (ecmd->port == PORT_AUI)
	smc_set_xcvr(dev, 1);
    else
	smc_set_xcvr(dev, 0);

    SMC_SELECT_BANK(0);
    tmp = inw(ioaddr + TCR);
    if (ecmd->duplex == DUPLEX_FULL)
	tmp |= TCR_FDUPLX;
    else
	tmp &= ~TCR_FDUPLX;
    outw(tmp, ioaddr + TCR);
	
    return 0;
}

static int check_if_running(struct net_device *dev)
{
	if (!netif_running(dev))
		return -EINVAL;
	return 0;
}

static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
	strcpy(info->driver, DRV_NAME);
	strcpy(info->version, DRV_VERSION);
}

static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
	struct smc_private *smc = netdev_priv(dev);
1994
	unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
1995 1996 1997 1998
	u16 saved_bank = inw(ioaddr + BANK_SELECT);
	int ret;

	spin_lock_irq(&smc->lock);
1999
	SMC_SELECT_BANK(3);
L
Linus Torvalds 已提交
2000 2001 2002 2003 2004
	if (smc->cfg & CFG_MII_SELECT)
		ret = mii_ethtool_gset(&smc->mii_if, ecmd);
	else
		ret = smc_netdev_get_ecmd(dev, ecmd);
	SMC_SELECT_BANK(saved_bank);
2005
	spin_unlock_irq(&smc->lock);
L
Linus Torvalds 已提交
2006 2007 2008 2009 2010 2011
	return ret;
}

static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
	struct smc_private *smc = netdev_priv(dev);
2012
	unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
2013 2014 2015 2016
	u16 saved_bank = inw(ioaddr + BANK_SELECT);
	int ret;

	spin_lock_irq(&smc->lock);
2017
	SMC_SELECT_BANK(3);
L
Linus Torvalds 已提交
2018 2019 2020 2021 2022
	if (smc->cfg & CFG_MII_SELECT)
		ret = mii_ethtool_sset(&smc->mii_if, ecmd);
	else
		ret = smc_netdev_set_ecmd(dev, ecmd);
	SMC_SELECT_BANK(saved_bank);
2023
	spin_unlock_irq(&smc->lock);
L
Linus Torvalds 已提交
2024 2025 2026 2027 2028 2029
	return ret;
}

static u32 smc_get_link(struct net_device *dev)
{
	struct smc_private *smc = netdev_priv(dev);
2030
	unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
2031 2032 2033 2034
	u16 saved_bank = inw(ioaddr + BANK_SELECT);
	u32 ret;

	spin_lock_irq(&smc->lock);
2035
	SMC_SELECT_BANK(3);
L
Linus Torvalds 已提交
2036 2037
	ret = smc_link_ok(dev);
	SMC_SELECT_BANK(saved_bank);
2038
	spin_unlock_irq(&smc->lock);
L
Linus Torvalds 已提交
2039 2040 2041 2042 2043 2044 2045
	return ret;
}

static int smc_nway_reset(struct net_device *dev)
{
	struct smc_private *smc = netdev_priv(dev);
	if (smc->cfg & CFG_MII_SELECT) {
2046
		unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
		u16 saved_bank = inw(ioaddr + BANK_SELECT);
		int res;

		SMC_SELECT_BANK(3);
		res = mii_nway_restart(&smc->mii_if);
		SMC_SELECT_BANK(saved_bank);

		return res;
	} else
		return -EOPNOTSUPP;
}

2059
static const struct ethtool_ops ethtool_ops = {
L
Linus Torvalds 已提交
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
	.begin = check_if_running,
	.get_drvinfo = smc_get_drvinfo,
	.get_settings = smc_get_settings,
	.set_settings = smc_set_settings,
	.get_link = smc_get_link,
	.nway_reset = smc_nway_reset,
};

static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
	struct smc_private *smc = netdev_priv(dev);
	struct mii_ioctl_data *mii = if_mii(rq);
	int rc = 0;
	u16 saved_bank;
2074
	unsigned int ioaddr = dev->base_addr;
L
Linus Torvalds 已提交
2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087

	if (!netif_running(dev))
		return -EINVAL;

	spin_lock_irq(&smc->lock);
	saved_bank = inw(ioaddr + BANK_SELECT);
	SMC_SELECT_BANK(3);
	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
	SMC_SELECT_BANK(saved_bank);
	spin_unlock_irq(&smc->lock);
	return rc;
}

2088 2089 2090 2091 2092 2093 2094 2095 2096
static struct pcmcia_device_id smc91c92_ids[] = {
	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
K
Komuro 已提交
2097 2098
	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
2099 2100 2101 2102 2103 2104 2105 2106 2107
	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
	PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
	PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
	PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
	PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
	PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
	PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
	PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
K
Komuro 已提交
2108 2109
	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
	PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
	PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
	/* These conflict with other cards! */
	/* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
	/* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
	PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);

L
Linus Torvalds 已提交
2120 2121 2122 2123 2124
static struct pcmcia_driver smc91c92_cs_driver = {
	.owner		= THIS_MODULE,
	.drv		= {
		.name	= "smc91c92_cs",
	},
2125
	.probe		= smc91c92_probe,
2126
	.remove		= smc91c92_detach,
2127
	.id_table       = smc91c92_ids,
2128 2129
	.suspend	= smc91c92_suspend,
	.resume		= smc91c92_resume,
L
Linus Torvalds 已提交
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
};

static int __init init_smc91c92_cs(void)
{
	return pcmcia_register_driver(&smc91c92_cs_driver);
}

static void __exit exit_smc91c92_cs(void)
{
	pcmcia_unregister_driver(&smc91c92_cs_driver);
}

module_init(init_smc91c92_cs);
module_exit(exit_smc91c92_cs);