#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
+#include <linux/crc32.h>
#include "../8390.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
MODULE_LICENSE("GPL");
-#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
-
-/* Bit map of interrupts to choose from */
-INT_MODULE_PARM(irq_mask, 0xdeb8);
-static int irq_list[4] = { -1 };
-MODULE_PARM(irq_list, "1-4i");
-
#ifdef PCMCIA_DEBUG
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
+
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
/*====================================================================*/
-static void axnet_config(dev_link_t *link);
-static void axnet_release(dev_link_t *link);
-static int axnet_event(event_t event, int priority,
- event_callback_args_t *args);
+static int axnet_config(struct pcmcia_device *link);
+static void axnet_release(struct pcmcia_device *link);
static int axnet_open(struct net_device *dev);
static int axnet_close(struct net_device *dev);
static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void ei_watchdog(u_long arg);
static void axnet_reset_8390(struct net_device *dev);
-static int mdio_read(ioaddr_t addr, int phy_id, int loc);
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value);
+static int mdio_read(kio_addr_t addr, int phy_id, int loc);
+static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value);
static void get_8390_hdr(struct net_device *,
struct e8390_pkt_hdr *, int);
static void block_output(struct net_device *dev, int count,
const u_char *buf, const int start_page);
-static dev_link_t *axnet_attach(void);
-static void axnet_detach(dev_link_t *);
-
-static dev_info_t dev_info = "axnet_cs";
-static dev_link_t *dev_list;
+static void axnet_detach(struct pcmcia_device *p_dev);
static void axdev_setup(struct net_device *dev);
static void AX88190_init(struct net_device *dev, int startp);
/*====================================================================*/
typedef struct axnet_dev_t {
- dev_link_t link;
+ struct pcmcia_device *p_dev;
dev_node_t node;
caddr_t base;
struct timer_list watchdog;
======================================================================*/
-static dev_link_t *axnet_attach(void)
+static int axnet_probe(struct pcmcia_device *link)
{
axnet_dev_t *info;
- dev_link_t *link;
struct net_device *dev;
- client_reg_t client_reg;
- int i, ret;
DEBUG(0, "axnet_attach()\n");
"eth%d", axdev_setup);
if (!dev)
- return NULL;
+ return -ENOMEM;
info = PRIV(dev);
- link = &info->link;
+ info->p_dev = link;
link->priv = dev;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
dev->do_ioctl = &axnet_ioctl;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
- /* Register with Card Services */
- link->next = dev_list;
- dev_list = link;
- client_reg.dev_info = &dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &axnet_event;
- client_reg.Version = 0x0210;
- client_reg.event_callback_args.client_data = link;
- ret = pcmcia_register_client(&link->handle, &client_reg);
- if (ret != CS_SUCCESS) {
- cs_error(link->handle, RegisterClient, ret);
- axnet_detach(link);
- return NULL;
- }
-
- return link;
+ return axnet_config(link);
} /* axnet_attach */
/*======================================================================
======================================================================*/
-static void axnet_detach(dev_link_t *link)
+static void axnet_detach(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- dev_link_t **linkp;
DEBUG(0, "axnet_detach(0x%p)\n", link);
- /* Locate device structure */
- for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) break;
- if (*linkp == NULL)
- return;
-
- if (link->dev)
+ if (link->dev_node)
unregister_netdev(dev);
- if (link->state & DEV_CONFIG)
- axnet_release(link);
-
- if (link->handle)
- pcmcia_deregister_client(link->handle);
+ axnet_release(link);
- /* Unlink device structure, free bits */
- *linkp = link->next;
free_netdev(dev);
} /* axnet_detach */
======================================================================*/
-static int get_prom(dev_link_t *link)
+static int get_prom(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- ioaddr_t ioaddr = dev->base_addr;
+ kio_addr_t ioaddr = dev->base_addr;
int i, j;
/* This is based on drivers/net/ne.c */
#define CS_CHECK(fn, ret) \
do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-static int try_io_port(dev_link_t *link)
+static int try_io_port(struct pcmcia_device *link)
{
int j, ret;
if (link->io.NumPorts1 == 32) {
for (j = 0; j < 0x400; j += 0x20) {
link->io.BasePort1 = j ^ 0x300;
link->io.BasePort2 = (j ^ 0x300) + 0x10;
- ret = pcmcia_request_io(link->handle, &link->io);
+ ret = pcmcia_request_io(link, &link->io);
if (ret == CS_SUCCESS) return ret;
}
return ret;
} else {
- return pcmcia_request_io(link->handle, &link->io);
+ return pcmcia_request_io(link, &link->io);
}
}
-static void axnet_config(dev_link_t *link)
+static int axnet_config(struct pcmcia_device *link)
{
- client_handle_t handle = link->handle;
struct net_device *dev = link->priv;
axnet_dev_t *info = PRIV(dev);
tuple_t tuple;
cisparse_t parse;
int i, j, last_ret, last_fn;
u_short buf[64];
- config_info_t conf;
DEBUG(0, "axnet_config(0x%p)\n", link);
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
tuple.DesiredTuple = CISTPL_CONFIG;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
link->conf.ConfigBase = parse.config.base;
/* don't trust the CIS on this; Linksys got it wrong */
link->conf.Present = 0x63;
- /* Configure card */
- link->state |= DEV_CONFIG;
-
- /* Look up current Vcc */
- CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
- link->conf.Vcc = conf.Vcc;
-
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
tuple.Attributes = 0;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
while (last_ret == CS_SUCCESS) {
cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
cistpl_io_t *io = &(parse.cftable_entry.io);
- if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
- pcmcia_parse_tuple(handle, &tuple, &parse) != 0 ||
+ if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
+ pcmcia_parse_tuple(link, &tuple, &parse) != 0 ||
cfg->index == 0 || cfg->io.nwin == 0)
goto next_entry;
if (last_ret == CS_SUCCESS) break;
}
next_entry:
- last_ret = pcmcia_get_next_tuple(handle, &tuple);
+ last_ret = pcmcia_get_next_tuple(link, &tuple);
}
if (last_ret != CS_SUCCESS) {
- cs_error(handle, RequestIO, last_ret);
+ cs_error(link, RequestIO, last_ret);
goto failed;
}
- CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
if (link->io.NumPorts2 == 8) {
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
}
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
Bit 2 of CCSR is active low. */
if (i == 32) {
conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
- pcmcia_access_configuration_register(link->handle, ®);
+ pcmcia_access_configuration_register(link, ®);
for (i = 0; i < 32; i++) {
j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
if ((j != 0) && (j != 0xffff)) break;
}
info->phy_id = (i < 32) ? i : -1;
- link->dev = &info->node;
- link->state &= ~DEV_CONFIG_PENDING;
+ link->dev_node = &info->node;
+ SET_NETDEV_DEV(dev, &handle_to_dev(link));
if (register_netdev(dev) != 0) {
printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n");
- link->dev = NULL;
+ link->dev_node = NULL;
goto failed;
}
} else {
printk(KERN_NOTICE " No MII transceivers found!\n");
}
- return;
+ return 0;
cs_failed:
- cs_error(link->handle, last_fn, last_ret);
+ cs_error(link, last_fn, last_ret);
failed:
axnet_release(link);
- link->state &= ~DEV_CONFIG_PENDING;
- return;
+ return -ENODEV;
} /* axnet_config */
/*======================================================================
======================================================================*/
-static void axnet_release(dev_link_t *link)
+static void axnet_release(struct pcmcia_device *link)
{
- DEBUG(0, "axnet_release(0x%p)\n", link);
-
- pcmcia_release_configuration(link->handle);
- pcmcia_release_io(link->handle, &link->io);
- pcmcia_release_irq(link->handle, &link->irq);
-
- link->state &= ~DEV_CONFIG;
+ pcmcia_disable_device(link);
}
-/*======================================================================
+static int axnet_suspend(struct pcmcia_device *link)
+{
+ struct net_device *dev = link->priv;
- The card status event handler. Mostly, this schedules other
- stuff to run after an event is received. A CARD_REMOVAL event
- also sets some flags to discourage the net drivers from trying
- to talk to the card any more.
+ if (link->open)
+ netif_device_detach(dev);
-======================================================================*/
+ return 0;
+}
-static int axnet_event(event_t event, int priority,
- event_callback_args_t *args)
+static int axnet_resume(struct pcmcia_device *link)
{
- dev_link_t *link = args->client_data;
- struct net_device *dev = link->priv;
+ struct net_device *dev = link->priv;
- DEBUG(2, "axnet_event(0x%06x)\n", event);
-
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- link->state &= ~DEV_PRESENT;
- if (link->state & DEV_CONFIG)
- netif_device_detach(dev);
- break;
- case CS_EVENT_CARD_INSERTION:
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- axnet_config(link);
- break;
- case CS_EVENT_PM_SUSPEND:
- link->state |= DEV_SUSPEND;
- /* Fall through... */
- case CS_EVENT_RESET_PHYSICAL:
- if (link->state & DEV_CONFIG) {
- if (link->open)
- netif_device_detach(dev);
- pcmcia_release_configuration(link->handle);
- }
- break;
- case CS_EVENT_PM_RESUME:
- link->state &= ~DEV_SUSPEND;
- /* Fall through... */
- case CS_EVENT_CARD_RESET:
- if (link->state & DEV_CONFIG) {
- pcmcia_request_configuration(link->handle, &link->conf);
- if (link->open) {
+ if (link->open) {
axnet_reset_8390(dev);
AX88190_init(dev, 1);
netif_device_attach(dev);
- }
}
- break;
- }
- return 0;
-} /* axnet_event */
+
+ return 0;
+}
+
/*======================================================================
#define MDIO_MASK 0x0f
#define MDIO_ENB_IN 0x02
-static void mdio_sync(ioaddr_t addr)
+static void mdio_sync(kio_addr_t addr)
{
int bits;
for (bits = 0; bits < 32; bits++) {
}
}
-static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+static int mdio_read(kio_addr_t addr, int phy_id, int loc)
{
u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
int i, retval = 0;
return (retval>>1) & 0xffff;
}
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
{
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i;
static int axnet_open(struct net_device *dev)
{
axnet_dev_t *info = PRIV(dev);
- dev_link_t *link = &info->link;
+ struct pcmcia_device *link = info->p_dev;
DEBUG(2, "axnet_open('%s')\n", dev->name);
- if (!DEV_OK(link))
+ if (!pcmcia_dev_present(link))
return -ENODEV;
link->open++;
- request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
+ request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, "axnet_cs", dev);
info->link_status = 0x00;
init_timer(&info->watchdog);
static int axnet_close(struct net_device *dev)
{
axnet_dev_t *info = PRIV(dev);
- dev_link_t *link = &info->link;
+ struct pcmcia_device *link = info->p_dev;
DEBUG(2, "axnet_close('%s')\n", dev->name);
static void axnet_reset_8390(struct net_device *dev)
{
- ioaddr_t nic_base = dev->base_addr;
+ kio_addr_t nic_base = dev->base_addr;
int i;
ei_status.txing = ei_status.dmaing = 0;
{
struct net_device *dev = (struct net_device *)(arg);
axnet_dev_t *info = PRIV(dev);
- ioaddr_t nic_base = dev->base_addr;
- ioaddr_t mii_addr = nic_base + AXNET_MII_EEP;
+ kio_addr_t nic_base = dev->base_addr;
+ kio_addr_t mii_addr = nic_base + AXNET_MII_EEP;
u_short link;
if (!netif_device_present(dev)) goto reschedule;
{
axnet_dev_t *info = PRIV(dev);
u16 *data = (u16 *)&rq->ifr_ifru;
- ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
+ kio_addr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
switch (cmd) {
case SIOCGMIIPHY:
data[0] = info->phy_id;
struct e8390_pkt_hdr *hdr,
int ring_page)
{
- ioaddr_t nic_base = dev->base_addr;
+ kio_addr_t nic_base = dev->base_addr;
outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */
outb_p(ring_page, nic_base + EN0_RSARHI);
static void block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset)
{
- ioaddr_t nic_base = dev->base_addr;
+ kio_addr_t nic_base = dev->base_addr;
int xfer_count = count;
char *buf = skb->data;
static void block_output(struct net_device *dev, int count,
const u_char *buf, const int start_page)
{
- ioaddr_t nic_base = dev->base_addr;
+ kio_addr_t nic_base = dev->base_addr;
#ifdef PCMCIA_DEBUG
if (ei_debug > 4)
outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
}
+static struct pcmcia_device_id axnet_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
+ PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+ PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
+ PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+ PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+ PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
+ PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
+ PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+ PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+ PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef),
+ /* this is not specific enough */
+ /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
+
static struct pcmcia_driver axnet_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "axnet_cs",
},
- .attach = axnet_attach,
- .detach = axnet_detach,
+ .probe = axnet_probe,
+ .remove = axnet_detach,
+ .id_table = axnet_ids,
+ .suspend = axnet_suspend,
+ .resume = axnet_resume,
};
static int __init init_axnet_cs(void)
static void __exit exit_axnet_cs(void)
{
pcmcia_unregister_driver(&axnet_cs_driver);
- while (dev_list != NULL)
- axnet_detach(dev_list);
}
module_init(init_axnet_cs);
static void ei_rx_overrun(struct net_device *dev)
{
- axnet_dev_t *info = (axnet_dev_t *)dev;
+ axnet_dev_t *info = PRIV(dev);
long e8390_base = dev->base_addr;
unsigned char was_txing, must_resend = 0;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
return &ei_local->stat;
}
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+ struct dev_mc_list *dmi;
+ u32 crc;
+
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+ /*
+ * The 8390 uses the 6 most significant bits of the
+ * CRC to index the multicast table.
+ */
+ bits[crc>>29] |= (1<<((crc>>26)&7));
+ }
+}
+
/**
* do_set_multicast_list - set/clear multicast filter
* @dev: net device for which multicast filter is adjusted
*
- * Set or clear the multicast filter for this adaptor. May be called
- * from a BH in 2.1.x. Must be called with lock held.
+ * Set or clear the multicast filter for this adaptor.
+ * Must be called with lock held.
*/
static void do_set_multicast_list(struct net_device *dev)
{
long e8390_base = dev->base_addr;
+ int i;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+ memset(ei_local->mcfilter, 0, 8);
+ if (dev->mc_list)
+ make_mc_bits(ei_local->mcfilter, dev);
+ } else {
+ /* set to accept-all */
+ memset(ei_local->mcfilter, 0xFF, 8);
+ }
+
+ outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+ for(i = 0; i < 8; i++)
+ {
+ outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+ }
+ outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
if(dev->flags&IFF_PROMISC)
outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
else
outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
+
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
}
/*
if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
}
- /*
- * Initialize the multicast list to accept-all. If we enable multicast
- * the higher levels can do the filtering.
- */
- for (i = 0; i < 8; i++)
- outb_p(0xff, e8390_base + EN1_MULT + i);
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);