xref: /linux/drivers/net/ethernet/cirrus/mac89x0.c (revision 9100eb012a31dcc3f6eff1f09eb9e118b1e5b6c4)
10a3360e1SGeert Uytterhoeven /* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
20a3360e1SGeert Uytterhoeven /*
30a3360e1SGeert Uytterhoeven 	Written 1996 by Russell Nelson, with reference to skeleton.c
40a3360e1SGeert Uytterhoeven 	written 1993-1994 by Donald Becker.
50a3360e1SGeert Uytterhoeven 
60a3360e1SGeert Uytterhoeven 	This software may be used and distributed according to the terms
70a3360e1SGeert Uytterhoeven 	of the GNU General Public License, incorporated herein by reference.
80a3360e1SGeert Uytterhoeven 
90a3360e1SGeert Uytterhoeven 	The author may be reached at nelson@crynwr.com, Crynwr
100a3360e1SGeert Uytterhoeven 	Software, 11 Grant St., Potsdam, NY 13676
110a3360e1SGeert Uytterhoeven 
120a3360e1SGeert Uytterhoeven   Changelog:
130a3360e1SGeert Uytterhoeven 
140a3360e1SGeert Uytterhoeven   Mike Cruse        : mcruse@cti-ltd.com
150a3360e1SGeert Uytterhoeven                     : Changes for Linux 2.0 compatibility.
160a3360e1SGeert Uytterhoeven                     : Added dev_id parameter in net_interrupt(),
170a3360e1SGeert Uytterhoeven                     : request_irq() and free_irq(). Just NULL for now.
180a3360e1SGeert Uytterhoeven 
190a3360e1SGeert Uytterhoeven   Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
200a3360e1SGeert Uytterhoeven                     : in net_open() and net_close() so kerneld would know
210a3360e1SGeert Uytterhoeven                     : that the module is in use and wouldn't eject the
220a3360e1SGeert Uytterhoeven                     : driver prematurely.
230a3360e1SGeert Uytterhoeven 
240a3360e1SGeert Uytterhoeven   Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
250a3360e1SGeert Uytterhoeven                     : as an example. Disabled autoprobing in init_module(),
260a3360e1SGeert Uytterhoeven                     : not a good thing to do to other devices while Linux
270a3360e1SGeert Uytterhoeven                     : is running from all accounts.
280a3360e1SGeert Uytterhoeven 
290a3360e1SGeert Uytterhoeven   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
300a3360e1SGeert Uytterhoeven 
310a3360e1SGeert Uytterhoeven   David Huggins-Daines <dhd@debian.org>
320a3360e1SGeert Uytterhoeven 
330a3360e1SGeert Uytterhoeven   Split this off into mac89x0.c, and gutted it of all parts which are
340a3360e1SGeert Uytterhoeven   not relevant to the existing CS8900 cards on the Macintosh
350a3360e1SGeert Uytterhoeven   (i.e. basically the Daynaport CS and LC cards).  To be precise:
360a3360e1SGeert Uytterhoeven 
370a3360e1SGeert Uytterhoeven     * Removed all the media-detection stuff, because these cards are
380a3360e1SGeert Uytterhoeven     TP-only.
390a3360e1SGeert Uytterhoeven 
400a3360e1SGeert Uytterhoeven     * Lobotomized the ISA interrupt bogosity, because these cards use
410a3360e1SGeert Uytterhoeven     a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
420a3360e1SGeert Uytterhoeven 
430a3360e1SGeert Uytterhoeven     * Basically eliminated everything not relevant to getting the
440a3360e1SGeert Uytterhoeven     cards minimally functioning on the Macintosh.
450a3360e1SGeert Uytterhoeven 
460a3360e1SGeert Uytterhoeven   I might add that these cards are badly designed even from the Mac
470a3360e1SGeert Uytterhoeven   standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
480a3360e1SGeert Uytterhoeven   I/O space and NuBus interrupts for these cards, but neglected to
490a3360e1SGeert Uytterhoeven   provide anything even remotely resembling a NuBus ROM.  Therefore we
500a3360e1SGeert Uytterhoeven   have to probe for them in a brain-damaged ISA-like fashion.
510a3360e1SGeert Uytterhoeven 
520a3360e1SGeert Uytterhoeven   Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
530a3360e1SGeert Uytterhoeven   check kmalloc and release the allocated memory on failure in
540a3360e1SGeert Uytterhoeven   mac89x0_probe and in init_module
550a3360e1SGeert Uytterhoeven   use local_irq_{save,restore}(flags) in net_get_stat, not just
560a3360e1SGeert Uytterhoeven   local_irq_{dis,en}able()
570a3360e1SGeert Uytterhoeven */
580a3360e1SGeert Uytterhoeven 
590a3360e1SGeert Uytterhoeven static char *version =
600a3360e1SGeert Uytterhoeven "cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
610a3360e1SGeert Uytterhoeven 
620a3360e1SGeert Uytterhoeven /* ======================= configure the driver here ======================= */
630a3360e1SGeert Uytterhoeven 
640a3360e1SGeert Uytterhoeven /* use 0 for production, 1 for verification, >2 for debug */
650a3360e1SGeert Uytterhoeven #ifndef NET_DEBUG
660a3360e1SGeert Uytterhoeven #define NET_DEBUG 0
670a3360e1SGeert Uytterhoeven #endif
680a3360e1SGeert Uytterhoeven 
690a3360e1SGeert Uytterhoeven /* ======================= end of configuration ======================= */
700a3360e1SGeert Uytterhoeven 
710a3360e1SGeert Uytterhoeven 
720a3360e1SGeert Uytterhoeven /* Always include 'config.h' first in case the user wants to turn on
730a3360e1SGeert Uytterhoeven    or override something. */
740a3360e1SGeert Uytterhoeven #include <linux/module.h>
750a3360e1SGeert Uytterhoeven 
760a3360e1SGeert Uytterhoeven /*
770a3360e1SGeert Uytterhoeven   Sources:
780a3360e1SGeert Uytterhoeven 
790a3360e1SGeert Uytterhoeven 	Crynwr packet driver epktisa.
800a3360e1SGeert Uytterhoeven 
810a3360e1SGeert Uytterhoeven 	Crystal Semiconductor data sheets.
820a3360e1SGeert Uytterhoeven 
830a3360e1SGeert Uytterhoeven */
840a3360e1SGeert Uytterhoeven 
850a3360e1SGeert Uytterhoeven #include <linux/kernel.h>
860a3360e1SGeert Uytterhoeven #include <linux/types.h>
870a3360e1SGeert Uytterhoeven #include <linux/fcntl.h>
880a3360e1SGeert Uytterhoeven #include <linux/interrupt.h>
890a3360e1SGeert Uytterhoeven #include <linux/ioport.h>
900a3360e1SGeert Uytterhoeven #include <linux/in.h>
910a3360e1SGeert Uytterhoeven #include <linux/string.h>
920a3360e1SGeert Uytterhoeven #include <linux/nubus.h>
930a3360e1SGeert Uytterhoeven #include <linux/errno.h>
940a3360e1SGeert Uytterhoeven #include <linux/init.h>
950a3360e1SGeert Uytterhoeven #include <linux/netdevice.h>
960a3360e1SGeert Uytterhoeven #include <linux/etherdevice.h>
970a3360e1SGeert Uytterhoeven #include <linux/skbuff.h>
980a3360e1SGeert Uytterhoeven #include <linux/delay.h>
990a3360e1SGeert Uytterhoeven #include <linux/bitops.h>
1000a3360e1SGeert Uytterhoeven #include <linux/gfp.h>
1010a3360e1SGeert Uytterhoeven 
1020a3360e1SGeert Uytterhoeven #include <asm/system.h>
1030a3360e1SGeert Uytterhoeven #include <asm/io.h>
1040a3360e1SGeert Uytterhoeven #include <asm/hwtest.h>
1050a3360e1SGeert Uytterhoeven #include <asm/macints.h>
1060a3360e1SGeert Uytterhoeven 
1070a3360e1SGeert Uytterhoeven #include "cs89x0.h"
1080a3360e1SGeert Uytterhoeven 
1090a3360e1SGeert Uytterhoeven static unsigned int net_debug = NET_DEBUG;
1100a3360e1SGeert Uytterhoeven 
1110a3360e1SGeert Uytterhoeven /* Information that need to be kept for each board. */
1120a3360e1SGeert Uytterhoeven struct net_local {
1130a3360e1SGeert Uytterhoeven 	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
1140a3360e1SGeert Uytterhoeven 	char chip_revision;	/* revision letter of the chip ('A'...) */
1150a3360e1SGeert Uytterhoeven 	int send_cmd;		/* the propercommand used to send a packet. */
1160a3360e1SGeert Uytterhoeven 	int rx_mode;
1170a3360e1SGeert Uytterhoeven 	int curr_rx_cfg;
1180a3360e1SGeert Uytterhoeven         int send_underrun;      /* keep track of how many underruns in a row we get */
1190a3360e1SGeert Uytterhoeven 	struct sk_buff *skb;
1200a3360e1SGeert Uytterhoeven };
1210a3360e1SGeert Uytterhoeven 
1220a3360e1SGeert Uytterhoeven /* Index to functions, as function prototypes. */
1230a3360e1SGeert Uytterhoeven 
1240a3360e1SGeert Uytterhoeven #if 0
1250a3360e1SGeert Uytterhoeven extern void reset_chip(struct net_device *dev);
1260a3360e1SGeert Uytterhoeven #endif
1270a3360e1SGeert Uytterhoeven static int net_open(struct net_device *dev);
1280a3360e1SGeert Uytterhoeven static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
1290a3360e1SGeert Uytterhoeven static irqreturn_t net_interrupt(int irq, void *dev_id);
1300a3360e1SGeert Uytterhoeven static void set_multicast_list(struct net_device *dev);
1310a3360e1SGeert Uytterhoeven static void net_rx(struct net_device *dev);
1320a3360e1SGeert Uytterhoeven static int net_close(struct net_device *dev);
1330a3360e1SGeert Uytterhoeven static struct net_device_stats *net_get_stats(struct net_device *dev);
1340a3360e1SGeert Uytterhoeven static int set_mac_address(struct net_device *dev, void *addr);
1350a3360e1SGeert Uytterhoeven 
1360a3360e1SGeert Uytterhoeven 
1370a3360e1SGeert Uytterhoeven /* Example routines you must write ;->. */
1380a3360e1SGeert Uytterhoeven #define tx_done(dev) 1
1390a3360e1SGeert Uytterhoeven 
1400a3360e1SGeert Uytterhoeven /* For reading/writing registers ISA-style */
1410a3360e1SGeert Uytterhoeven static inline int
1420a3360e1SGeert Uytterhoeven readreg_io(struct net_device *dev, int portno)
1430a3360e1SGeert Uytterhoeven {
1440a3360e1SGeert Uytterhoeven 	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
1450a3360e1SGeert Uytterhoeven 	return swab16(nubus_readw(dev->base_addr + DATA_PORT));
1460a3360e1SGeert Uytterhoeven }
1470a3360e1SGeert Uytterhoeven 
1480a3360e1SGeert Uytterhoeven static inline void
1490a3360e1SGeert Uytterhoeven writereg_io(struct net_device *dev, int portno, int value)
1500a3360e1SGeert Uytterhoeven {
1510a3360e1SGeert Uytterhoeven 	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
1520a3360e1SGeert Uytterhoeven 	nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
1530a3360e1SGeert Uytterhoeven }
1540a3360e1SGeert Uytterhoeven 
1550a3360e1SGeert Uytterhoeven /* These are for reading/writing registers in shared memory */
1560a3360e1SGeert Uytterhoeven static inline int
1570a3360e1SGeert Uytterhoeven readreg(struct net_device *dev, int portno)
1580a3360e1SGeert Uytterhoeven {
1590a3360e1SGeert Uytterhoeven 	return swab16(nubus_readw(dev->mem_start + portno));
1600a3360e1SGeert Uytterhoeven }
1610a3360e1SGeert Uytterhoeven 
1620a3360e1SGeert Uytterhoeven static inline void
1630a3360e1SGeert Uytterhoeven writereg(struct net_device *dev, int portno, int value)
1640a3360e1SGeert Uytterhoeven {
1650a3360e1SGeert Uytterhoeven 	nubus_writew(swab16(value), dev->mem_start + portno);
1660a3360e1SGeert Uytterhoeven }
1670a3360e1SGeert Uytterhoeven 
1680a3360e1SGeert Uytterhoeven static const struct net_device_ops mac89x0_netdev_ops = {
1690a3360e1SGeert Uytterhoeven 	.ndo_open		= net_open,
1700a3360e1SGeert Uytterhoeven 	.ndo_stop		= net_close,
1710a3360e1SGeert Uytterhoeven 	.ndo_start_xmit		= net_send_packet,
1720a3360e1SGeert Uytterhoeven 	.ndo_get_stats		= net_get_stats,
1730a3360e1SGeert Uytterhoeven 	.ndo_set_rx_mode	= set_multicast_list,
1740a3360e1SGeert Uytterhoeven 	.ndo_set_mac_address	= set_mac_address,
1750a3360e1SGeert Uytterhoeven 	.ndo_validate_addr	= eth_validate_addr,
1760a3360e1SGeert Uytterhoeven 	.ndo_change_mtu		= eth_change_mtu,
1770a3360e1SGeert Uytterhoeven };
1780a3360e1SGeert Uytterhoeven 
1790a3360e1SGeert Uytterhoeven /* Probe for the CS8900 card in slot E.  We won't bother looking
1800a3360e1SGeert Uytterhoeven    anywhere else until we have a really good reason to do so. */
1810a3360e1SGeert Uytterhoeven struct net_device * __init mac89x0_probe(int unit)
1820a3360e1SGeert Uytterhoeven {
1830a3360e1SGeert Uytterhoeven 	struct net_device *dev;
1840a3360e1SGeert Uytterhoeven 	static int once_is_enough;
1850a3360e1SGeert Uytterhoeven 	struct net_local *lp;
1860a3360e1SGeert Uytterhoeven 	static unsigned version_printed;
1870a3360e1SGeert Uytterhoeven 	int i, slot;
1880a3360e1SGeert Uytterhoeven 	unsigned rev_type = 0;
1890a3360e1SGeert Uytterhoeven 	unsigned long ioaddr;
1900a3360e1SGeert Uytterhoeven 	unsigned short sig;
1910a3360e1SGeert Uytterhoeven 	int err = -ENODEV;
1920a3360e1SGeert Uytterhoeven 
1930a3360e1SGeert Uytterhoeven 	if (!MACH_IS_MAC)
1940a3360e1SGeert Uytterhoeven 		return ERR_PTR(-ENODEV);
1950a3360e1SGeert Uytterhoeven 
1960a3360e1SGeert Uytterhoeven 	dev = alloc_etherdev(sizeof(struct net_local));
1970a3360e1SGeert Uytterhoeven 	if (!dev)
1980a3360e1SGeert Uytterhoeven 		return ERR_PTR(-ENOMEM);
1990a3360e1SGeert Uytterhoeven 
2000a3360e1SGeert Uytterhoeven 	if (unit >= 0) {
2010a3360e1SGeert Uytterhoeven 		sprintf(dev->name, "eth%d", unit);
2020a3360e1SGeert Uytterhoeven 		netdev_boot_setup_check(dev);
2030a3360e1SGeert Uytterhoeven 	}
2040a3360e1SGeert Uytterhoeven 
2050a3360e1SGeert Uytterhoeven 	if (once_is_enough)
2060a3360e1SGeert Uytterhoeven 		goto out;
2070a3360e1SGeert Uytterhoeven 	once_is_enough = 1;
2080a3360e1SGeert Uytterhoeven 
2090a3360e1SGeert Uytterhoeven 	/* We might have to parameterize this later */
2100a3360e1SGeert Uytterhoeven 	slot = 0xE;
2110a3360e1SGeert Uytterhoeven 	/* Get out now if there's a real NuBus card in slot E */
2120a3360e1SGeert Uytterhoeven 	if (nubus_find_slot(slot, NULL) != NULL)
2130a3360e1SGeert Uytterhoeven 		goto out;
2140a3360e1SGeert Uytterhoeven 
2150a3360e1SGeert Uytterhoeven 	/* The pseudo-ISA bits always live at offset 0x300 (gee,
2160a3360e1SGeert Uytterhoeven            wonder why...) */
2170a3360e1SGeert Uytterhoeven 	ioaddr = (unsigned long)
2180a3360e1SGeert Uytterhoeven 		nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
2190a3360e1SGeert Uytterhoeven 	{
2200a3360e1SGeert Uytterhoeven 		unsigned long flags;
2210a3360e1SGeert Uytterhoeven 		int card_present;
2220a3360e1SGeert Uytterhoeven 
2230a3360e1SGeert Uytterhoeven 		local_irq_save(flags);
2240a3360e1SGeert Uytterhoeven 		card_present = (hwreg_present((void*) ioaddr+4) &&
2250a3360e1SGeert Uytterhoeven 				hwreg_present((void*) ioaddr + DATA_PORT));
2260a3360e1SGeert Uytterhoeven 		local_irq_restore(flags);
2270a3360e1SGeert Uytterhoeven 
2280a3360e1SGeert Uytterhoeven 		if (!card_present)
2290a3360e1SGeert Uytterhoeven 			goto out;
2300a3360e1SGeert Uytterhoeven 	}
2310a3360e1SGeert Uytterhoeven 
2320a3360e1SGeert Uytterhoeven 	nubus_writew(0, ioaddr + ADD_PORT);
2330a3360e1SGeert Uytterhoeven 	sig = nubus_readw(ioaddr + DATA_PORT);
2340a3360e1SGeert Uytterhoeven 	if (sig != swab16(CHIP_EISA_ID_SIG))
2350a3360e1SGeert Uytterhoeven 		goto out;
2360a3360e1SGeert Uytterhoeven 
2370a3360e1SGeert Uytterhoeven 	/* Initialize the net_device structure. */
2380a3360e1SGeert Uytterhoeven 	lp = netdev_priv(dev);
2390a3360e1SGeert Uytterhoeven 
2400a3360e1SGeert Uytterhoeven 	/* Fill in the 'dev' fields. */
2410a3360e1SGeert Uytterhoeven 	dev->base_addr = ioaddr;
2420a3360e1SGeert Uytterhoeven 	dev->mem_start = (unsigned long)
2430a3360e1SGeert Uytterhoeven 		nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
2440a3360e1SGeert Uytterhoeven 	dev->mem_end = dev->mem_start + 0x1000;
2450a3360e1SGeert Uytterhoeven 
2460a3360e1SGeert Uytterhoeven 	/* Turn on shared memory */
2470a3360e1SGeert Uytterhoeven 	writereg_io(dev, PP_BusCTL, MEMORY_ON);
2480a3360e1SGeert Uytterhoeven 
2490a3360e1SGeert Uytterhoeven 	/* get the chip type */
2500a3360e1SGeert Uytterhoeven 	rev_type = readreg(dev, PRODUCT_ID_ADD);
2510a3360e1SGeert Uytterhoeven 	lp->chip_type = rev_type &~ REVISON_BITS;
2520a3360e1SGeert Uytterhoeven 	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
2530a3360e1SGeert Uytterhoeven 
2540a3360e1SGeert Uytterhoeven 	/* Check the chip type and revision in order to set the correct send command
2550a3360e1SGeert Uytterhoeven 	CS8920 revision C and CS8900 revision F can use the faster send. */
2560a3360e1SGeert Uytterhoeven 	lp->send_cmd = TX_AFTER_381;
2570a3360e1SGeert Uytterhoeven 	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
2580a3360e1SGeert Uytterhoeven 		lp->send_cmd = TX_NOW;
2590a3360e1SGeert Uytterhoeven 	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
2600a3360e1SGeert Uytterhoeven 		lp->send_cmd = TX_NOW;
2610a3360e1SGeert Uytterhoeven 
2620a3360e1SGeert Uytterhoeven 	if (net_debug && version_printed++ == 0)
2630a3360e1SGeert Uytterhoeven 		printk(version);
2640a3360e1SGeert Uytterhoeven 
2650a3360e1SGeert Uytterhoeven 	printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx",
2660a3360e1SGeert Uytterhoeven 	       dev->name,
2670a3360e1SGeert Uytterhoeven 	       lp->chip_type==CS8900?'0':'2',
2680a3360e1SGeert Uytterhoeven 	       lp->chip_type==CS8920M?"M":"",
2690a3360e1SGeert Uytterhoeven 	       lp->chip_revision,
2700a3360e1SGeert Uytterhoeven 	       dev->base_addr);
2710a3360e1SGeert Uytterhoeven 
2720a3360e1SGeert Uytterhoeven 	/* Try to read the MAC address */
2730a3360e1SGeert Uytterhoeven 	if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
2740a3360e1SGeert Uytterhoeven 		printk("\nmac89x0: No EEPROM, giving up now.\n");
2750a3360e1SGeert Uytterhoeven 		goto out1;
2760a3360e1SGeert Uytterhoeven         } else {
2770a3360e1SGeert Uytterhoeven                 for (i = 0; i < ETH_ALEN; i += 2) {
2780a3360e1SGeert Uytterhoeven 			/* Big-endian (why??!) */
2790a3360e1SGeert Uytterhoeven 			unsigned short s = readreg(dev, PP_IA + i);
2800a3360e1SGeert Uytterhoeven                         dev->dev_addr[i] = s >> 8;
2810a3360e1SGeert Uytterhoeven                         dev->dev_addr[i+1] = s & 0xff;
2820a3360e1SGeert Uytterhoeven                 }
2830a3360e1SGeert Uytterhoeven         }
2840a3360e1SGeert Uytterhoeven 
2850a3360e1SGeert Uytterhoeven 	dev->irq = SLOT2IRQ(slot);
2860a3360e1SGeert Uytterhoeven 
2870a3360e1SGeert Uytterhoeven 	/* print the IRQ and ethernet address. */
2880a3360e1SGeert Uytterhoeven 
2890a3360e1SGeert Uytterhoeven 	printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr);
2900a3360e1SGeert Uytterhoeven 
2910a3360e1SGeert Uytterhoeven 	dev->netdev_ops		= &mac89x0_netdev_ops;
2920a3360e1SGeert Uytterhoeven 
2930a3360e1SGeert Uytterhoeven 	err = register_netdev(dev);
2940a3360e1SGeert Uytterhoeven 	if (err)
2950a3360e1SGeert Uytterhoeven 		goto out1;
2960a3360e1SGeert Uytterhoeven 	return NULL;
2970a3360e1SGeert Uytterhoeven out1:
2980a3360e1SGeert Uytterhoeven 	nubus_writew(0, dev->base_addr + ADD_PORT);
2990a3360e1SGeert Uytterhoeven out:
3000a3360e1SGeert Uytterhoeven 	free_netdev(dev);
3010a3360e1SGeert Uytterhoeven 	return ERR_PTR(err);
3020a3360e1SGeert Uytterhoeven }
3030a3360e1SGeert Uytterhoeven 
3040a3360e1SGeert Uytterhoeven #if 0
3050a3360e1SGeert Uytterhoeven /* This is useful for something, but I don't know what yet. */
3060a3360e1SGeert Uytterhoeven void __init reset_chip(struct net_device *dev)
3070a3360e1SGeert Uytterhoeven {
3080a3360e1SGeert Uytterhoeven 	int reset_start_time;
3090a3360e1SGeert Uytterhoeven 
3100a3360e1SGeert Uytterhoeven 	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
3110a3360e1SGeert Uytterhoeven 
3120a3360e1SGeert Uytterhoeven 	/* wait 30 ms */
3130a3360e1SGeert Uytterhoeven 	msleep_interruptible(30);
3140a3360e1SGeert Uytterhoeven 
3150a3360e1SGeert Uytterhoeven 	/* Wait until the chip is reset */
3160a3360e1SGeert Uytterhoeven 	reset_start_time = jiffies;
3170a3360e1SGeert Uytterhoeven 	while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
3180a3360e1SGeert Uytterhoeven 		;
3190a3360e1SGeert Uytterhoeven }
3200a3360e1SGeert Uytterhoeven #endif
3210a3360e1SGeert Uytterhoeven 
3220a3360e1SGeert Uytterhoeven /* Open/initialize the board.  This is called (in the current kernel)
3230a3360e1SGeert Uytterhoeven    sometime after booting when the 'ifconfig' program is run.
3240a3360e1SGeert Uytterhoeven 
3250a3360e1SGeert Uytterhoeven    This routine should set everything up anew at each open, even
3260a3360e1SGeert Uytterhoeven    registers that "should" only need to be set once at boot, so that
3270a3360e1SGeert Uytterhoeven    there is non-reboot way to recover if something goes wrong.
3280a3360e1SGeert Uytterhoeven    */
3290a3360e1SGeert Uytterhoeven static int
3300a3360e1SGeert Uytterhoeven net_open(struct net_device *dev)
3310a3360e1SGeert Uytterhoeven {
3320a3360e1SGeert Uytterhoeven 	struct net_local *lp = netdev_priv(dev);
3330a3360e1SGeert Uytterhoeven 	int i;
3340a3360e1SGeert Uytterhoeven 
3350a3360e1SGeert Uytterhoeven 	/* Disable the interrupt for now */
3360a3360e1SGeert Uytterhoeven 	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
3370a3360e1SGeert Uytterhoeven 
3380a3360e1SGeert Uytterhoeven 	/* Grab the interrupt */
3390a3360e1SGeert Uytterhoeven 	if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev))
3400a3360e1SGeert Uytterhoeven 		return -EAGAIN;
3410a3360e1SGeert Uytterhoeven 
3420a3360e1SGeert Uytterhoeven 	/* Set up the IRQ - Apparently magic */
3430a3360e1SGeert Uytterhoeven 	if (lp->chip_type == CS8900)
3440a3360e1SGeert Uytterhoeven 		writereg(dev, PP_CS8900_ISAINT, 0);
3450a3360e1SGeert Uytterhoeven 	else
3460a3360e1SGeert Uytterhoeven 		writereg(dev, PP_CS8920_ISAINT, 0);
3470a3360e1SGeert Uytterhoeven 
3480a3360e1SGeert Uytterhoeven 	/* set the Ethernet address */
3490a3360e1SGeert Uytterhoeven 	for (i=0; i < ETH_ALEN/2; i++)
3500a3360e1SGeert Uytterhoeven 		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
3510a3360e1SGeert Uytterhoeven 
3520a3360e1SGeert Uytterhoeven 	/* Turn on both receive and transmit operations */
3530a3360e1SGeert Uytterhoeven 	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
3540a3360e1SGeert Uytterhoeven 
3550a3360e1SGeert Uytterhoeven 	/* Receive only error free packets addressed to this card */
3560a3360e1SGeert Uytterhoeven 	lp->rx_mode = 0;
3570a3360e1SGeert Uytterhoeven 	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
3580a3360e1SGeert Uytterhoeven 
3590a3360e1SGeert Uytterhoeven 	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
3600a3360e1SGeert Uytterhoeven 
3610a3360e1SGeert Uytterhoeven 	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
3620a3360e1SGeert Uytterhoeven 
3630a3360e1SGeert Uytterhoeven 	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
3640a3360e1SGeert Uytterhoeven 	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
3650a3360e1SGeert Uytterhoeven 
3660a3360e1SGeert Uytterhoeven 	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
3670a3360e1SGeert Uytterhoeven 		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
3680a3360e1SGeert Uytterhoeven 
3690a3360e1SGeert Uytterhoeven 	/* now that we've got our act together, enable everything */
3700a3360e1SGeert Uytterhoeven 	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
3710a3360e1SGeert Uytterhoeven 	netif_start_queue(dev);
3720a3360e1SGeert Uytterhoeven 	return 0;
3730a3360e1SGeert Uytterhoeven }
3740a3360e1SGeert Uytterhoeven 
3750a3360e1SGeert Uytterhoeven static int
3760a3360e1SGeert Uytterhoeven net_send_packet(struct sk_buff *skb, struct net_device *dev)
3770a3360e1SGeert Uytterhoeven {
3780a3360e1SGeert Uytterhoeven 	struct net_local *lp = netdev_priv(dev);
3790a3360e1SGeert Uytterhoeven 	unsigned long flags;
3800a3360e1SGeert Uytterhoeven 
3810a3360e1SGeert Uytterhoeven 	if (net_debug > 3)
3820a3360e1SGeert Uytterhoeven 		printk("%s: sent %d byte packet of type %x\n",
3830a3360e1SGeert Uytterhoeven 		       dev->name, skb->len,
3840a3360e1SGeert Uytterhoeven 		       (skb->data[ETH_ALEN+ETH_ALEN] << 8)
3850a3360e1SGeert Uytterhoeven 		       | skb->data[ETH_ALEN+ETH_ALEN+1]);
3860a3360e1SGeert Uytterhoeven 
3870a3360e1SGeert Uytterhoeven 	/* keep the upload from being interrupted, since we
3880a3360e1SGeert Uytterhoeven 	   ask the chip to start transmitting before the
3890a3360e1SGeert Uytterhoeven 	   whole packet has been completely uploaded. */
3900a3360e1SGeert Uytterhoeven 	local_irq_save(flags);
3910a3360e1SGeert Uytterhoeven 	netif_stop_queue(dev);
3920a3360e1SGeert Uytterhoeven 
3930a3360e1SGeert Uytterhoeven 	/* initiate a transmit sequence */
3940a3360e1SGeert Uytterhoeven 	writereg(dev, PP_TxCMD, lp->send_cmd);
3950a3360e1SGeert Uytterhoeven 	writereg(dev, PP_TxLength, skb->len);
3960a3360e1SGeert Uytterhoeven 
3970a3360e1SGeert Uytterhoeven 	/* Test to see if the chip has allocated memory for the packet */
3980a3360e1SGeert Uytterhoeven 	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
3990a3360e1SGeert Uytterhoeven 		/* Gasp!  It hasn't.  But that shouldn't happen since
4000a3360e1SGeert Uytterhoeven 		   we're waiting for TxOk, so return 1 and requeue this packet. */
4010a3360e1SGeert Uytterhoeven 		local_irq_restore(flags);
4020a3360e1SGeert Uytterhoeven 		return NETDEV_TX_BUSY;
4030a3360e1SGeert Uytterhoeven 	}
4040a3360e1SGeert Uytterhoeven 
4050a3360e1SGeert Uytterhoeven 	/* Write the contents of the packet */
4060a3360e1SGeert Uytterhoeven 	skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
4070a3360e1SGeert Uytterhoeven 				  skb->len+1);
4080a3360e1SGeert Uytterhoeven 
4090a3360e1SGeert Uytterhoeven 	local_irq_restore(flags);
4100a3360e1SGeert Uytterhoeven 	dev_kfree_skb (skb);
4110a3360e1SGeert Uytterhoeven 
4120a3360e1SGeert Uytterhoeven 	return NETDEV_TX_OK;
4130a3360e1SGeert Uytterhoeven }
4140a3360e1SGeert Uytterhoeven 
4150a3360e1SGeert Uytterhoeven /* The typical workload of the driver:
4160a3360e1SGeert Uytterhoeven    Handle the network interface interrupts. */
4170a3360e1SGeert Uytterhoeven static irqreturn_t net_interrupt(int irq, void *dev_id)
4180a3360e1SGeert Uytterhoeven {
4190a3360e1SGeert Uytterhoeven 	struct net_device *dev = dev_id;
4200a3360e1SGeert Uytterhoeven 	struct net_local *lp;
4210a3360e1SGeert Uytterhoeven 	int ioaddr, status;
4220a3360e1SGeert Uytterhoeven 
4230a3360e1SGeert Uytterhoeven 	if (dev == NULL) {
4240a3360e1SGeert Uytterhoeven 		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
4250a3360e1SGeert Uytterhoeven 		return IRQ_NONE;
4260a3360e1SGeert Uytterhoeven 	}
4270a3360e1SGeert Uytterhoeven 
4280a3360e1SGeert Uytterhoeven 	ioaddr = dev->base_addr;
4290a3360e1SGeert Uytterhoeven 	lp = netdev_priv(dev);
4300a3360e1SGeert Uytterhoeven 
4310a3360e1SGeert Uytterhoeven 	/* we MUST read all the events out of the ISQ, otherwise we'll never
4320a3360e1SGeert Uytterhoeven            get interrupted again.  As a consequence, we can't have any limit
4330a3360e1SGeert Uytterhoeven            on the number of times we loop in the interrupt handler.  The
4340a3360e1SGeert Uytterhoeven            hardware guarantees that eventually we'll run out of events.  Of
4350a3360e1SGeert Uytterhoeven            course, if you're on a slow machine, and packets are arriving
4360a3360e1SGeert Uytterhoeven            faster than you can read them off, you're screwed.  Hasta la
4370a3360e1SGeert Uytterhoeven            vista, baby!  */
4380a3360e1SGeert Uytterhoeven 	while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
4390a3360e1SGeert Uytterhoeven 		if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
4400a3360e1SGeert Uytterhoeven 		switch(status & ISQ_EVENT_MASK) {
4410a3360e1SGeert Uytterhoeven 		case ISQ_RECEIVER_EVENT:
4420a3360e1SGeert Uytterhoeven 			/* Got a packet(s). */
4430a3360e1SGeert Uytterhoeven 			net_rx(dev);
4440a3360e1SGeert Uytterhoeven 			break;
4450a3360e1SGeert Uytterhoeven 		case ISQ_TRANSMITTER_EVENT:
4460a3360e1SGeert Uytterhoeven 			dev->stats.tx_packets++;
4470a3360e1SGeert Uytterhoeven 			netif_wake_queue(dev);
4480a3360e1SGeert Uytterhoeven 			if ((status & TX_OK) == 0)
4490a3360e1SGeert Uytterhoeven 				dev->stats.tx_errors++;
4500a3360e1SGeert Uytterhoeven 			if (status & TX_LOST_CRS)
4510a3360e1SGeert Uytterhoeven 				dev->stats.tx_carrier_errors++;
4520a3360e1SGeert Uytterhoeven 			if (status & TX_SQE_ERROR)
4530a3360e1SGeert Uytterhoeven 				dev->stats.tx_heartbeat_errors++;
4540a3360e1SGeert Uytterhoeven 			if (status & TX_LATE_COL)
4550a3360e1SGeert Uytterhoeven 				dev->stats.tx_window_errors++;
4560a3360e1SGeert Uytterhoeven 			if (status & TX_16_COL)
4570a3360e1SGeert Uytterhoeven 				dev->stats.tx_aborted_errors++;
4580a3360e1SGeert Uytterhoeven 			break;
4590a3360e1SGeert Uytterhoeven 		case ISQ_BUFFER_EVENT:
4600a3360e1SGeert Uytterhoeven 			if (status & READY_FOR_TX) {
4610a3360e1SGeert Uytterhoeven 				/* we tried to transmit a packet earlier,
4620a3360e1SGeert Uytterhoeven                                    but inexplicably ran out of buffers.
4630a3360e1SGeert Uytterhoeven                                    That shouldn't happen since we only ever
4640a3360e1SGeert Uytterhoeven                                    load one packet.  Shrug.  Do the right
4650a3360e1SGeert Uytterhoeven                                    thing anyway. */
4660a3360e1SGeert Uytterhoeven 				netif_wake_queue(dev);
4670a3360e1SGeert Uytterhoeven 			}
4680a3360e1SGeert Uytterhoeven 			if (status & TX_UNDERRUN) {
4690a3360e1SGeert Uytterhoeven 				if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
4700a3360e1SGeert Uytterhoeven                                 lp->send_underrun++;
4710a3360e1SGeert Uytterhoeven                                 if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
4720a3360e1SGeert Uytterhoeven                                 else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
4730a3360e1SGeert Uytterhoeven                         }
4740a3360e1SGeert Uytterhoeven 			break;
4750a3360e1SGeert Uytterhoeven 		case ISQ_RX_MISS_EVENT:
4760a3360e1SGeert Uytterhoeven 			dev->stats.rx_missed_errors += (status >> 6);
4770a3360e1SGeert Uytterhoeven 			break;
4780a3360e1SGeert Uytterhoeven 		case ISQ_TX_COL_EVENT:
4790a3360e1SGeert Uytterhoeven 			dev->stats.collisions += (status >> 6);
4800a3360e1SGeert Uytterhoeven 			break;
4810a3360e1SGeert Uytterhoeven 		}
4820a3360e1SGeert Uytterhoeven 	}
4830a3360e1SGeert Uytterhoeven 	return IRQ_HANDLED;
4840a3360e1SGeert Uytterhoeven }
4850a3360e1SGeert Uytterhoeven 
4860a3360e1SGeert Uytterhoeven /* We have a good packet(s), get it/them out of the buffers. */
4870a3360e1SGeert Uytterhoeven static void
4880a3360e1SGeert Uytterhoeven net_rx(struct net_device *dev)
4890a3360e1SGeert Uytterhoeven {
4900a3360e1SGeert Uytterhoeven 	struct sk_buff *skb;
4910a3360e1SGeert Uytterhoeven 	int status, length;
4920a3360e1SGeert Uytterhoeven 
4930a3360e1SGeert Uytterhoeven 	status = readreg(dev, PP_RxStatus);
4940a3360e1SGeert Uytterhoeven 	if ((status & RX_OK) == 0) {
4950a3360e1SGeert Uytterhoeven 		dev->stats.rx_errors++;
4960a3360e1SGeert Uytterhoeven 		if (status & RX_RUNT)
4970a3360e1SGeert Uytterhoeven 				dev->stats.rx_length_errors++;
4980a3360e1SGeert Uytterhoeven 		if (status & RX_EXTRA_DATA)
4990a3360e1SGeert Uytterhoeven 				dev->stats.rx_length_errors++;
5000a3360e1SGeert Uytterhoeven 		if ((status & RX_CRC_ERROR) &&
5010a3360e1SGeert Uytterhoeven 		    !(status & (RX_EXTRA_DATA|RX_RUNT)))
5020a3360e1SGeert Uytterhoeven 			/* per str 172 */
5030a3360e1SGeert Uytterhoeven 			dev->stats.rx_crc_errors++;
5040a3360e1SGeert Uytterhoeven 		if (status & RX_DRIBBLE)
5050a3360e1SGeert Uytterhoeven 				dev->stats.rx_frame_errors++;
5060a3360e1SGeert Uytterhoeven 		return;
5070a3360e1SGeert Uytterhoeven 	}
5080a3360e1SGeert Uytterhoeven 
5090a3360e1SGeert Uytterhoeven 	length = readreg(dev, PP_RxLength);
5100a3360e1SGeert Uytterhoeven 	/* Malloc up new buffer. */
5110a3360e1SGeert Uytterhoeven 	skb = alloc_skb(length, GFP_ATOMIC);
5120a3360e1SGeert Uytterhoeven 	if (skb == NULL) {
5130a3360e1SGeert Uytterhoeven 		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
5140a3360e1SGeert Uytterhoeven 		dev->stats.rx_dropped++;
5150a3360e1SGeert Uytterhoeven 		return;
5160a3360e1SGeert Uytterhoeven 	}
5170a3360e1SGeert Uytterhoeven 	skb_put(skb, length);
5180a3360e1SGeert Uytterhoeven 
5190a3360e1SGeert Uytterhoeven 	skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame),
5200a3360e1SGeert Uytterhoeven 				length);
5210a3360e1SGeert Uytterhoeven 
5220a3360e1SGeert Uytterhoeven 	if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
5230a3360e1SGeert Uytterhoeven                                  dev->name, length,
5240a3360e1SGeert Uytterhoeven                                  (skb->data[ETH_ALEN+ETH_ALEN] << 8)
5250a3360e1SGeert Uytterhoeven 				 | skb->data[ETH_ALEN+ETH_ALEN+1]);
5260a3360e1SGeert Uytterhoeven 
5270a3360e1SGeert Uytterhoeven         skb->protocol=eth_type_trans(skb,dev);
5280a3360e1SGeert Uytterhoeven 	netif_rx(skb);
5290a3360e1SGeert Uytterhoeven 	dev->stats.rx_packets++;
5300a3360e1SGeert Uytterhoeven 	dev->stats.rx_bytes += length;
5310a3360e1SGeert Uytterhoeven }
5320a3360e1SGeert Uytterhoeven 
5330a3360e1SGeert Uytterhoeven /* The inverse routine to net_open(). */
5340a3360e1SGeert Uytterhoeven static int
5350a3360e1SGeert Uytterhoeven net_close(struct net_device *dev)
5360a3360e1SGeert Uytterhoeven {
5370a3360e1SGeert Uytterhoeven 
5380a3360e1SGeert Uytterhoeven 	writereg(dev, PP_RxCFG, 0);
5390a3360e1SGeert Uytterhoeven 	writereg(dev, PP_TxCFG, 0);
5400a3360e1SGeert Uytterhoeven 	writereg(dev, PP_BufCFG, 0);
5410a3360e1SGeert Uytterhoeven 	writereg(dev, PP_BusCTL, 0);
5420a3360e1SGeert Uytterhoeven 
5430a3360e1SGeert Uytterhoeven 	netif_stop_queue(dev);
5440a3360e1SGeert Uytterhoeven 
5450a3360e1SGeert Uytterhoeven 	free_irq(dev->irq, dev);
5460a3360e1SGeert Uytterhoeven 
5470a3360e1SGeert Uytterhoeven 	/* Update the statistics here. */
5480a3360e1SGeert Uytterhoeven 
5490a3360e1SGeert Uytterhoeven 	return 0;
5500a3360e1SGeert Uytterhoeven 
5510a3360e1SGeert Uytterhoeven }
5520a3360e1SGeert Uytterhoeven 
5530a3360e1SGeert Uytterhoeven /* Get the current statistics.	This may be called with the card open or
5540a3360e1SGeert Uytterhoeven    closed. */
5550a3360e1SGeert Uytterhoeven static struct net_device_stats *
5560a3360e1SGeert Uytterhoeven net_get_stats(struct net_device *dev)
5570a3360e1SGeert Uytterhoeven {
5580a3360e1SGeert Uytterhoeven 	unsigned long flags;
5590a3360e1SGeert Uytterhoeven 
5600a3360e1SGeert Uytterhoeven 	local_irq_save(flags);
5610a3360e1SGeert Uytterhoeven 	/* Update the statistics from the device registers. */
5620a3360e1SGeert Uytterhoeven 	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
5630a3360e1SGeert Uytterhoeven 	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
5640a3360e1SGeert Uytterhoeven 	local_irq_restore(flags);
5650a3360e1SGeert Uytterhoeven 
5660a3360e1SGeert Uytterhoeven 	return &dev->stats;
5670a3360e1SGeert Uytterhoeven }
5680a3360e1SGeert Uytterhoeven 
5690a3360e1SGeert Uytterhoeven static void set_multicast_list(struct net_device *dev)
5700a3360e1SGeert Uytterhoeven {
5710a3360e1SGeert Uytterhoeven 	struct net_local *lp = netdev_priv(dev);
5720a3360e1SGeert Uytterhoeven 
5730a3360e1SGeert Uytterhoeven 	if(dev->flags&IFF_PROMISC)
5740a3360e1SGeert Uytterhoeven 	{
5750a3360e1SGeert Uytterhoeven 		lp->rx_mode = RX_ALL_ACCEPT;
5760a3360e1SGeert Uytterhoeven 	} else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
5770a3360e1SGeert Uytterhoeven 		/* The multicast-accept list is initialized to accept-all, and we
5780a3360e1SGeert Uytterhoeven 		   rely on higher-level filtering for now. */
5790a3360e1SGeert Uytterhoeven 		lp->rx_mode = RX_MULTCAST_ACCEPT;
5800a3360e1SGeert Uytterhoeven 	}
5810a3360e1SGeert Uytterhoeven 	else
5820a3360e1SGeert Uytterhoeven 		lp->rx_mode = 0;
5830a3360e1SGeert Uytterhoeven 
5840a3360e1SGeert Uytterhoeven 	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
5850a3360e1SGeert Uytterhoeven 
5860a3360e1SGeert Uytterhoeven 	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
5870a3360e1SGeert Uytterhoeven 	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
5880a3360e1SGeert Uytterhoeven 	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
5890a3360e1SGeert Uytterhoeven }
5900a3360e1SGeert Uytterhoeven 
5910a3360e1SGeert Uytterhoeven 
5920a3360e1SGeert Uytterhoeven static int set_mac_address(struct net_device *dev, void *addr)
5930a3360e1SGeert Uytterhoeven {
59466dc92edSDanny Kukawka 	struct sockaddr *saddr = addr;
595*9100eb01SDavid S. Miller 	int i;
59666dc92edSDanny Kukawka 
597*9100eb01SDavid S. Miller 	if (!is_valid_ether_addr(saddr->sa_data))
59866dc92edSDanny Kukawka 		return -EADDRNOTAVAIL;
59966dc92edSDanny Kukawka 
600*9100eb01SDavid S. Miller 	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
60166dc92edSDanny Kukawka 	printk("%s: Setting MAC address to %pM\n", dev->name, dev->dev_addr);
60266dc92edSDanny Kukawka 
6030a3360e1SGeert Uytterhoeven 	/* set the Ethernet address */
6040a3360e1SGeert Uytterhoeven 	for (i=0; i < ETH_ALEN/2; i++)
6050a3360e1SGeert Uytterhoeven 		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
6060a3360e1SGeert Uytterhoeven 
6070a3360e1SGeert Uytterhoeven 	return 0;
6080a3360e1SGeert Uytterhoeven }
6090a3360e1SGeert Uytterhoeven 
6100a3360e1SGeert Uytterhoeven #ifdef MODULE
6110a3360e1SGeert Uytterhoeven 
6120a3360e1SGeert Uytterhoeven static struct net_device *dev_cs89x0;
6130a3360e1SGeert Uytterhoeven static int debug;
6140a3360e1SGeert Uytterhoeven 
6150a3360e1SGeert Uytterhoeven module_param(debug, int, 0);
6160a3360e1SGeert Uytterhoeven MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
6170a3360e1SGeert Uytterhoeven MODULE_LICENSE("GPL");
6180a3360e1SGeert Uytterhoeven 
6190a3360e1SGeert Uytterhoeven int __init
6200a3360e1SGeert Uytterhoeven init_module(void)
6210a3360e1SGeert Uytterhoeven {
6220a3360e1SGeert Uytterhoeven 	net_debug = debug;
6230a3360e1SGeert Uytterhoeven         dev_cs89x0 = mac89x0_probe(-1);
6240a3360e1SGeert Uytterhoeven 	if (IS_ERR(dev_cs89x0)) {
6250a3360e1SGeert Uytterhoeven                 printk(KERN_WARNING "mac89x0.c: No card found\n");
6260a3360e1SGeert Uytterhoeven 		return PTR_ERR(dev_cs89x0);
6270a3360e1SGeert Uytterhoeven 	}
6280a3360e1SGeert Uytterhoeven 	return 0;
6290a3360e1SGeert Uytterhoeven }
6300a3360e1SGeert Uytterhoeven 
6310a3360e1SGeert Uytterhoeven void
6320a3360e1SGeert Uytterhoeven cleanup_module(void)
6330a3360e1SGeert Uytterhoeven {
6340a3360e1SGeert Uytterhoeven 	unregister_netdev(dev_cs89x0);
6350a3360e1SGeert Uytterhoeven 	nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT);
6360a3360e1SGeert Uytterhoeven 	free_netdev(dev_cs89x0);
6370a3360e1SGeert Uytterhoeven }
6380a3360e1SGeert Uytterhoeven #endif /* MODULE */
639