/*
net-3-driver for the IBM LAN Adapter/A
This is an extension to the Linux operating system, and is covered by the
same GNU General Public License that covers that work.
Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
alfred.arnold@lancom.de)
This driver is based both on the SK_MCA driver, which is itself based on the
SK_G16 and 3C523 driver.
paper sources:
'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
Hans-Peter Messmer for the basic Microchannel stuff
'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
for help on Ethernet driver programming
'DP83934CVUL-20/25 MHz SONIC-T Ethernet Controller Datasheet' by National
Semiconductor for info on the MAC chip
'LAN Technical Reference Ethernet Adapter Interface Version 1 Release 1.0
Document Number SC30-3661-00' by IBM for info on the adapter itself
Also see http://www.natsemi.com/
special acknowledgements to:
- Bob Eager for helping me out with documentation from IBM
- Jim Shorney for his endless patience with me while I was using
him as a beta tester to trace down the address filter bug ;-)
Missing things:
-> set debug level via ioctl instead of compile-time switches
-> I didn't follow the development of the 2.1.x kernels, so my
assumptions about which things changed with which kernel version
are probably nonsense
History:
Nov 6th, 1999
startup from SK_MCA driver
Dec 6th, 1999
finally got docs about the card. A big thank you to Bob Eager!
Dec 12th, 1999
first packet received
Dec 13th, 1999
recv queue done, tcpdump works
Dec 15th, 1999
transmission part works
Dec 28th, 1999
added usage of the isa_functions for Linux 2.3 . Things should
still work with 2.0.x....
Jan 28th, 2000
in Linux 2.2.13, the version.h file mysteriously didn't get
included. Added a workaround for this. Futhermore, it now
not only compiles as a modules ;-)
Jan 30th, 2000
newer kernels automatically probe more than one board, so the
'startslot' as a variable is also needed here
Apr 12th, 2000
the interrupt mask register is not set 'hard' instead of individually
setting registers, since this seems to set bits that shouldn't be
set
May 21st, 2000
reset interrupt status immediately after CAM load
add a recovery delay after releasing the chip's reset line
May 24th, 2000
finally found the bug in the address filter setup - damned signed
chars!
June 1st, 2000
corrected version codes, added support for the latest 2.3 changes
Oct 28th, 2002
cleaned up for the 2.5 tree <alan@redhat.com>
*************************************************************************/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/mca-legacy.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <asm/processor.h>
#include <asm/io.h>
#define _IBM_LANA_DRIVER_
#include "ibmlana.h"
#undef DEBUG
#define DRV_NAME "ibmlana"
/* ------------------------------------------------------------------------
* global static data - not more since we can handle multiple boards and
* have to pack all state info into the device struct!
* ------------------------------------------------------------------------ */
static char *MediaNames[Media_Count] = {
"10BaseT", "10Base5", "Unknown", "10Base2"
};
/* ------------------------------------------------------------------------
* private subfunctions
* ------------------------------------------------------------------------ */
#ifdef DEBUG
/* dump all registers */
static void dumpregs(struct net_device *dev)
{
int z;
for (z = 0; z < 160; z += 2) {
if (!(z & 15))
printk("REGS: %04x:", z);
printk(" %04x", inw(dev->base_addr + z));
if ((z & 15) == 14)
printk("\n");
}
}
/* dump parts of shared memory - only needed during debugging */
static void dumpmem(struct net_device *dev, u32 start, u32 len)
{
ibmlana_priv *priv = netdev_priv(dev);
int z;
printk("Address %04x:\n", start);
for (z = 0; z < len; z++) {
if ((z & 15) == 0)
printk("%04x:", z);
printk(" %02x", readb(priv->base + start + z));
if ((z & 15) == 15)
printk("\n");
}
if ((z & 15) != 0)
printk("\n");
}
/* print exact time - ditto */
static void PrTime(void)
{
struct timeval tv;
do_gettimeofday(&tv);
printk("%9d:%06d: ", (int) tv.tv_sec, (int) tv.tv_usec);
}
#endif /* DEBUG */
/* deduce resources out of POS registers */
static void getaddrs(int slot, int *base, int *memlen, int *iobase,
int *irq, ibmlana_medium * medium)
{
u_char pos0, pos1;
pos0 = mca_read_stored_pos(slot, 2);
pos1 = mca_read_stored_pos(slot, 3);
*base = 0xc0000 + ((pos1 & 0xf0) << 9);
*memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
*iobase = (pos0 & 0xe0) << 7;
switch (pos0 & 0x06) {
case 0:
*irq = 5<