162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+
262306a36Sopenharmony_ci/*======================================================================
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci    A PCMCIA ethernet driver for NS8390-based cards
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci    This driver supports the D-Link DE-650 and Linksys EthernetCard
762306a36Sopenharmony_ci    cards, the newer D-Link and Linksys combo cards, Accton EN2212
862306a36Sopenharmony_ci    cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
962306a36Sopenharmony_ci    mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
1062306a36Sopenharmony_ci    Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
1162306a36Sopenharmony_ci    mode.  It will also handle the Socket EA card in either mode.
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci    pcnet_cs.c 1.153 2003/11/09 18:53:09
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci    The network driver code is based on Donald Becker's NE2000 code:
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci    Written 1992,1993 by Donald Becker.
2062306a36Sopenharmony_ci    Copyright 1993 United States Government as represented by the
2162306a36Sopenharmony_ci    Director, National Security Agency.
2262306a36Sopenharmony_ci    Donald Becker may be reached at becker@scyld.com
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci    Based also on Keith Moore's changes to Don Becker's code, for IBM
2562306a36Sopenharmony_ci    CCAE support.  Drivers merged back together, and shared-memory
2662306a36Sopenharmony_ci    Socket EA support added, by Ken Raeburn, September 1995.
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci======================================================================*/
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/kernel.h>
3362306a36Sopenharmony_ci#include <linux/module.h>
3462306a36Sopenharmony_ci#include <linux/ptrace.h>
3562306a36Sopenharmony_ci#include <linux/string.h>
3662306a36Sopenharmony_ci#include <linux/timer.h>
3762306a36Sopenharmony_ci#include <linux/delay.h>
3862306a36Sopenharmony_ci#include <linux/netdevice.h>
3962306a36Sopenharmony_ci#include <linux/log2.h>
4062306a36Sopenharmony_ci#include <linux/etherdevice.h>
4162306a36Sopenharmony_ci#include <linux/mii.h>
4262306a36Sopenharmony_ci#include "8390.h"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <pcmcia/cistpl.h>
4562306a36Sopenharmony_ci#include <pcmcia/ciscode.h>
4662306a36Sopenharmony_ci#include <pcmcia/ds.h>
4762306a36Sopenharmony_ci#include <pcmcia/cisreg.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <asm/io.h>
5062306a36Sopenharmony_ci#include <asm/byteorder.h>
5162306a36Sopenharmony_ci#include <linux/uaccess.h>
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define PCNET_CMD	0x00
5462306a36Sopenharmony_ci#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
5562306a36Sopenharmony_ci#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
5662306a36Sopenharmony_ci#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define PCNET_START_PG	0x40	/* First page of TX buffer */
5962306a36Sopenharmony_ci#define PCNET_STOP_PG	0x80	/* Last page +1 of RX ring */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Socket EA cards have a larger packet buffer */
6262306a36Sopenharmony_ci#define SOCKET_START_PG	0x01
6362306a36Sopenharmony_ci#define SOCKET_STOP_PG	0xff
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define PCNET_RDC_TIMEOUT (2*HZ/100)	/* Max wait in jiffies for Tx RDC */
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic const char *if_names[] = { "auto", "10baseT", "10base2"};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*====================================================================*/
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Module parameters */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciMODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
7462306a36Sopenharmony_ciMODULE_DESCRIPTION("NE2000 compatible PCMCIA ethernet driver");
7562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciINT_MODULE_PARM(if_port,	1);	/* Transceiver type */
8062306a36Sopenharmony_ciINT_MODULE_PARM(use_big_buf,	1);	/* use 64K packet buffer? */
8162306a36Sopenharmony_ciINT_MODULE_PARM(mem_speed,	0);	/* shared mem speed, in ns */
8262306a36Sopenharmony_ciINT_MODULE_PARM(delay_output,	0);	/* pause after xmit? */
8362306a36Sopenharmony_ciINT_MODULE_PARM(delay_time,	4);	/* in usec */
8462306a36Sopenharmony_ciINT_MODULE_PARM(use_shmem,	-1);	/* use shared memory? */
8562306a36Sopenharmony_ciINT_MODULE_PARM(full_duplex,	0);	/* full duplex? */
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Ugh!  Let the user hardwire the hardware address for queer cards */
8862306a36Sopenharmony_cistatic int hw_addr[6] = { 0, /* ... */ };
8962306a36Sopenharmony_cimodule_param_array(hw_addr, int, NULL, 0);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*====================================================================*/
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void mii_phy_probe(struct net_device *dev);
9462306a36Sopenharmony_cistatic int pcnet_config(struct pcmcia_device *link);
9562306a36Sopenharmony_cistatic void pcnet_release(struct pcmcia_device *link);
9662306a36Sopenharmony_cistatic int pcnet_open(struct net_device *dev);
9762306a36Sopenharmony_cistatic int pcnet_close(struct net_device *dev);
9862306a36Sopenharmony_cistatic int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
9962306a36Sopenharmony_cistatic irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
10062306a36Sopenharmony_cistatic void ei_watchdog(struct timer_list *t);
10162306a36Sopenharmony_cistatic void pcnet_reset_8390(struct net_device *dev);
10262306a36Sopenharmony_cistatic int set_config(struct net_device *dev, struct ifmap *map);
10362306a36Sopenharmony_cistatic int setup_shmem_window(struct pcmcia_device *link, int start_pg,
10462306a36Sopenharmony_ci			      int stop_pg, int cm_offset);
10562306a36Sopenharmony_cistatic int setup_dma_config(struct pcmcia_device *link, int start_pg,
10662306a36Sopenharmony_ci			    int stop_pg);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic void pcnet_detach(struct pcmcia_device *p_dev);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*====================================================================*/
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct hw_info {
11362306a36Sopenharmony_ci    u_int	offset;
11462306a36Sopenharmony_ci    u_char	a0, a1, a2;
11562306a36Sopenharmony_ci    u_int	flags;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define DELAY_OUTPUT	0x01
11962306a36Sopenharmony_ci#define HAS_MISC_REG	0x02
12062306a36Sopenharmony_ci#define USE_BIG_BUF	0x04
12162306a36Sopenharmony_ci#define HAS_IBM_MISC	0x08
12262306a36Sopenharmony_ci#define IS_DL10019	0x10
12362306a36Sopenharmony_ci#define IS_DL10022	0x20
12462306a36Sopenharmony_ci#define HAS_MII		0x40
12562306a36Sopenharmony_ci#define USE_SHMEM	0x80	/* autodetected */
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define AM79C9XX_HOME_PHY	0x00006B90  /* HomePNA PHY */
12862306a36Sopenharmony_ci#define AM79C9XX_ETH_PHY	0x00006B70  /* 10baseT PHY */
12962306a36Sopenharmony_ci#define MII_PHYID_REV_MASK	0xfffffff0
13062306a36Sopenharmony_ci#define MII_PHYID_REG1		0x02
13162306a36Sopenharmony_ci#define MII_PHYID_REG2		0x03
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic struct hw_info hw_info[] = {
13462306a36Sopenharmony_ci    { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
13562306a36Sopenharmony_ci    { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
13662306a36Sopenharmony_ci    { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
13762306a36Sopenharmony_ci    { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
13862306a36Sopenharmony_ci      DELAY_OUTPUT | HAS_IBM_MISC },
13962306a36Sopenharmony_ci    { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
14062306a36Sopenharmony_ci    { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
14162306a36Sopenharmony_ci    { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
14262306a36Sopenharmony_ci    { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
14362306a36Sopenharmony_ci    { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
14462306a36Sopenharmony_ci    { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
14562306a36Sopenharmony_ci    { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
14662306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
14762306a36Sopenharmony_ci    { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
14862306a36Sopenharmony_ci    { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
14962306a36Sopenharmony_ci    { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
15062306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
15162306a36Sopenharmony_ci    { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
15262306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
15362306a36Sopenharmony_ci    { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
15462306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
15562306a36Sopenharmony_ci    { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
15662306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
15762306a36Sopenharmony_ci    { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
15862306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
15962306a36Sopenharmony_ci    { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
16062306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
16162306a36Sopenharmony_ci    { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
16262306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
16362306a36Sopenharmony_ci    { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
16462306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
16562306a36Sopenharmony_ci    { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
16662306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
16762306a36Sopenharmony_ci    { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
16862306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
16962306a36Sopenharmony_ci    { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
17062306a36Sopenharmony_ci    { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
17162306a36Sopenharmony_ci    { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
17262306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
17362306a36Sopenharmony_ci    { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
17462306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
17562306a36Sopenharmony_ci    { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
17662306a36Sopenharmony_ci    { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
17762306a36Sopenharmony_ci    { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
17862306a36Sopenharmony_ci    { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
17962306a36Sopenharmony_ci    { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
18062306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
18162306a36Sopenharmony_ci    { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
18262306a36Sopenharmony_ci      HAS_MISC_REG | HAS_IBM_MISC },
18362306a36Sopenharmony_ci    { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
18462306a36Sopenharmony_ci    { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
18562306a36Sopenharmony_ci    { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
18662306a36Sopenharmony_ci    { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
18762306a36Sopenharmony_ci      DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
18862306a36Sopenharmony_ci    { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
18962306a36Sopenharmony_ci    { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
19062306a36Sopenharmony_ci    { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
19162306a36Sopenharmony_ci    { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
19262306a36Sopenharmony_ci    { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define NR_INFO		ARRAY_SIZE(hw_info)
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic struct hw_info default_info = { 0, 0, 0, 0, 0 };
19862306a36Sopenharmony_cistatic struct hw_info dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
19962306a36Sopenharmony_cistatic struct hw_info dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistruct pcnet_dev {
20262306a36Sopenharmony_ci	struct pcmcia_device	*p_dev;
20362306a36Sopenharmony_ci    u_int		flags;
20462306a36Sopenharmony_ci    void		__iomem *base;
20562306a36Sopenharmony_ci    struct timer_list	watchdog;
20662306a36Sopenharmony_ci    int			stale, fast_poll;
20762306a36Sopenharmony_ci    u_char		phy_id;
20862306a36Sopenharmony_ci    u_char		eth_phy, pna_phy;
20962306a36Sopenharmony_ci    u_short		link_status;
21062306a36Sopenharmony_ci    u_long		mii_reset;
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic inline struct pcnet_dev *PRIV(struct net_device *dev)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	char *p = netdev_priv(dev);
21662306a36Sopenharmony_ci	return (struct pcnet_dev *)(p + sizeof(struct ei_device));
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic const struct net_device_ops pcnet_netdev_ops = {
22062306a36Sopenharmony_ci	.ndo_open		= pcnet_open,
22162306a36Sopenharmony_ci	.ndo_stop		= pcnet_close,
22262306a36Sopenharmony_ci	.ndo_set_config		= set_config,
22362306a36Sopenharmony_ci	.ndo_start_xmit 	= ei_start_xmit,
22462306a36Sopenharmony_ci	.ndo_get_stats		= ei_get_stats,
22562306a36Sopenharmony_ci	.ndo_eth_ioctl		= ei_ioctl,
22662306a36Sopenharmony_ci	.ndo_set_rx_mode	= ei_set_multicast_list,
22762306a36Sopenharmony_ci	.ndo_tx_timeout 	= ei_tx_timeout,
22862306a36Sopenharmony_ci	.ndo_set_mac_address 	= eth_mac_addr,
22962306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
23062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
23162306a36Sopenharmony_ci	.ndo_poll_controller 	= ei_poll,
23262306a36Sopenharmony_ci#endif
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int pcnet_probe(struct pcmcia_device *link)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci    struct pcnet_dev *info;
23862306a36Sopenharmony_ci    struct net_device *dev;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci    dev_dbg(&link->dev, "pcnet_attach()\n");
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci    /* Create new ethernet device */
24362306a36Sopenharmony_ci    dev = __alloc_ei_netdev(sizeof(struct pcnet_dev));
24462306a36Sopenharmony_ci    if (!dev) return -ENOMEM;
24562306a36Sopenharmony_ci    info = PRIV(dev);
24662306a36Sopenharmony_ci    info->p_dev = link;
24762306a36Sopenharmony_ci    link->priv = dev;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci    dev->netdev_ops = &pcnet_netdev_ops;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci    return pcnet_config(link);
25462306a36Sopenharmony_ci} /* pcnet_attach */
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic void pcnet_detach(struct pcmcia_device *link)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct net_device *dev = link->priv;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	dev_dbg(&link->dev, "pcnet_detach\n");
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	unregister_netdev(dev);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	pcnet_release(link);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	free_netdev(dev);
26762306a36Sopenharmony_ci} /* pcnet_detach */
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/*======================================================================
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci    This probes for a card's hardware address, for card types that
27262306a36Sopenharmony_ci    encode this information in their CIS.
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci======================================================================*/
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic struct hw_info *get_hwinfo(struct pcmcia_device *link)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci    struct net_device *dev = link->priv;
27962306a36Sopenharmony_ci    u_char __iomem *base, *virt;
28062306a36Sopenharmony_ci    u8 addr[ETH_ALEN];
28162306a36Sopenharmony_ci    int i, j;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci    /* Allocate a small memory window */
28462306a36Sopenharmony_ci    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
28562306a36Sopenharmony_ci    link->resource[2]->start = 0; link->resource[2]->end = 0;
28662306a36Sopenharmony_ci    i = pcmcia_request_window(link, link->resource[2], 0);
28762306a36Sopenharmony_ci    if (i != 0)
28862306a36Sopenharmony_ci	return NULL;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci    virt = ioremap(link->resource[2]->start,
29162306a36Sopenharmony_ci	    resource_size(link->resource[2]));
29262306a36Sopenharmony_ci    if (unlikely(!virt)) {
29362306a36Sopenharmony_ci	    pcmcia_release_window(link, link->resource[2]);
29462306a36Sopenharmony_ci	    return NULL;
29562306a36Sopenharmony_ci    }
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci    for (i = 0; i < NR_INFO; i++) {
29862306a36Sopenharmony_ci	pcmcia_map_mem_page(link, link->resource[2],
29962306a36Sopenharmony_ci		hw_info[i].offset & ~(resource_size(link->resource[2])-1));
30062306a36Sopenharmony_ci	base = &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)];
30162306a36Sopenharmony_ci	if ((readb(base+0) == hw_info[i].a0) &&
30262306a36Sopenharmony_ci	    (readb(base+2) == hw_info[i].a1) &&
30362306a36Sopenharmony_ci	    (readb(base+4) == hw_info[i].a2)) {
30462306a36Sopenharmony_ci		for (j = 0; j < 6; j++)
30562306a36Sopenharmony_ci			addr[j] = readb(base + (j<<1));
30662306a36Sopenharmony_ci		eth_hw_addr_set(dev, addr);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci    }
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci    iounmap(virt);
31262306a36Sopenharmony_ci    j = pcmcia_release_window(link, link->resource[2]);
31362306a36Sopenharmony_ci    return (i < NR_INFO) ? hw_info+i : NULL;
31462306a36Sopenharmony_ci} /* get_hwinfo */
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/*======================================================================
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci    This probes for a card's hardware address by reading the PROM.
31962306a36Sopenharmony_ci    It checks the address against a list of known types, then falls
32062306a36Sopenharmony_ci    back to a simple NE2000 clone signature check.
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci======================================================================*/
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic struct hw_info *get_prom(struct pcmcia_device *link)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci    struct net_device *dev = link->priv;
32762306a36Sopenharmony_ci    unsigned int ioaddr = dev->base_addr;
32862306a36Sopenharmony_ci    u8 addr[ETH_ALEN];
32962306a36Sopenharmony_ci    u_char prom[32];
33062306a36Sopenharmony_ci    int i, j;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci    /* This is lifted straight from drivers/net/ethernet/8390/ne.c */
33362306a36Sopenharmony_ci    struct {
33462306a36Sopenharmony_ci	u_char value, offset;
33562306a36Sopenharmony_ci    } program_seq[] = {
33662306a36Sopenharmony_ci	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
33762306a36Sopenharmony_ci	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
33862306a36Sopenharmony_ci	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
33962306a36Sopenharmony_ci	{0x00,	EN0_RCNTHI},
34062306a36Sopenharmony_ci	{0x00,	EN0_IMR},	/* Mask completion irq. */
34162306a36Sopenharmony_ci	{0xFF,	EN0_ISR},
34262306a36Sopenharmony_ci	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
34362306a36Sopenharmony_ci	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
34462306a36Sopenharmony_ci	{32,	EN0_RCNTLO},
34562306a36Sopenharmony_ci	{0x00,	EN0_RCNTHI},
34662306a36Sopenharmony_ci	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
34762306a36Sopenharmony_ci	{0x00,	EN0_RSARHI},
34862306a36Sopenharmony_ci	{E8390_RREAD+E8390_START, E8390_CMD},
34962306a36Sopenharmony_ci    };
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci    pcnet_reset_8390(dev);
35262306a36Sopenharmony_ci    mdelay(10);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
35562306a36Sopenharmony_ci	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci    for (i = 0; i < 32; i++)
35862306a36Sopenharmony_ci	prom[i] = inb(ioaddr + PCNET_DATAPORT);
35962306a36Sopenharmony_ci    for (i = 0; i < NR_INFO; i++) {
36062306a36Sopenharmony_ci	if ((prom[0] == hw_info[i].a0) &&
36162306a36Sopenharmony_ci	    (prom[2] == hw_info[i].a1) &&
36262306a36Sopenharmony_ci	    (prom[4] == hw_info[i].a2))
36362306a36Sopenharmony_ci	    break;
36462306a36Sopenharmony_ci    }
36562306a36Sopenharmony_ci    if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
36662306a36Sopenharmony_ci	for (j = 0; j < 6; j++)
36762306a36Sopenharmony_ci	    addr[j] = prom[j<<1];
36862306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr);
36962306a36Sopenharmony_ci	return (i < NR_INFO) ? hw_info+i : &default_info;
37062306a36Sopenharmony_ci    }
37162306a36Sopenharmony_ci    return NULL;
37262306a36Sopenharmony_ci} /* get_prom */
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/*======================================================================
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci    For DL10019 based cards, like the Linksys EtherFast
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci======================================================================*/
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic struct hw_info *get_dl10019(struct pcmcia_device *link)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci    struct net_device *dev = link->priv;
38362306a36Sopenharmony_ci    u8 addr[ETH_ALEN];
38462306a36Sopenharmony_ci    int i;
38562306a36Sopenharmony_ci    u_char sum;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci    for (sum = 0, i = 0x14; i < 0x1c; i++)
38862306a36Sopenharmony_ci	sum += inb_p(dev->base_addr + i);
38962306a36Sopenharmony_ci    if (sum != 0xff)
39062306a36Sopenharmony_ci	return NULL;
39162306a36Sopenharmony_ci    for (i = 0; i < 6; i++)
39262306a36Sopenharmony_ci	addr[i] = inb_p(dev->base_addr + 0x14 + i);
39362306a36Sopenharmony_ci    eth_hw_addr_set(dev, addr);
39462306a36Sopenharmony_ci    i = inb(dev->base_addr + 0x1f);
39562306a36Sopenharmony_ci    return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/*======================================================================
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci    For Asix AX88190 based cards
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci======================================================================*/
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic struct hw_info *get_ax88190(struct pcmcia_device *link)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci    struct net_device *dev = link->priv;
40762306a36Sopenharmony_ci    unsigned int ioaddr = dev->base_addr;
40862306a36Sopenharmony_ci    u8 addr[ETH_ALEN];
40962306a36Sopenharmony_ci    int i, j;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci    /* Not much of a test, but the alternatives are messy */
41262306a36Sopenharmony_ci    if (link->config_base != 0x03c0)
41362306a36Sopenharmony_ci	return NULL;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci    outb_p(0x01, ioaddr + EN0_DCFG);	/* Set word-wide access. */
41662306a36Sopenharmony_ci    outb_p(0x00, ioaddr + EN0_RSARLO);	/* DMA starting at 0x0400. */
41762306a36Sopenharmony_ci    outb_p(0x04, ioaddr + EN0_RSARHI);
41862306a36Sopenharmony_ci    outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci    for (i = 0; i < 6; i += 2) {
42162306a36Sopenharmony_ci	j = inw(ioaddr + PCNET_DATAPORT);
42262306a36Sopenharmony_ci	addr[i] = j & 0xff;
42362306a36Sopenharmony_ci	addr[i+1] = j >> 8;
42462306a36Sopenharmony_ci    }
42562306a36Sopenharmony_ci    eth_hw_addr_set(dev, addr);
42662306a36Sopenharmony_ci    return NULL;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/*======================================================================
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci    This should be totally unnecessary... but when we can't figure
43262306a36Sopenharmony_ci    out the hardware address any other way, we'll let the user hard
43362306a36Sopenharmony_ci    wire it when the module is initialized.
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci======================================================================*/
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic struct hw_info *get_hwired(struct pcmcia_device *link)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci    struct net_device *dev = link->priv;
44062306a36Sopenharmony_ci    u8 addr[ETH_ALEN];
44162306a36Sopenharmony_ci    int i;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci    for (i = 0; i < 6; i++)
44462306a36Sopenharmony_ci	if (hw_addr[i] != 0) break;
44562306a36Sopenharmony_ci    if (i == 6)
44662306a36Sopenharmony_ci	return NULL;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci    for (i = 0; i < 6; i++)
44962306a36Sopenharmony_ci	addr[i] = hw_addr[i];
45062306a36Sopenharmony_ci    eth_hw_addr_set(dev, addr);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci    return &default_info;
45362306a36Sopenharmony_ci} /* get_hwired */
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic int try_io_port(struct pcmcia_device *link)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci    int j, ret;
45862306a36Sopenharmony_ci    link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
45962306a36Sopenharmony_ci    link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
46062306a36Sopenharmony_ci    if (link->resource[0]->end == 32) {
46162306a36Sopenharmony_ci	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
46262306a36Sopenharmony_ci	if (link->resource[1]->end > 0) {
46362306a36Sopenharmony_ci	    /* for master/slave multifunction cards */
46462306a36Sopenharmony_ci	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci    } else {
46762306a36Sopenharmony_ci	/* This should be two 16-port windows */
46862306a36Sopenharmony_ci	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
46962306a36Sopenharmony_ci	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
47062306a36Sopenharmony_ci    }
47162306a36Sopenharmony_ci    if (link->resource[0]->start == 0) {
47262306a36Sopenharmony_ci	for (j = 0; j < 0x400; j += 0x20) {
47362306a36Sopenharmony_ci	    link->resource[0]->start = j ^ 0x300;
47462306a36Sopenharmony_ci	    link->resource[1]->start = (j ^ 0x300) + 0x10;
47562306a36Sopenharmony_ci	    link->io_lines = 16;
47662306a36Sopenharmony_ci	    ret = pcmcia_request_io(link);
47762306a36Sopenharmony_ci	    if (ret == 0)
47862306a36Sopenharmony_ci		    return ret;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci	return ret;
48162306a36Sopenharmony_ci    } else {
48262306a36Sopenharmony_ci	return pcmcia_request_io(link);
48362306a36Sopenharmony_ci    }
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int pcnet_confcheck(struct pcmcia_device *p_dev, void *priv_data)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	int *priv = priv_data;
48962306a36Sopenharmony_ci	int try = (*priv & 0x1);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	*priv &= (p_dev->resource[2]->end >= 0x4000) ? 0x10 : ~0x10;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (p_dev->config_index == 0)
49462306a36Sopenharmony_ci		return -EINVAL;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
49762306a36Sopenharmony_ci		return -EINVAL;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (try)
50062306a36Sopenharmony_ci		p_dev->io_lines = 16;
50162306a36Sopenharmony_ci	return try_io_port(p_dev);
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic struct hw_info *pcnet_try_config(struct pcmcia_device *link,
50562306a36Sopenharmony_ci					int *has_shmem, int try)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct net_device *dev = link->priv;
50862306a36Sopenharmony_ci	struct hw_info *local_hw_info;
50962306a36Sopenharmony_ci	struct pcnet_dev *info = PRIV(dev);
51062306a36Sopenharmony_ci	int priv = try;
51162306a36Sopenharmony_ci	int ret;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
51462306a36Sopenharmony_ci	if (ret) {
51562306a36Sopenharmony_ci		dev_warn(&link->dev, "no useable port range found\n");
51662306a36Sopenharmony_ci		return NULL;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	*has_shmem = (priv & 0x10);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (!link->irq)
52162306a36Sopenharmony_ci		return NULL;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (resource_size(link->resource[1]) == 8)
52462306a36Sopenharmony_ci		link->config_flags |= CONF_ENABLE_SPKR;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if ((link->manf_id == MANFID_IBM) &&
52762306a36Sopenharmony_ci	    (link->card_id == PRODID_IBM_HOME_AND_AWAY))
52862306a36Sopenharmony_ci		link->config_index |= 0x10;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	ret = pcmcia_enable_device(link);
53162306a36Sopenharmony_ci	if (ret)
53262306a36Sopenharmony_ci		return NULL;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	dev->irq = link->irq;
53562306a36Sopenharmony_ci	dev->base_addr = link->resource[0]->start;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (info->flags & HAS_MISC_REG) {
53862306a36Sopenharmony_ci		if ((if_port == 1) || (if_port == 2))
53962306a36Sopenharmony_ci			dev->if_port = if_port;
54062306a36Sopenharmony_ci		else
54162306a36Sopenharmony_ci			dev_notice(&link->dev, "invalid if_port requested\n");
54262306a36Sopenharmony_ci	} else
54362306a36Sopenharmony_ci		dev->if_port = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if ((link->config_base == 0x03c0) &&
54662306a36Sopenharmony_ci	    (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
54762306a36Sopenharmony_ci		dev_info(&link->dev,
54862306a36Sopenharmony_ci			"this is an AX88190 card - use axnet_cs instead.\n");
54962306a36Sopenharmony_ci		return NULL;
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	local_hw_info = get_hwinfo(link);
55362306a36Sopenharmony_ci	if (!local_hw_info)
55462306a36Sopenharmony_ci		local_hw_info = get_prom(link);
55562306a36Sopenharmony_ci	if (!local_hw_info)
55662306a36Sopenharmony_ci		local_hw_info = get_dl10019(link);
55762306a36Sopenharmony_ci	if (!local_hw_info)
55862306a36Sopenharmony_ci		local_hw_info = get_ax88190(link);
55962306a36Sopenharmony_ci	if (!local_hw_info)
56062306a36Sopenharmony_ci		local_hw_info = get_hwired(link);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	return local_hw_info;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic int pcnet_config(struct pcmcia_device *link)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci    struct net_device *dev = link->priv;
56862306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
56962306a36Sopenharmony_ci    int start_pg, stop_pg, cm_offset;
57062306a36Sopenharmony_ci    int has_shmem = 0;
57162306a36Sopenharmony_ci    struct hw_info *local_hw_info;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci    dev_dbg(&link->dev, "pcnet_config\n");
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci    local_hw_info = pcnet_try_config(link, &has_shmem, 0);
57662306a36Sopenharmony_ci    if (!local_hw_info) {
57762306a36Sopenharmony_ci	    /* check whether forcing io_lines to 16 helps... */
57862306a36Sopenharmony_ci	    pcmcia_disable_device(link);
57962306a36Sopenharmony_ci	    local_hw_info = pcnet_try_config(link, &has_shmem, 1);
58062306a36Sopenharmony_ci	    if (local_hw_info == NULL) {
58162306a36Sopenharmony_ci		    dev_notice(&link->dev, "unable to read hardware net"
58262306a36Sopenharmony_ci			    " address for io base %#3lx\n", dev->base_addr);
58362306a36Sopenharmony_ci		    goto failed;
58462306a36Sopenharmony_ci	    }
58562306a36Sopenharmony_ci    }
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci    info->flags = local_hw_info->flags;
58862306a36Sopenharmony_ci    /* Check for user overrides */
58962306a36Sopenharmony_ci    info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
59062306a36Sopenharmony_ci    if ((link->manf_id == MANFID_SOCKET) &&
59162306a36Sopenharmony_ci	((link->card_id == PRODID_SOCKET_LPE) ||
59262306a36Sopenharmony_ci	 (link->card_id == PRODID_SOCKET_LPE_CF) ||
59362306a36Sopenharmony_ci	 (link->card_id == PRODID_SOCKET_EIO)))
59462306a36Sopenharmony_ci	info->flags &= ~USE_BIG_BUF;
59562306a36Sopenharmony_ci    if (!use_big_buf)
59662306a36Sopenharmony_ci	info->flags &= ~USE_BIG_BUF;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci    if (info->flags & USE_BIG_BUF) {
59962306a36Sopenharmony_ci	start_pg = SOCKET_START_PG;
60062306a36Sopenharmony_ci	stop_pg = SOCKET_STOP_PG;
60162306a36Sopenharmony_ci	cm_offset = 0x10000;
60262306a36Sopenharmony_ci    } else {
60362306a36Sopenharmony_ci	start_pg = PCNET_START_PG;
60462306a36Sopenharmony_ci	stop_pg = PCNET_STOP_PG;
60562306a36Sopenharmony_ci	cm_offset = 0;
60662306a36Sopenharmony_ci    }
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci    /* has_shmem is ignored if use_shmem != -1 */
60962306a36Sopenharmony_ci    if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
61062306a36Sopenharmony_ci	(setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
61162306a36Sopenharmony_ci	setup_dma_config(link, start_pg, stop_pg);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci    ei_status.name = "NE2000";
61462306a36Sopenharmony_ci    ei_status.word16 = 1;
61562306a36Sopenharmony_ci    ei_status.reset_8390 = pcnet_reset_8390;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci    if (info->flags & (IS_DL10019|IS_DL10022))
61862306a36Sopenharmony_ci	mii_phy_probe(dev);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci    SET_NETDEV_DEV(dev, &link->dev);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci    if (register_netdev(dev) != 0) {
62362306a36Sopenharmony_ci	pr_notice("register_netdev() failed\n");
62462306a36Sopenharmony_ci	goto failed;
62562306a36Sopenharmony_ci    }
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci    if (info->flags & (IS_DL10019|IS_DL10022)) {
62862306a36Sopenharmony_ci	u_char id = inb(dev->base_addr + 0x1a);
62962306a36Sopenharmony_ci	netdev_info(dev, "NE2000 (DL100%d rev %02x): ",
63062306a36Sopenharmony_ci		    (info->flags & IS_DL10022) ? 22 : 19, id);
63162306a36Sopenharmony_ci	if (info->pna_phy)
63262306a36Sopenharmony_ci	    pr_cont("PNA, ");
63362306a36Sopenharmony_ci    } else {
63462306a36Sopenharmony_ci	netdev_info(dev, "NE2000 Compatible: ");
63562306a36Sopenharmony_ci    }
63662306a36Sopenharmony_ci    pr_cont("io %#3lx, irq %d,", dev->base_addr, dev->irq);
63762306a36Sopenharmony_ci    if (info->flags & USE_SHMEM)
63862306a36Sopenharmony_ci	pr_cont(" mem %#5lx,", dev->mem_start);
63962306a36Sopenharmony_ci    if (info->flags & HAS_MISC_REG)
64062306a36Sopenharmony_ci	pr_cont(" %s xcvr,", if_names[dev->if_port]);
64162306a36Sopenharmony_ci    pr_cont(" hw_addr %pM\n", dev->dev_addr);
64262306a36Sopenharmony_ci    return 0;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cifailed:
64562306a36Sopenharmony_ci    pcnet_release(link);
64662306a36Sopenharmony_ci    return -ENODEV;
64762306a36Sopenharmony_ci} /* pcnet_config */
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic void pcnet_release(struct pcmcia_device *link)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct pcnet_dev *info = PRIV(link->priv);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	dev_dbg(&link->dev, "pcnet_release\n");
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (info->flags & USE_SHMEM)
65662306a36Sopenharmony_ci		iounmap(info->base);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	pcmcia_disable_device(link);
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int pcnet_suspend(struct pcmcia_device *link)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct net_device *dev = link->priv;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (link->open)
66662306a36Sopenharmony_ci		netif_device_detach(dev);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int pcnet_resume(struct pcmcia_device *link)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	struct net_device *dev = link->priv;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (link->open) {
67662306a36Sopenharmony_ci		pcnet_reset_8390(dev);
67762306a36Sopenharmony_ci		NS8390_init(dev, 1);
67862306a36Sopenharmony_ci		netif_device_attach(dev);
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return 0;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/*======================================================================
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci    MII interface support for DL10019 and DL10022 based cards
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci    On the DL10019, the MII IO direction bit is 0x10; on the DL10022
69062306a36Sopenharmony_ci    it is 0x20.  Setting both bits seems to work on both card types.
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci======================================================================*/
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci#define DLINK_GPIO		0x1c
69562306a36Sopenharmony_ci#define DLINK_DIAG		0x1d
69662306a36Sopenharmony_ci#define DLINK_EEPROM		0x1e
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci#define MDIO_SHIFT_CLK		0x80
69962306a36Sopenharmony_ci#define MDIO_DATA_OUT		0x40
70062306a36Sopenharmony_ci#define MDIO_DIR_WRITE		0x30
70162306a36Sopenharmony_ci#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
70262306a36Sopenharmony_ci#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
70362306a36Sopenharmony_ci#define MDIO_DATA_READ		0x10
70462306a36Sopenharmony_ci#define MDIO_MASK		0x0f
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic void mdio_sync(unsigned int addr)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci    int bits, mask = inb(addr) & MDIO_MASK;
70962306a36Sopenharmony_ci    for (bits = 0; bits < 32; bits++) {
71062306a36Sopenharmony_ci	outb(mask | MDIO_DATA_WRITE1, addr);
71162306a36Sopenharmony_ci	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
71262306a36Sopenharmony_ci    }
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic int mdio_read(unsigned int addr, int phy_id, int loc)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
71862306a36Sopenharmony_ci    int i, retval = 0, mask = inb(addr) & MDIO_MASK;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci    mdio_sync(addr);
72162306a36Sopenharmony_ci    for (i = 13; i >= 0; i--) {
72262306a36Sopenharmony_ci	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
72362306a36Sopenharmony_ci	outb(mask | dat, addr);
72462306a36Sopenharmony_ci	outb(mask | dat | MDIO_SHIFT_CLK, addr);
72562306a36Sopenharmony_ci    }
72662306a36Sopenharmony_ci    for (i = 19; i > 0; i--) {
72762306a36Sopenharmony_ci	outb(mask, addr);
72862306a36Sopenharmony_ci	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
72962306a36Sopenharmony_ci	outb(mask | MDIO_SHIFT_CLK, addr);
73062306a36Sopenharmony_ci    }
73162306a36Sopenharmony_ci    return (retval>>1) & 0xffff;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic void mdio_write(unsigned int addr, int phy_id, int loc, int value)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
73762306a36Sopenharmony_ci    int i, mask = inb(addr) & MDIO_MASK;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci    mdio_sync(addr);
74062306a36Sopenharmony_ci    for (i = 31; i >= 0; i--) {
74162306a36Sopenharmony_ci	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
74262306a36Sopenharmony_ci	outb(mask | dat, addr);
74362306a36Sopenharmony_ci	outb(mask | dat | MDIO_SHIFT_CLK, addr);
74462306a36Sopenharmony_ci    }
74562306a36Sopenharmony_ci    for (i = 1; i >= 0; i--) {
74662306a36Sopenharmony_ci	outb(mask, addr);
74762306a36Sopenharmony_ci	outb(mask | MDIO_SHIFT_CLK, addr);
74862306a36Sopenharmony_ci    }
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci/*======================================================================
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci    EEPROM access routines for DL10019 and DL10022 based cards
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci======================================================================*/
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci#define EE_EEP		0x40
75862306a36Sopenharmony_ci#define EE_ASIC		0x10
75962306a36Sopenharmony_ci#define EE_CS		0x08
76062306a36Sopenharmony_ci#define EE_CK		0x04
76162306a36Sopenharmony_ci#define EE_DO		0x02
76262306a36Sopenharmony_ci#define EE_DI		0x01
76362306a36Sopenharmony_ci#define EE_ADOT		0x01	/* DataOut for ASIC */
76462306a36Sopenharmony_ci#define EE_READ_CMD	0x06
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci#define DL19FDUPLX	0x0400	/* DL10019 Full duplex mode */
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int read_eeprom(unsigned int ioaddr, int location)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci    int i, retval = 0;
77162306a36Sopenharmony_ci    unsigned int ee_addr = ioaddr + DLINK_EEPROM;
77262306a36Sopenharmony_ci    int read_cmd = location | (EE_READ_CMD << 8);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci    outb(0, ee_addr);
77562306a36Sopenharmony_ci    outb(EE_EEP|EE_CS, ee_addr);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci    /* Shift the read command bits out. */
77862306a36Sopenharmony_ci    for (i = 10; i >= 0; i--) {
77962306a36Sopenharmony_ci	short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
78062306a36Sopenharmony_ci	outb_p(EE_EEP|EE_CS|dataval, ee_addr);
78162306a36Sopenharmony_ci	outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);
78262306a36Sopenharmony_ci    }
78362306a36Sopenharmony_ci    outb(EE_EEP|EE_CS, ee_addr);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci    for (i = 16; i > 0; i--) {
78662306a36Sopenharmony_ci	outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);
78762306a36Sopenharmony_ci	retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);
78862306a36Sopenharmony_ci	outb_p(EE_EEP|EE_CS, ee_addr);
78962306a36Sopenharmony_ci    }
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci    /* Terminate the EEPROM access. */
79262306a36Sopenharmony_ci    outb(0, ee_addr);
79362306a36Sopenharmony_ci    return retval;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci/*
79762306a36Sopenharmony_ci    The internal ASIC registers can be changed by EEPROM READ access
79862306a36Sopenharmony_ci    with EE_ASIC bit set.
79962306a36Sopenharmony_ci    In ASIC mode, EE_ADOT is used to output the data to the ASIC.
80062306a36Sopenharmony_ci*/
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic void write_asic(unsigned int ioaddr, int location, short asic_data)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	int i;
80562306a36Sopenharmony_ci	unsigned int ee_addr = ioaddr + DLINK_EEPROM;
80662306a36Sopenharmony_ci	short dataval;
80762306a36Sopenharmony_ci	int read_cmd = location | (EE_READ_CMD << 8);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	asic_data |= read_eeprom(ioaddr, location);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	outb(0, ee_addr);
81262306a36Sopenharmony_ci	outb(EE_ASIC|EE_CS|EE_DI, ee_addr);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	read_cmd = read_cmd >> 1;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	/* Shift the read command bits out. */
81762306a36Sopenharmony_ci	for (i = 9; i >= 0; i--) {
81862306a36Sopenharmony_ci		dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
81962306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
82062306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);
82162306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci	// sync
82462306a36Sopenharmony_ci	outb(EE_ASIC|EE_CS, ee_addr);
82562306a36Sopenharmony_ci	outb(EE_ASIC|EE_CS|EE_CK, ee_addr);
82662306a36Sopenharmony_ci	outb(EE_ASIC|EE_CS, ee_addr);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	for (i = 15; i >= 0; i--) {
82962306a36Sopenharmony_ci		dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;
83062306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
83162306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);
83262306a36Sopenharmony_ci		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	/* Terminate the ASIC access. */
83662306a36Sopenharmony_ci	outb(EE_ASIC|EE_DI, ee_addr);
83762306a36Sopenharmony_ci	outb(EE_ASIC|EE_DI| EE_CK, ee_addr);
83862306a36Sopenharmony_ci	outb(EE_ASIC|EE_DI, ee_addr);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	outb(0, ee_addr);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/*====================================================================*/
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void set_misc_reg(struct net_device *dev)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
84862306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
84962306a36Sopenharmony_ci    u_char tmp;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci    if (info->flags & HAS_MISC_REG) {
85262306a36Sopenharmony_ci	tmp = inb_p(nic_base + PCNET_MISC) & ~3;
85362306a36Sopenharmony_ci	if (dev->if_port == 2)
85462306a36Sopenharmony_ci	    tmp |= 1;
85562306a36Sopenharmony_ci	if (info->flags & USE_BIG_BUF)
85662306a36Sopenharmony_ci	    tmp |= 2;
85762306a36Sopenharmony_ci	if (info->flags & HAS_IBM_MISC)
85862306a36Sopenharmony_ci	    tmp |= 8;
85962306a36Sopenharmony_ci	outb_p(tmp, nic_base + PCNET_MISC);
86062306a36Sopenharmony_ci    }
86162306a36Sopenharmony_ci    if (info->flags & IS_DL10022) {
86262306a36Sopenharmony_ci	if (info->flags & HAS_MII) {
86362306a36Sopenharmony_ci	    /* Advertise 100F, 100H, 10F, 10H */
86462306a36Sopenharmony_ci	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
86562306a36Sopenharmony_ci	    /* Restart MII autonegotiation */
86662306a36Sopenharmony_ci	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
86762306a36Sopenharmony_ci	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
86862306a36Sopenharmony_ci	    info->mii_reset = jiffies;
86962306a36Sopenharmony_ci	} else {
87062306a36Sopenharmony_ci	    outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci    } else if (info->flags & IS_DL10019) {
87362306a36Sopenharmony_ci	/* Advertise 100F, 100H, 10F, 10H */
87462306a36Sopenharmony_ci	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
87562306a36Sopenharmony_ci	/* Restart MII autonegotiation */
87662306a36Sopenharmony_ci	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
87762306a36Sopenharmony_ci	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
87862306a36Sopenharmony_ci    }
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci/*====================================================================*/
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic void mii_phy_probe(struct net_device *dev)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
88662306a36Sopenharmony_ci    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
88762306a36Sopenharmony_ci    int i;
88862306a36Sopenharmony_ci    u_int tmp, phyid;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci    for (i = 31; i >= 0; i--) {
89162306a36Sopenharmony_ci	tmp = mdio_read(mii_addr, i, 1);
89262306a36Sopenharmony_ci	if ((tmp == 0) || (tmp == 0xffff))
89362306a36Sopenharmony_ci	    continue;
89462306a36Sopenharmony_ci	tmp = mdio_read(mii_addr, i, MII_PHYID_REG1);
89562306a36Sopenharmony_ci	phyid = tmp << 16;
89662306a36Sopenharmony_ci	phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
89762306a36Sopenharmony_ci	phyid &= MII_PHYID_REV_MASK;
89862306a36Sopenharmony_ci	netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid);
89962306a36Sopenharmony_ci	if (phyid == AM79C9XX_HOME_PHY) {
90062306a36Sopenharmony_ci	    info->pna_phy = i;
90162306a36Sopenharmony_ci	} else if (phyid != AM79C9XX_ETH_PHY) {
90262306a36Sopenharmony_ci	    info->eth_phy = i;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci    }
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int pcnet_open(struct net_device *dev)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci    int ret;
91062306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
91162306a36Sopenharmony_ci    struct pcmcia_device *link = info->p_dev;
91262306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci    dev_dbg(&link->dev, "pcnet_open('%s')\n", dev->name);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci    if (!pcmcia_dev_present(link))
91762306a36Sopenharmony_ci	return -ENODEV;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci    set_misc_reg(dev);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
92262306a36Sopenharmony_ci    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev->name, dev);
92362306a36Sopenharmony_ci    if (ret)
92462306a36Sopenharmony_ci	    return ret;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci    link->open++;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci    info->phy_id = info->eth_phy;
92962306a36Sopenharmony_ci    info->link_status = 0x00;
93062306a36Sopenharmony_ci    timer_setup(&info->watchdog, ei_watchdog, 0);
93162306a36Sopenharmony_ci    mod_timer(&info->watchdog, jiffies + HZ);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci    return ei_open(dev);
93462306a36Sopenharmony_ci} /* pcnet_open */
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci/*====================================================================*/
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int pcnet_close(struct net_device *dev)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
94162306a36Sopenharmony_ci    struct pcmcia_device *link = info->p_dev;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci    dev_dbg(&link->dev, "pcnet_close('%s')\n", dev->name);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci    ei_close(dev);
94662306a36Sopenharmony_ci    free_irq(dev->irq, dev);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci    link->open--;
94962306a36Sopenharmony_ci    netif_stop_queue(dev);
95062306a36Sopenharmony_ci    del_timer_sync(&info->watchdog);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci    return 0;
95362306a36Sopenharmony_ci} /* pcnet_close */
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/*======================================================================
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci    Hard reset the card.  This used to pause for the same period that
95862306a36Sopenharmony_ci    a 8390 reset command required, but that shouldn't be necessary.
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci======================================================================*/
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic void pcnet_reset_8390(struct net_device *dev)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
96562306a36Sopenharmony_ci    int i;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci    ei_status.txing = ei_status.dmaing = 0;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci    for (i = 0; i < 100; i++) {
97462306a36Sopenharmony_ci	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
97562306a36Sopenharmony_ci	    break;
97662306a36Sopenharmony_ci	udelay(100);
97762306a36Sopenharmony_ci    }
97862306a36Sopenharmony_ci    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci    if (i == 100)
98162306a36Sopenharmony_ci	netdev_err(dev, "pcnet_reset_8390() did not complete.\n");
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci    set_misc_reg(dev);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci} /* pcnet_reset_8390 */
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci/*====================================================================*/
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic int set_config(struct net_device *dev, struct ifmap *map)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
99262306a36Sopenharmony_ci    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
99362306a36Sopenharmony_ci	if (!(info->flags & HAS_MISC_REG))
99462306a36Sopenharmony_ci	    return -EOPNOTSUPP;
99562306a36Sopenharmony_ci	else if ((map->port < 1) || (map->port > 2))
99662306a36Sopenharmony_ci	    return -EINVAL;
99762306a36Sopenharmony_ci	dev->if_port = map->port;
99862306a36Sopenharmony_ci	netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
99962306a36Sopenharmony_ci	NS8390_init(dev, 1);
100062306a36Sopenharmony_ci    }
100162306a36Sopenharmony_ci    return 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci/*====================================================================*/
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci    struct net_device *dev = dev_id;
100962306a36Sopenharmony_ci    struct pcnet_dev *info;
101062306a36Sopenharmony_ci    irqreturn_t ret = ei_interrupt(irq, dev_id);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci    if (ret == IRQ_HANDLED) {
101362306a36Sopenharmony_ci	    info = PRIV(dev);
101462306a36Sopenharmony_ci	    info->stale = 0;
101562306a36Sopenharmony_ci    }
101662306a36Sopenharmony_ci    return ret;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic void ei_watchdog(struct timer_list *t)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci    struct pcnet_dev *info = from_timer(info, t, watchdog);
102262306a36Sopenharmony_ci    struct net_device *dev = info->p_dev->priv;
102362306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
102462306a36Sopenharmony_ci    unsigned int mii_addr = nic_base + DLINK_GPIO;
102562306a36Sopenharmony_ci    u_short link;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci    if (!netif_device_present(dev)) goto reschedule;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci    /* Check for pending interrupt with expired latency timer: with
103062306a36Sopenharmony_ci       this, we can limp along even if the interrupt is blocked */
103162306a36Sopenharmony_ci    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
103262306a36Sopenharmony_ci	if (!info->fast_poll)
103362306a36Sopenharmony_ci	    netdev_info(dev, "interrupt(s) dropped!\n");
103462306a36Sopenharmony_ci	ei_irq_wrapper(dev->irq, dev);
103562306a36Sopenharmony_ci	info->fast_poll = HZ;
103662306a36Sopenharmony_ci    }
103762306a36Sopenharmony_ci    if (info->fast_poll) {
103862306a36Sopenharmony_ci	info->fast_poll--;
103962306a36Sopenharmony_ci	info->watchdog.expires = jiffies + 1;
104062306a36Sopenharmony_ci	add_timer(&info->watchdog);
104162306a36Sopenharmony_ci	return;
104262306a36Sopenharmony_ci    }
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci    if (!(info->flags & HAS_MII))
104562306a36Sopenharmony_ci	goto reschedule;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci    mdio_read(mii_addr, info->phy_id, 1);
104862306a36Sopenharmony_ci    link = mdio_read(mii_addr, info->phy_id, 1);
104962306a36Sopenharmony_ci    if (!link || (link == 0xffff)) {
105062306a36Sopenharmony_ci	if (info->eth_phy) {
105162306a36Sopenharmony_ci	    info->phy_id = info->eth_phy = 0;
105262306a36Sopenharmony_ci	} else {
105362306a36Sopenharmony_ci	    netdev_info(dev, "MII is missing!\n");
105462306a36Sopenharmony_ci	    info->flags &= ~HAS_MII;
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci	goto reschedule;
105762306a36Sopenharmony_ci    }
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci    link &= 0x0004;
106062306a36Sopenharmony_ci    if (link != info->link_status) {
106162306a36Sopenharmony_ci	u_short p = mdio_read(mii_addr, info->phy_id, 5);
106262306a36Sopenharmony_ci	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
106362306a36Sopenharmony_ci	if (link && (info->flags & IS_DL10022)) {
106462306a36Sopenharmony_ci	    /* Disable collision detection on full duplex links */
106562306a36Sopenharmony_ci	    outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
106662306a36Sopenharmony_ci	} else if (link && (info->flags & IS_DL10019)) {
106762306a36Sopenharmony_ci	    /* Disable collision detection on full duplex links */
106862306a36Sopenharmony_ci	    write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci	if (link) {
107162306a36Sopenharmony_ci	    if (info->phy_id == info->eth_phy) {
107262306a36Sopenharmony_ci		if (p)
107362306a36Sopenharmony_ci		    netdev_info(dev, "autonegotiation complete: "
107462306a36Sopenharmony_ci				"%sbaseT-%cD selected\n",
107562306a36Sopenharmony_ci				((p & 0x0180) ? "100" : "10"),
107662306a36Sopenharmony_ci				((p & 0x0140) ? 'F' : 'H'));
107762306a36Sopenharmony_ci		else
107862306a36Sopenharmony_ci		    netdev_info(dev, "link partner did not autonegotiate\n");
107962306a36Sopenharmony_ci	    }
108062306a36Sopenharmony_ci	    NS8390_init(dev, 1);
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci	info->link_status = link;
108362306a36Sopenharmony_ci    }
108462306a36Sopenharmony_ci    if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) {
108562306a36Sopenharmony_ci	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
108662306a36Sopenharmony_ci	if (((info->phy_id == info->pna_phy) && link) ||
108762306a36Sopenharmony_ci	    ((info->phy_id != info->pna_phy) && !link)) {
108862306a36Sopenharmony_ci	    /* isolate this MII and try flipping to the other one */
108962306a36Sopenharmony_ci	    mdio_write(mii_addr, info->phy_id, 0, 0x0400);
109062306a36Sopenharmony_ci	    info->phy_id ^= info->pna_phy ^ info->eth_phy;
109162306a36Sopenharmony_ci	    netdev_info(dev, "switched to %s transceiver\n",
109262306a36Sopenharmony_ci			(info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
109362306a36Sopenharmony_ci	    mdio_write(mii_addr, info->phy_id, 0,
109462306a36Sopenharmony_ci		       (info->phy_id == info->eth_phy) ? 0x1000 : 0);
109562306a36Sopenharmony_ci	    info->link_status = 0;
109662306a36Sopenharmony_ci	    info->mii_reset = jiffies;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci    }
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cireschedule:
110162306a36Sopenharmony_ci    info->watchdog.expires = jiffies + HZ;
110262306a36Sopenharmony_ci    add_timer(&info->watchdog);
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci/*====================================================================*/
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_cistatic int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
111162306a36Sopenharmony_ci    struct mii_ioctl_data *data = if_mii(rq);
111262306a36Sopenharmony_ci    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci    if (!(info->flags & (IS_DL10019|IS_DL10022)))
111562306a36Sopenharmony_ci	return -EINVAL;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci    switch (cmd) {
111862306a36Sopenharmony_ci    case SIOCGMIIPHY:
111962306a36Sopenharmony_ci	data->phy_id = info->phy_id;
112062306a36Sopenharmony_ci	fallthrough;
112162306a36Sopenharmony_ci    case SIOCGMIIREG:		/* Read MII PHY register. */
112262306a36Sopenharmony_ci	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
112362306a36Sopenharmony_ci	return 0;
112462306a36Sopenharmony_ci    case SIOCSMIIREG:		/* Write MII PHY register. */
112562306a36Sopenharmony_ci	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
112662306a36Sopenharmony_ci	return 0;
112762306a36Sopenharmony_ci    }
112862306a36Sopenharmony_ci    return -EOPNOTSUPP;
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci/*====================================================================*/
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic void dma_get_8390_hdr(struct net_device *dev,
113462306a36Sopenharmony_ci			     struct e8390_pkt_hdr *hdr,
113562306a36Sopenharmony_ci			     int ring_page)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci    if (ei_status.dmaing) {
114062306a36Sopenharmony_ci	netdev_err(dev, "DMAing conflict in dma_block_input."
114162306a36Sopenharmony_ci		   "[DMAstat:%1x][irqlock:%1x]\n",
114262306a36Sopenharmony_ci		   ei_status.dmaing, ei_status.irqlock);
114362306a36Sopenharmony_ci	return;
114462306a36Sopenharmony_ci    }
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci    ei_status.dmaing |= 0x01;
114762306a36Sopenharmony_ci    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
114862306a36Sopenharmony_ci    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
114962306a36Sopenharmony_ci    outb_p(0, nic_base + EN0_RCNTHI);
115062306a36Sopenharmony_ci    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
115162306a36Sopenharmony_ci    outb_p(ring_page, nic_base + EN0_RSARHI);
115262306a36Sopenharmony_ci    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci    insw(nic_base + PCNET_DATAPORT, hdr,
115562306a36Sopenharmony_ci	    sizeof(struct e8390_pkt_hdr)>>1);
115662306a36Sopenharmony_ci    /* Fix for big endian systems */
115762306a36Sopenharmony_ci    hdr->count = le16_to_cpu(hdr->count);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
116062306a36Sopenharmony_ci    ei_status.dmaing &= ~0x01;
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci/*====================================================================*/
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic void dma_block_input(struct net_device *dev, int count,
116662306a36Sopenharmony_ci			    struct sk_buff *skb, int ring_offset)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
116962306a36Sopenharmony_ci    int xfer_count = count;
117062306a36Sopenharmony_ci    char *buf = skb->data;
117162306a36Sopenharmony_ci    struct ei_device *ei_local = netdev_priv(dev);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci    if ((netif_msg_rx_status(ei_local)) && (count != 4))
117462306a36Sopenharmony_ci	netdev_dbg(dev, "[bi=%d]\n", count+4);
117562306a36Sopenharmony_ci    if (ei_status.dmaing) {
117662306a36Sopenharmony_ci	netdev_err(dev, "DMAing conflict in dma_block_input."
117762306a36Sopenharmony_ci		   "[DMAstat:%1x][irqlock:%1x]\n",
117862306a36Sopenharmony_ci		   ei_status.dmaing, ei_status.irqlock);
117962306a36Sopenharmony_ci	return;
118062306a36Sopenharmony_ci    }
118162306a36Sopenharmony_ci    ei_status.dmaing |= 0x01;
118262306a36Sopenharmony_ci    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
118362306a36Sopenharmony_ci    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
118462306a36Sopenharmony_ci    outb_p(count >> 8, nic_base + EN0_RCNTHI);
118562306a36Sopenharmony_ci    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
118662306a36Sopenharmony_ci    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
118762306a36Sopenharmony_ci    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci    insw(nic_base + PCNET_DATAPORT,buf,count>>1);
119062306a36Sopenharmony_ci    if (count & 0x01) {
119162306a36Sopenharmony_ci	buf[count-1] = inb(nic_base + PCNET_DATAPORT);
119262306a36Sopenharmony_ci	xfer_count++;
119362306a36Sopenharmony_ci    }
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci    /* This was for the ALPHA version only, but enough people have been
119662306a36Sopenharmony_ci       encountering problems that it is still here. */
119762306a36Sopenharmony_ci#ifdef PCMCIA_DEBUG
119862306a36Sopenharmony_ci      /* DMA termination address check... */
119962306a36Sopenharmony_ci    if (netif_msg_rx_status(ei_local)) {
120062306a36Sopenharmony_ci	int addr, tries = 20;
120162306a36Sopenharmony_ci	do {
120262306a36Sopenharmony_ci	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
120362306a36Sopenharmony_ci	       -- it's broken for Rx on some cards! */
120462306a36Sopenharmony_ci	    int high = inb_p(nic_base + EN0_RSARHI);
120562306a36Sopenharmony_ci	    int low = inb_p(nic_base + EN0_RSARLO);
120662306a36Sopenharmony_ci	    addr = (high << 8) + low;
120762306a36Sopenharmony_ci	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
120862306a36Sopenharmony_ci		break;
120962306a36Sopenharmony_ci	} while (--tries > 0);
121062306a36Sopenharmony_ci	if (tries <= 0)
121162306a36Sopenharmony_ci	    netdev_notice(dev, "RX transfer address mismatch,"
121262306a36Sopenharmony_ci			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
121362306a36Sopenharmony_ci			  ring_offset + xfer_count, addr);
121462306a36Sopenharmony_ci    }
121562306a36Sopenharmony_ci#endif
121662306a36Sopenharmony_ci    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
121762306a36Sopenharmony_ci    ei_status.dmaing &= ~0x01;
121862306a36Sopenharmony_ci} /* dma_block_input */
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci/*====================================================================*/
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic void dma_block_output(struct net_device *dev, int count,
122362306a36Sopenharmony_ci			     const u_char *buf, const int start_page)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci    unsigned int nic_base = dev->base_addr;
122662306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
122762306a36Sopenharmony_ci#ifdef PCMCIA_DEBUG
122862306a36Sopenharmony_ci    int retries = 0;
122962306a36Sopenharmony_ci    struct ei_device *ei_local = netdev_priv(dev);
123062306a36Sopenharmony_ci#endif
123162306a36Sopenharmony_ci    u_long dma_start;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci#ifdef PCMCIA_DEBUG
123462306a36Sopenharmony_ci    netif_dbg(ei_local, tx_queued, dev, "[bo=%d]\n", count);
123562306a36Sopenharmony_ci#endif
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci    /* Round the count up for word writes.  Do we need to do this?
123862306a36Sopenharmony_ci       What effect will an odd byte count have on the 8390?
123962306a36Sopenharmony_ci       I should check someday. */
124062306a36Sopenharmony_ci    if (count & 0x01)
124162306a36Sopenharmony_ci	count++;
124262306a36Sopenharmony_ci    if (ei_status.dmaing) {
124362306a36Sopenharmony_ci	netdev_err(dev, "DMAing conflict in dma_block_output."
124462306a36Sopenharmony_ci		   "[DMAstat:%1x][irqlock:%1x]\n",
124562306a36Sopenharmony_ci		   ei_status.dmaing, ei_status.irqlock);
124662306a36Sopenharmony_ci	return;
124762306a36Sopenharmony_ci    }
124862306a36Sopenharmony_ci    ei_status.dmaing |= 0x01;
124962306a36Sopenharmony_ci    /* We should already be in page 0, but to be safe... */
125062306a36Sopenharmony_ci    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci#ifdef PCMCIA_DEBUG
125362306a36Sopenharmony_ci  retry:
125462306a36Sopenharmony_ci#endif
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci    outb_p(ENISR_RDC, nic_base + EN0_ISR);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci    /* Now the normal output. */
125962306a36Sopenharmony_ci    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
126062306a36Sopenharmony_ci    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
126162306a36Sopenharmony_ci    outb_p(0x00, nic_base + EN0_RSARLO);
126262306a36Sopenharmony_ci    outb_p(start_page, nic_base + EN0_RSARHI);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
126562306a36Sopenharmony_ci    outsw(nic_base + PCNET_DATAPORT, buf, count>>1);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci    dma_start = jiffies;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci#ifdef PCMCIA_DEBUG
127062306a36Sopenharmony_ci    /* This was for the ALPHA version only, but enough people have been
127162306a36Sopenharmony_ci       encountering problems that it is still here. */
127262306a36Sopenharmony_ci    /* DMA termination address check... */
127362306a36Sopenharmony_ci    if (netif_msg_tx_queued(ei_local)) {
127462306a36Sopenharmony_ci	int addr, tries = 20;
127562306a36Sopenharmony_ci	do {
127662306a36Sopenharmony_ci	    int high = inb_p(nic_base + EN0_RSARHI);
127762306a36Sopenharmony_ci	    int low = inb_p(nic_base + EN0_RSARLO);
127862306a36Sopenharmony_ci	    addr = (high << 8) + low;
127962306a36Sopenharmony_ci	    if ((start_page << 8) + count == addr)
128062306a36Sopenharmony_ci		break;
128162306a36Sopenharmony_ci	} while (--tries > 0);
128262306a36Sopenharmony_ci	if (tries <= 0) {
128362306a36Sopenharmony_ci	    netdev_notice(dev, "Tx packet transfer address mismatch,"
128462306a36Sopenharmony_ci			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
128562306a36Sopenharmony_ci			  (start_page << 8) + count, addr);
128662306a36Sopenharmony_ci	    if (retries++ == 0)
128762306a36Sopenharmony_ci		goto retry;
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci    }
129062306a36Sopenharmony_ci#endif
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
129362306a36Sopenharmony_ci	if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
129462306a36Sopenharmony_ci		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
129562306a36Sopenharmony_ci		pcnet_reset_8390(dev);
129662306a36Sopenharmony_ci		NS8390_init(dev, 1);
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
130162306a36Sopenharmony_ci    if (info->flags & DELAY_OUTPUT)
130262306a36Sopenharmony_ci	udelay((long)delay_time);
130362306a36Sopenharmony_ci    ei_status.dmaing &= ~0x01;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci/*====================================================================*/
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int setup_dma_config(struct pcmcia_device *link, int start_pg,
130962306a36Sopenharmony_ci			    int stop_pg)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci    struct net_device *dev = link->priv;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci    ei_status.tx_start_page = start_pg;
131462306a36Sopenharmony_ci    ei_status.rx_start_page = start_pg + TX_PAGES;
131562306a36Sopenharmony_ci    ei_status.stop_page = stop_pg;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci    /* set up block i/o functions */
131862306a36Sopenharmony_ci    ei_status.get_8390_hdr = dma_get_8390_hdr;
131962306a36Sopenharmony_ci    ei_status.block_input = dma_block_input;
132062306a36Sopenharmony_ci    ei_status.block_output = dma_block_output;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci    return 0;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/*====================================================================*/
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic void copyin(void *dest, void __iomem *src, int c)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci    u_short *d = dest;
133062306a36Sopenharmony_ci    u_short __iomem *s = src;
133162306a36Sopenharmony_ci    int odd;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci    if (c <= 0)
133462306a36Sopenharmony_ci	return;
133562306a36Sopenharmony_ci    odd = (c & 1); c >>= 1;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci    if (c) {
133862306a36Sopenharmony_ci	do { *d++ = __raw_readw(s++); } while (--c);
133962306a36Sopenharmony_ci    }
134062306a36Sopenharmony_ci    /* get last byte by fetching a word and masking */
134162306a36Sopenharmony_ci    if (odd)
134262306a36Sopenharmony_ci	*((u_char *)d) = readw(s) & 0xff;
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic void copyout(void __iomem *dest, const void *src, int c)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci    u_short __iomem *d = dest;
134862306a36Sopenharmony_ci    const u_short *s = src;
134962306a36Sopenharmony_ci    int odd;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci    if (c <= 0)
135262306a36Sopenharmony_ci	return;
135362306a36Sopenharmony_ci    odd = (c & 1); c >>= 1;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci    if (c) {
135662306a36Sopenharmony_ci	do { __raw_writew(*s++, d++); } while (--c);
135762306a36Sopenharmony_ci    }
135862306a36Sopenharmony_ci    /* copy last byte doing a read-modify-write */
135962306a36Sopenharmony_ci    if (odd)
136062306a36Sopenharmony_ci	writew((readw(d) & 0xff00) | *(u_char *)s, d);
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci/*====================================================================*/
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic void shmem_get_8390_hdr(struct net_device *dev,
136662306a36Sopenharmony_ci			       struct e8390_pkt_hdr *hdr,
136762306a36Sopenharmony_ci			       int ring_page)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci    void __iomem *xfer_start = ei_status.mem + (TX_PAGES<<8)
137062306a36Sopenharmony_ci				+ (ring_page << 8)
137162306a36Sopenharmony_ci				- (ei_status.rx_start_page << 8);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci    copyin(hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
137462306a36Sopenharmony_ci    /* Fix for big endian systems */
137562306a36Sopenharmony_ci    hdr->count = le16_to_cpu(hdr->count);
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci/*====================================================================*/
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic void shmem_block_input(struct net_device *dev, int count,
138162306a36Sopenharmony_ci			      struct sk_buff *skb, int ring_offset)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci    void __iomem *base = ei_status.mem;
138462306a36Sopenharmony_ci    unsigned long offset = (TX_PAGES<<8) + ring_offset
138562306a36Sopenharmony_ci				- (ei_status.rx_start_page << 8);
138662306a36Sopenharmony_ci    char *buf = skb->data;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci    if (offset + count > ei_status.priv) {
138962306a36Sopenharmony_ci	/* We must wrap the input move. */
139062306a36Sopenharmony_ci	int semi_count = ei_status.priv - offset;
139162306a36Sopenharmony_ci	copyin(buf, base + offset, semi_count);
139262306a36Sopenharmony_ci	buf += semi_count;
139362306a36Sopenharmony_ci	offset = TX_PAGES<<8;
139462306a36Sopenharmony_ci	count -= semi_count;
139562306a36Sopenharmony_ci    }
139662306a36Sopenharmony_ci    copyin(buf, base + offset, count);
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci/*====================================================================*/
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic void shmem_block_output(struct net_device *dev, int count,
140262306a36Sopenharmony_ci			       const u_char *buf, const int start_page)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci    void __iomem *shmem = ei_status.mem + (start_page << 8);
140562306a36Sopenharmony_ci    shmem -= ei_status.tx_start_page << 8;
140662306a36Sopenharmony_ci    copyout(shmem, buf, count);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci/*====================================================================*/
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic int setup_shmem_window(struct pcmcia_device *link, int start_pg,
141262306a36Sopenharmony_ci			      int stop_pg, int cm_offset)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci    struct net_device *dev = link->priv;
141562306a36Sopenharmony_ci    struct pcnet_dev *info = PRIV(dev);
141662306a36Sopenharmony_ci    int i, window_size, offset, ret;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci    window_size = (stop_pg - start_pg) << 8;
141962306a36Sopenharmony_ci    if (window_size > 32 * 1024)
142062306a36Sopenharmony_ci	window_size = 32 * 1024;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci    /* Make sure it's a power of two.  */
142362306a36Sopenharmony_ci    window_size = roundup_pow_of_two(window_size);
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci    /* Allocate a memory window */
142662306a36Sopenharmony_ci    link->resource[3]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
142762306a36Sopenharmony_ci    link->resource[3]->flags |= WIN_USE_WAIT;
142862306a36Sopenharmony_ci    link->resource[3]->start = 0; link->resource[3]->end = window_size;
142962306a36Sopenharmony_ci    ret = pcmcia_request_window(link, link->resource[3], mem_speed);
143062306a36Sopenharmony_ci    if (ret)
143162306a36Sopenharmony_ci	    goto failed;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci    offset = (start_pg << 8) + cm_offset;
143462306a36Sopenharmony_ci    offset -= offset % window_size;
143562306a36Sopenharmony_ci    ret = pcmcia_map_mem_page(link, link->resource[3], offset);
143662306a36Sopenharmony_ci    if (ret)
143762306a36Sopenharmony_ci	    goto failed;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci    /* Try scribbling on the buffer */
144062306a36Sopenharmony_ci    info->base = ioremap(link->resource[3]->start,
144162306a36Sopenharmony_ci			resource_size(link->resource[3]));
144262306a36Sopenharmony_ci    if (unlikely(!info->base)) {
144362306a36Sopenharmony_ci	    ret = -ENOMEM;
144462306a36Sopenharmony_ci	    goto failed;
144562306a36Sopenharmony_ci    }
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci    for (i = 0; i < (TX_PAGES<<8); i += 2)
144862306a36Sopenharmony_ci	__raw_writew((i>>1), info->base+offset+i);
144962306a36Sopenharmony_ci    udelay(100);
145062306a36Sopenharmony_ci    for (i = 0; i < (TX_PAGES<<8); i += 2)
145162306a36Sopenharmony_ci	if (__raw_readw(info->base+offset+i) != (i>>1)) break;
145262306a36Sopenharmony_ci    pcnet_reset_8390(dev);
145362306a36Sopenharmony_ci    if (i != (TX_PAGES<<8)) {
145462306a36Sopenharmony_ci	iounmap(info->base);
145562306a36Sopenharmony_ci	pcmcia_release_window(link, link->resource[3]);
145662306a36Sopenharmony_ci	info->base = NULL;
145762306a36Sopenharmony_ci	goto failed;
145862306a36Sopenharmony_ci    }
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci    ei_status.mem = info->base + offset;
146162306a36Sopenharmony_ci    ei_status.priv = resource_size(link->resource[3]);
146262306a36Sopenharmony_ci    dev->mem_start = (u_long)ei_status.mem;
146362306a36Sopenharmony_ci    dev->mem_end = dev->mem_start + resource_size(link->resource[3]);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci    ei_status.tx_start_page = start_pg;
146662306a36Sopenharmony_ci    ei_status.rx_start_page = start_pg + TX_PAGES;
146762306a36Sopenharmony_ci    ei_status.stop_page = start_pg + (
146862306a36Sopenharmony_ci	    (resource_size(link->resource[3]) - offset) >> 8);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci    /* set up block i/o functions */
147162306a36Sopenharmony_ci    ei_status.get_8390_hdr = shmem_get_8390_hdr;
147262306a36Sopenharmony_ci    ei_status.block_input = shmem_block_input;
147362306a36Sopenharmony_ci    ei_status.block_output = shmem_block_output;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci    info->flags |= USE_SHMEM;
147662306a36Sopenharmony_ci    return 0;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_cifailed:
147962306a36Sopenharmony_ci    return 1;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci/*====================================================================*/
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_cistatic const struct pcmcia_device_id pcnet_ids[] = {
148562306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
148662306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
148762306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
148862306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
148962306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
149062306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
149162306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
149262306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
149362306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
149462306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
149562306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
149662306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
149762306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
149862306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
149962306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
150062306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
150162306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
150262306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
150362306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
150462306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
150562306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
150662306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
150762306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
150862306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
150962306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
151062306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
151162306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
151262306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
151362306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
151462306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
151562306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
151662306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
151762306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
151862306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
151962306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
152062306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
152162306a36Sopenharmony_ci	PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),
152262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
152362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),
152462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
152562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("CNet  ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
152662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
152762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
152862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("EFA   ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
152962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
153062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
153162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
153262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
153362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
153462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
153562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
153662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
153762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
153862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
153962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
154062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
154162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
154262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
154362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
154462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
154562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
154662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
154762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
154862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
154962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
155062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
155162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
155262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
155362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
155462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
155562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
155662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
155762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a),
155862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether CF-TD LAN Card", 0x5261440f, 0x8797663b),
155962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
156062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
156162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
156262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
156362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83),
156462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
156562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
156662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
156762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73ec0d88),
156862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
156962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
157062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
157162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
157262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
157362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
157462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
157562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
157662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
157762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
157862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660+", 0x1a424a1c, 0x50dcd0ec),
157962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
158062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
158162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
158262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
158362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
158462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
158562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
158662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
158762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
158862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
158962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
159062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
159162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
159262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
159362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
159462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
159562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
159662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
159762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IC-CARD+", "IC-CARD+", 0x93693494, 0x93693494),
159862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
159962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
160062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
160162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("KENTRONICS", "KEP-230", 0xaf8144c9, 0x868f6616),
160262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
160362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
160462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
160562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
160662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
160762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
160862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
160962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
161062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
161162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
161262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
161362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
161462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
161562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
161662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline + 10/100 Network PC Card (PCM100H1)", 0x733cc81, 0x7a3e5c3a),
161762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
161862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee),
161962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
162062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN10TE", 0x88fcdeda, 0xc1e2521c),
162162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
162262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
162362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
162462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
162562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
162662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
162762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
162862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
162962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
163062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
163162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
163262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
163362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
163462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
163562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
163662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
163762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
163862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
163962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
164062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
164162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
164262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
164362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
164462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
164562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
164662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
164762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
164862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
164962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
165062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
165162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "    Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
165262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
165362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
165462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
165562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
165662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd33481, 0x10b41826),
165762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
165862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
165962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
166062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
166162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
166262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
166362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
166462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
166562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
166662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
166762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
166862306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
166962306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID13("Hypertec",  "EP401", 0x8787bec7, 0xf6e4a31e),
167062306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
167162306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
167262306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
167362306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
167462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
167562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
167662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
167762306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
167862306a36Sopenharmony_ci	/* too generic! */
167962306a36Sopenharmony_ci	/* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
168062306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
168162306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
168262306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
168362306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
168462306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
168562306a36Sopenharmony_ci	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
168662306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
168762306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
168862306a36Sopenharmony_ci	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"),
168962306a36Sopenharmony_ci	PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"),
169062306a36Sopenharmony_ci	PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"),
169162306a36Sopenharmony_ci	PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"),
169262306a36Sopenharmony_ci	PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"),
169362306a36Sopenharmony_ci	PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "cis/tamarack.cis"),
169462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac239b),
169562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0",
169662306a36Sopenharmony_ci		0xb4be14e3, 0x43ac239b, 0x0877b627),
169762306a36Sopenharmony_ci	PCMCIA_DEVICE_NULL
169862306a36Sopenharmony_ci};
169962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
170062306a36Sopenharmony_ciMODULE_FIRMWARE("cis/PCMLM28.cis");
170162306a36Sopenharmony_ciMODULE_FIRMWARE("cis/DP83903.cis");
170262306a36Sopenharmony_ciMODULE_FIRMWARE("cis/LA-PCM.cis");
170362306a36Sopenharmony_ciMODULE_FIRMWARE("cis/PE520.cis");
170462306a36Sopenharmony_ciMODULE_FIRMWARE("cis/NE2K.cis");
170562306a36Sopenharmony_ciMODULE_FIRMWARE("cis/PE-200.cis");
170662306a36Sopenharmony_ciMODULE_FIRMWARE("cis/tamarack.cis");
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic struct pcmcia_driver pcnet_driver = {
170962306a36Sopenharmony_ci	.name		= "pcnet_cs",
171062306a36Sopenharmony_ci	.probe		= pcnet_probe,
171162306a36Sopenharmony_ci	.remove		= pcnet_detach,
171262306a36Sopenharmony_ci	.owner		= THIS_MODULE,
171362306a36Sopenharmony_ci	.id_table	= pcnet_ids,
171462306a36Sopenharmony_ci	.suspend	= pcnet_suspend,
171562306a36Sopenharmony_ci	.resume		= pcnet_resume,
171662306a36Sopenharmony_ci};
171762306a36Sopenharmony_cimodule_pcmcia_driver(pcnet_driver);
1718