11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Written 1993-1998 by Donald Becker. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 1993 United States Government as represented by the 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Director, National Security Agency. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This software may be used and distributed according to the terms 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of the GNU General Public License, incorporated herein by reference. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The author may be reached as becker@scyld.com, or C/O 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Scyld Computing Corporation 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 410 Severn Ave., Suite 210 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Annapolis MD 21403 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver uses the cards in the 8390-compatible mode. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Most of the run-time complexity is handled by the generic code in 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8390.c. The code in this file is responsible for 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_probe() Detecting and initializing the card. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_probe1() 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_probe_isapnp() 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_open() The card-specific details of starting, stopping 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_reset_8390() and resetting the 8390 NIC core. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_close() 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_block_input() Routines for reading and writing blocks of 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_block_output() packet buffer memory. 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_pio_input() 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_pio_output() 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver enables the shared memory only when doing the actual data 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transfers to avoid a bug in early version of the card that corrupted 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data transferred by a AHA1542. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver now supports the programmed-I/O (PIO) data transfer mode of 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the EtherEZ. It does not use the non-8390-compatible "Altego" mode. 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds That support (if available) is in smc-ez.c. 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Changelog: 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Paul Gortmaker : multiple card support for module users. 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Donald Becker : 4/17/96 PIO support, minor potential problems avoided. 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Donald Becker : 6/6/96 correctly set auto-wrap bit. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Alexander Sotirov : 1/20/01 Added support for ISAPnP cards 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Note about the ISA PnP support: 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver can not autoprobe for more than one SMC EtherEZ PnP card. 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You have to configure the second card manually through the /proc/isapnp 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interface and then load the module with an explicit io=0x___ option. 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char version[] = 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 65a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isapnp.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 71bf4e70e54cf31dcca48d279c7f7e71328eebe749Al Viro#include <asm/irq.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "8390.h" 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME "smc-ultra" 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of I/O addresses to be probed. */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int ultra_portlist[] __initdata = 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra_probe1(struct net_device *dev, int ioaddr); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __ISAPNP__ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra_probe_isapnp(struct net_device *dev); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra_open(struct net_device *dev); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_reset_8390(struct net_device *dev); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_page); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_block_input(struct net_device *dev, int count, 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int ring_offset); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_block_output(struct net_device *dev, int count, 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, const int start_page); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_page); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_input(struct net_device *dev, int count, 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int ring_offset); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_output(struct net_device *dev, int count, 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, const int start_page); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra_close_card(struct net_device *dev); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __ISAPNP__ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct isapnp_device_id ultra_device_ids[] __initdata = { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long) "SMC EtherEZ (8416)" }, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* terminate list */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(isapnp, ultra_device_ids); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define START_PG 0x00 /* First page of TX buffer */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA_CMDREG 0 /* Offset to ASIC command register. */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA_MEMENB 0x40 /* Enable the shared memory. */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOPD 0x02 /* I/O Pipe Data (16 bits), PIO operation. */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOPA 0x07 /* I/O Pipe Address for PIO operation. */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA_IO_EXTENT 32 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EN0_ERWCNT 0x08 /* Early receive warning count. */ 1256aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_poll(struct net_device *dev) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq(dev->irq); 1307d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells ei_interrupt(dev->irq, dev); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(dev->irq); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Probe for the Ultra. This looks like a 8013 with the station 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address PROM at I/O ports <base>+8 to <base>+13, with a checksum 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds following. 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init do_ultra_probe(struct net_device *dev) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int base_addr = dev->base_addr; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq = dev->irq; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (base_addr > 0x1ff) /* Check a single specified location. */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ultra_probe1(dev, base_addr); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (base_addr != 0) /* Don't probe at all. */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __ISAPNP__ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Look for any installed ISAPnP cards */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isapnp_present() && (ultra_probe_isapnp(dev) == 0)) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; ultra_portlist[i]; i++) { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ultra_probe1(dev, ultra_portlist[i]) == 0) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init ultra_probe(int unit) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = alloc_ei_netdev(); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(dev->name, "eth%d", unit); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = do_ultra_probe(dev); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(err); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 187d079841d795b83822357ef058ce8d7979dad854cStephen Hemmingerstatic const struct net_device_ops ultra_netdev_ops = { 188d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_open = ultra_open, 189d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_stop = ultra_close_card, 190d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger 191d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_start_xmit = ei_start_xmit, 192d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_tx_timeout = ei_tx_timeout, 193d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_get_stats = ei_get_stats, 194afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = ei_set_multicast_list, 195d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_validate_addr = eth_validate_addr, 196fe96aaa14f553f0eb7af0e3502563a5400c65257Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 197d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger .ndo_change_mtu = eth_change_mtu, 198d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER 19906e884031702f06b32ce20750ab3c46c596dc776Stephen Hemminger .ndo_poll_controller = ultra_poll, 200d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger#endif 201d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger}; 202d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ultra_probe1(struct net_device *dev, int ioaddr) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, retval; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int checksum = 0; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *model_name; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char eeprom_irq = 0; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned version_printed; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Values from various config regs. */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char num_pages, irqreg, addr, piomode; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char idreg = inb(ioaddr + 7); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reg4 = inb(ioaddr + 4) & 0x7f; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the ID nibble. */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((idreg & 0xF0) != 0x20 /* SMC Ultra */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (idreg & 0xF0) != 0x40) { /* SMC EtherEZ */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select the station address register set. */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg4, ioaddr + 4); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum += inb(ioaddr + 8 + i); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((checksum & 0xff) != 0xFF) { 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug && version_printed++ == 0) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(version); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ"; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) 2410795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->dev_addr[i] = inb(ioaddr + 8 + i); 2420795af5729b18218767fab27c44b1384f72dc9adJoe Perches 243e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%s: %s at %#3x, %pM", dev->name, model_name, 244e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg ioaddr, dev->dev_addr); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch from the station address to the alternate register set and 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read the useful registers there. */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80 | reg4, ioaddr + 4); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds piomode = inb(ioaddr + 0x8); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = inb(ioaddr + 0xb); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irqreg = inb(ioaddr + 0xd); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch back to the station address register set so that the MS-DOS driver 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds can find the card after a warm boot. */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg4, ioaddr + 4); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq < 2) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15}; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The IRQ bits are split. */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq == 0) { 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", failed to detect IRQ line.\n"); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eeprom_irq = 1; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The 8390 isn't at the base address, so fake the offset */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 280b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches static const int addr_tbl[4] = { 281b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches 0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000 282b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches }; 283b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches static const short num_pages_tbl[4] = { 284b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches 0x20, 0x40, 0x80, 0xff 285b6bc765067ece933cc3dc7f5e95665a89100b1d5Joe Perches }; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_pages = num_pages_tbl[(addr >> 4) & 3]; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.name = model_name; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.word16 = 1; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.tx_start_page = START_PG; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.rx_start_page = START_PG + TX_PAGES; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.stop_page = num_pages; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ei_status.mem) { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", failed to ioremap.\n"); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENOMEM; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (piomode) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(",%s IRQ %d programmed-I/O mode.\n", 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eeprom_irq ? "EEPROM" : "assigned ", dev->irq); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_input = &ultra_pio_input; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_output = &ultra_pio_output; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.get_8390_hdr = &ultra_pio_get_hdr; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ", 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq, dev->mem_start, dev->mem_end-1); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_input = &ultra_block_input; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_output = &ultra_block_output; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.get_8390_hdr = &ultra_get_8390_hdr; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.reset_8390 = &ultra_reset_8390; 320d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger 321d079841d795b83822357ef058ce8d7979dad854cStephen Hemminger dev->netdev_ops = &ultra_netdev_ops; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NS8390_init(dev, 0); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 324b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au> retval = register_netdev(dev); 325b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au> if (retval) 326b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au> goto out; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ioaddr, ULTRA_IO_EXTENT); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __ISAPNP__ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ultra_probe_isapnp(struct net_device *dev) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; ultra_device_ids[i].vendor != 0; i++) { 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pnp_dev *idev = NULL; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((idev = pnp_find_dev(NULL, 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_device_ids[i].vendor, 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ultra_device_ids[i].function, 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idev))) { 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Avoid already found cards from previous calls */ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pnp_device_attach(idev) < 0) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pnp_activate_dev(idev) < 0) { 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __again: 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pnp_device_detach(idev); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if no io and irq, search for next */ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto __again; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* found it */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = pnp_port_start(idev, 0); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = pnp_irq(idev, 0); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char *) ultra_device_ids[i].driver_data, 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr, dev->irq); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ultra_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pnp_device_detach(idev); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.priv = (unsigned long)idev; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!idev) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_open(struct net_device *dev) 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40, 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, }; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr); /* Disable shared memory for safety. */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80, ioaddr + 5); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the IRQ line. */ 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(inb(ioaddr + 4) | 0x80, ioaddr + 4); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_status.block_input == &ultra_pio_input) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x01, ioaddr + 0x19); /* Enable ring read auto-wrap. */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the early receive warning level in window 0 high enough not 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to receive ERW interrupts. */ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, dev->base_addr + EN0_ERWCNT); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_open(dev); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_reset_8390(struct net_device *dev) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA_RESET, cmd_port); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.txing = 0; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, cmd_port); /* Disable shared memory for safety. */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80, cmd_port + 5); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_status.block_input == &ultra_pio_input) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x11, cmd_port + 6); /* Enable interrupts and PIO. */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x01, cmd_port + 6); /* Enable interrupts and memory. */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) printk("reset done\n"); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Grab the 8390 specific header. Similar to the block_input routine, but 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds we don't need to be concerned with ring wrap as the header will be at 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the start of a page, so we optimize accordingly. */ 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG)<<8); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __BIG_ENDIAN 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Officially this is what we are doing, but the readl() is faster */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unfortunately it isn't endian aware of the struct */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr->count = le16_to_cpu(hdr->count); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((unsigned int*)hdr)[0] = readl(hdr_start); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Block input and output are easy on shared memory ethercards, the only 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complication is when the ring buffer wraps. */ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *xfer_start = ei_status.mem + ring_offset - (START_PG<<8); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable shared memory. */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ring_offset + count > ei_status.stop_page*256) { 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We must wrap the input move. */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int semi_count = ei_status.stop_page*256 - ring_offset; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(skb->data, xfer_start, semi_count); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= semi_count; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4694ec031166f6a466a443f462e567f7551096b1741Al Viro memcpy_fromio(skb->data, xfer_start, count); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_block_output(struct net_device *dev, int count, const unsigned char *buf, 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int start_page) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *shmem = ei_status.mem + ((start_page - START_PG)<<8); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable shared memory. */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_toio(shmem, buf, count); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The identical operations for programmed I/O cards. 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The PIO model is trivial to use: the 16 bit start address is written 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte-sequentially to IOPA, with no intervening I/O operations, and the 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data is read or written to the IOPD data port. 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The only potential complication is that the address register is shared 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and must be always be rewritten between each read/write direction change. 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This is no problem for us, as the 8390 code ensures that we are single 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds threaded. */ 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_page) 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ring_page, ioaddr + IOPA); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_input(struct net_device *dev, int count, 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int ring_offset) 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf = skb->data; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For now set the address again, although it should already be correct. */ 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ring_offset >> 8, ioaddr + IOPA); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We know skbuffs are padded to at least word alignment. */ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insw(ioaddr + IOPD, buf, (count+1)>>1); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra_pio_output(struct net_device *dev, int count, 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, const int start_page) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */ 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(start_page, ioaddr + IOPA); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* An extra odd byte is OK here as well. */ 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsw(ioaddr + IOPD, buf, (count+1)>>1); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsultra_close_card(struct net_device *dev) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Shutting down ethercard.\n", dev->name); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + 6); /* Disable interrupts. */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NS8390_init(dev, 0); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We should someday disable shared memory and change to 8-bit mode 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "just in case"... */ 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5506aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ultra[MAX_ULTRA_CARDS]; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io[MAX_ULTRA_CARDS]; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq[MAX_ULTRA_CARDS]; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(io, int, NULL, 0); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "I/O base address(es)"); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver"); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is set up so that only a single autoprobe takes place per call. 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsISA device autoprobes on a running machine are not recommended. */ 566a2bd2ec8d1bef7479d26d375162963106757e8e9Randy Dunlapint __init 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_module(void) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int this_dev, found = 0; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io[this_dev] == 0) { 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (this_dev != 0) break; /* only autoprobe 1st one */ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n"); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_ei_netdev(); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq[this_dev]; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = io[this_dev]; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (do_ultra_probe(dev) == 0) { 583b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au> dev_ultra[found++] = dev; 584b1fc5505e0dbcc3fd7c75bfe6bee39ec50080963<herbert@gondor.apana.org.au> continue; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (found) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59564916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenkostatic void cleanup_card(struct net_device *dev) 59664916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko{ 59764916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko /* NB: ultra_close_card() does free_irq */ 59864916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko#ifdef __ISAPNP__ 59964916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; 60064916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko if (idev) 60164916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko pnp_device_detach(idev); 60264916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko#endif 60364916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT); 60464916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko iounmap(ei_status.mem); 60564916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko} 60664916f1ebe93592153c72bcdb189a31e4d40049aDenis Vlasenko 607afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscleanup_module(void) 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int this_dev; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) { 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_ultra[this_dev]; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cleanup_card(dev); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */ 622