diff -urN linux-2.4.19-rmk7/arch/arm/config.in linux-2.4.19-rmk7-dnp1/arch/arm/config.in
--- linux-2.4.19-rmk7/arch/arm/config.in	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/arch/arm/config.in	2003-07-05 13:55:50.000000000 +0200
@@ -103,6 +103,7 @@
 fi
 dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600
 #dep_bool '  Consus' CONFIG_SA1100_CONSUS $CONFIG_ARCH_SA1100
+dep_bool '  DNP/1110' CONFIG_SA1100_DNP1110 $CONFIG_ARCH_SA1100
 #dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
 dep_bool '  Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100
 if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then
diff -urN linux-2.4.19-rmk7/arch/arm/def-configs/dnp1110 linux-2.4.19-rmk7-dnp1/arch/arm/def-configs/dnp1110
--- linux-2.4.19-rmk7/arch/arm/def-configs/dnp1110	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/arch/arm/def-configs/dnp1110	2003-07-05 18:43:56.000000000 +0200
@@ -0,0 +1,606 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSAGC is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_ADSBITSYPLUS is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_H3600_SLEEVE is not set
+CONFIG_SA1100_DNP1110=y
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_GUIDEA07 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+# CONFIG_CPU_FREQ is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=32M root=/dev/nfs ip=dhcp"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_ARM_CIRRUS is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+CONFIG_NET_VENDOR_SMC=y
+# CONFIG_WD80x3 is not set
+# CONFIG_ULTRAMCA is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRA32 is not set
+# CONFIG_SMC9194 is not set
+CONFIG_SMC91X=y
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+# CONFIG_SERIAL_OMAHA is not set
+# CONFIG_SERIAL_OMAHA_CONSOLE is not set
+# CONFIG_SERIAL_AT91US3 is not set
+# CONFIG_SERIAL_AT91US3_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
diff -urN linux-2.4.19-rmk7/arch/arm/kernel/head-armv.S linux-2.4.19-rmk7-dnp1/arch/arm/kernel/head-armv.S
--- linux-2.4.19-rmk7/arch/arm/kernel/head-armv.S	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/arch/arm/kernel/head-armv.S	2003-07-05 14:16:05.000000000 +0200
@@ -130,6 +130,14 @@
  */
 		mov	r1, #MACH_TYPE_L7200
 #endif
+#if defined(CONFIG_SA1100_DNP1110)
+/*
+ * FIXME - The SSV bootcode has arcitecture number 255 although they
+ * didn't apply for an official number :-( So we set r1 manually to be
+ * compatible with the original bootcode.
+ */
+                mov     r1, #MACH_TYPE_DNP1110
+#endif
 
 		mov	r0, #F_BIT | I_BIT | MODE_SVC	@ make sure svc mode
 		msr	cpsr_c, r0			@ and all irqs disabled
diff -urN linux-2.4.19-rmk7/arch/arm/mach-sa1100/dnp1110.c linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/dnp1110.c
--- linux-2.4.19-rmk7/arch/arm/mach-sa1100/dnp1110.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/dnp1110.c	2003-07-05 17:30:42.000000000 +0200
@@ -0,0 +1,154 @@
+/*
+ * linux/arch/arm/mach-sa1100/dnp1110.c
+ *
+ * Author: Marco Hasewinkel
+ *
+ * This file contains all DNP/1110 specific tweaks
+ * for "DNP/1110 - mha@ssv <m.hasewinkel@web.de>"
+ */
+ 
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+
+
+#include "generic.h"
+
+static int __init dnp1110_init(void)
+{
+	GPDR = 0x08000000;	/* GPIO0-GPIO26 to Input */
+				/* GPIO27 to Output */
+
+	GAFR = 0x08000000;	/* alternate function on GPIO27 */
+
+	TUCR = 0x20000000;	/* set 3.6864 MHz out to GPIO27 */
+
+	PPDR = 0x0000008A;	/* COM1 CTS+DSR+DCD+RI to Input */
+				/* COM1 RTS+DTR to Output */
+				/* Vpp is Output and RCM Input */
+				/* Port C to Input */
+
+	PPSR &= ~0x80;		/* Vpp disable */
+
+	Ser1SDCR0 |= SDCR0_UART;/* Select UART function in serial port 1 */
+
+	MECR = 0x21082108;	/* PCMCIA Socket 0 & 1 Timing - FIXME !!! */
+				/* cycle time 621ns (=(7*8+8)*9.7ns) */
+	
+	MECR &= ~0x0000FFFF;	/* SMSC91111 LAN chip */
+	MECR |= 0x00000421;	/* cycle time 146ns =(7*1+8)*9.7ns */
+	
+	return 0;
+}
+
+__initcall(dnp1110_init);
+
+
+static void __init
+fixup_dnp1110(struct machine_desc *desc, struct param_struct *params,
+	  char **cmdline, struct meminfo *mi)
+{
+	SET_BANK(0, 0xc0000000, 32*1024*1024);	/* DNP/1110 32MB */
+//	SET_BANK(0, 0xc0000000, 16*1024*1024);	/* DNP/1110 16MB */
+	mi->nr_banks = 1;
+
+	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
+	setup_ramdisk(1, 0, 0, 8192);
+	setup_initrd(0xc0400000, 3*1024*1024);	/* max 3MB INITRAMDISK */
+}
+
+static struct map_desc dnp1110_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+  { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* SMSC91111 LAN controller */
+  LAST_DESC
+};
+
+static void dnp1110_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	u_int mdm_ctl0 = PPSR;			// get Pin State Register
+
+	if (port->mapbase == _Ser1UTCR0) {
+		if (mctrl & TIOCM_RTS)
+			mdm_ctl0 &= ~(1<<1);	// clear Pin LDD1 = RTS
+		else
+			mdm_ctl0 |= (1<<1);	// set Pin LDD1 = RTS
+
+		if (mctrl & TIOCM_DTR)
+			mdm_ctl0 &= ~(1<<3);	// clear Pin LDD3 = DTR
+		else
+			mdm_ctl0 |= (1<<3);	// set Pin LDD3 = DTR
+	}
+	else
+	    return;
+
+	PPSR = mdm_ctl0;			// set Pin State Register
+}
+
+static u_int dnp1110_get_mctrl(struct uart_port *port)
+{
+	u_int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CD;
+
+	u_int mdm_ctl1 = PPSR;			// get Pin State Register
+
+	if (port->mapbase == _Ser1UTCR0) {
+		if (mdm_ctl1 & (1<<0))		// Pin LDD0 = CTS
+			ret &= ~TIOCM_CTS;
+		if (mdm_ctl1 & (1<<2))		// Pin LDD2 = DSR
+			ret &= ~TIOCM_DSR;
+		if (mdm_ctl1 & (1<<4))		// Pin LDD4 = DCD
+			ret &= ~TIOCM_CD;
+	}
+
+	return ret;
+}
+
+static struct sa1100_port_fns dnp1110_port_fns __initdata = {
+	set_mctrl:	dnp1110_set_mctrl,
+	get_mctrl:	dnp1110_get_mctrl,
+};
+
+static void __init dnp1110_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(dnp1110_io_desc);
+
+	sa1100_register_uart_fns(&dnp1110_port_fns);
+	sa1100_register_uart(0, 1);	/* COM1 = ttySA0 (SA UART 1) */
+	sa1100_register_uart(1, 3);	/* COM2 = ttySA1 (SA UART 3) */
+}
+
+static void __init dnp1110_init_irq(void)
+{
+
+/* first default SA11X0 IRQ mapping */
+    sa1100_init_irq();
+
+/* then dnp/1110 special IRQ mapping */
+    set_GPIO_IRQ_edge(GPIO_GPIO(0), GPIO_RISING_EDGE);	/* USER INT 1 */
+    set_GPIO_IRQ_edge(GPIO_GPIO(1), GPIO_RISING_EDGE);	/* USER INT 2 */
+    set_GPIO_IRQ_edge(GPIO_GPIO(2), GPIO_RISING_EDGE);	/* USER INT 3 */
+    set_GPIO_IRQ_edge(GPIO_GPIO(3), GPIO_RISING_EDGE);	/* USER INT 4 */
+    set_GPIO_IRQ_edge(GPIO_GPIO(4), GPIO_RISING_EDGE);	/* USER INT 5 */
+
+    set_GPIO_IRQ_edge(GPIO_GPIO(5), GPIO_RISING_EDGE);	/* LAN */
+    set_GPIO_IRQ_edge(GPIO_GPIO(6), GPIO_RISING_EDGE);	/* SSV only */
+}
+
+MACHINE_START(DNP1110, "DNP/1110 - SSV Embedded Systems")
+	MAINTAINER("Marco Hasewinkel <m.hasewinkel@web.de>; Robert Schwebel <r.schwebel@pengutronix.de>")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_dnp1110)
+	MAPIO(dnp1110_map_io)
+	INITIRQ(dnp1110_init_irq)
+MACHINE_END
diff -urN linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds.c linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds.c
--- linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds.c	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds.c	2003-07-05 13:55:50.000000000 +0200
@@ -29,6 +29,8 @@
 		leds_event = brutus_leds_event;
 	if (machine_is_cerf())
 		leds_event = cerf_leds_event;
+	if (machine_is_dnp1110())
+		leds_event = dnp1110_leds_event;
 	if (machine_is_flexanet())
 		leds_event = flexanet_leds_event;
 	if (machine_is_frodo())
diff -urN linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds-dnp1110.c linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds-dnp1110.c
--- linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds-dnp1110.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds-dnp1110.c	2003-07-05 13:55:50.000000000 +0200
@@ -0,0 +1,114 @@
+/*
+ * linux/arch/arm/mach-sa1100/leds-dnp1110.c
+ *
+ * Author: Rolf Offermanns <rof@sysgo.de>
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	1
+#define LED_STATE_CLAIMED	2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+#define LED_D0          GPIO_GPIO(8)
+#define LED_D1          GPIO_GPIO(9)
+#define LED_D2          GPIO_GPIO(10)
+#define LED_D3          GPIO_GPIO(11)
+#define LED_MASK        (LED_D0|LED_D1|LED_D2|LED_D3)
+
+
+void dnp1110_leds_event(led_event_t evt)
+{
+        unsigned long flags;
+
+	local_irq_save(flags);
+
+        switch (evt) {
+        case led_start:
+				GPDR = (GPDR|0x0000ff00);
+				GPCR = 0x0000ff00;
+                hw_led_state = LED_MASK;
+                led_state = LED_STATE_ENABLED;
+                break;
+
+        case led_stop:
+                led_state &= ~LED_STATE_ENABLED;
+                break;
+
+        case led_claim:
+                led_state |= LED_STATE_CLAIMED;
+                hw_led_state = LED_MASK;
+                break;
+        case led_release:
+                led_state &= ~LED_STATE_CLAIMED;
+                hw_led_state = LED_MASK;
+                break;
+
+#ifdef CONFIG_LEDS_TIMER
+        case led_timer:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state ^= LED_D0;
+                break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+        case led_idle_start:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D1;
+                break;
+
+        case led_idle_end:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D1;
+                break;
+#endif
+        case led_green_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D2;
+                break;
+
+        case led_green_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D2;
+                break;
+
+        case led_amber_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D3;
+                break;
+
+        case led_amber_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D3;
+                break;
+
+        case led_red_on:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state &= ~LED_D1;
+                break;
+
+        case led_red_off:
+                if (!(led_state & LED_STATE_CLAIMED))
+                        hw_led_state |= LED_D1;
+                break;
+
+        default:
+                break;
+        }
+
+        if  (led_state & LED_STATE_ENABLED) {
+                GPSR = hw_led_state;
+                GPCR = hw_led_state ^ LED_MASK;
+        }
+
+	local_irq_restore(flags);
+}
diff -urN linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds.h linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds.h
--- linux-2.4.19-rmk7/arch/arm/mach-sa1100/leds.h	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/leds.h	2003-07-05 13:55:50.000000000 +0200
@@ -5,6 +5,7 @@
 extern void consus_leds_event(led_event_t evt);
 extern void brutus_leds_event(led_event_t evt);
 extern void cerf_leds_event(led_event_t evt);
+extern void dnp1110_leds_event(led_event_t evt);
 extern void flexanet_leds_event(led_event_t evt);
 extern void frodo_leds_event(led_event_t evt);
 extern void graphicsclient_leds_event(led_event_t evt);
diff -urN linux-2.4.19-rmk7/arch/arm/mach-sa1100/Makefile linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/Makefile
--- linux-2.4.19-rmk7/arch/arm/mach-sa1100/Makefile	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/arch/arm/mach-sa1100/Makefile	2003-07-05 13:55:50.000000000 +0200
@@ -53,6 +53,7 @@
 obj-$(CONFIG_SA1100_CEP) += cep.o
 obj-$(CONFIG_SA1100_CERF) += cerf.o
 obj-$(CONFIG_SA1100_CONSUS) += consus.o
+obj-$(CONFIG_SA1100_DNP1110) += dnp1110.o
 obj-$(CONFIG_SA1100_EMPEG) += empeg.o
 obj-$(CONFIG_SA1100_FLEXANET) += flexanet.o
 obj-$(CONFIG_SA1100_FREEBIRD) += freebird.o
@@ -87,6 +88,7 @@
 leds-$(CONFIG_SA1100_ASSABET) += leds-assabet.o
 leds-$(CONFIG_SA1100_BRUTUS) += leds-brutus.o
 leds-$(CONFIG_SA1100_CERF) += leds-cerf.o
+leds-$(CONFIG_SA1100_DNP1110) += leds-dnp1110.o
 leds-$(CONFIG_SA1100_CONSUS) += leds-consus.o
 leds-$(CONFIG_SA1100_FLEXANET) += leds-flexanet.o
 leds-$(CONFIG_SA1100_FRODO) += leds-frodo.o
diff -urN linux-2.4.19-rmk7/Documentation/Configure.help linux-2.4.19-rmk7-dnp1/Documentation/Configure.help
--- linux-2.4.19-rmk7/Documentation/Configure.help	2003-07-05 13:46:34.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/Documentation/Configure.help	2003-07-05 13:55:50.000000000 +0200
@@ -22941,6 +22941,18 @@
   and business machine applications. Say Y here if you require support for
   this target.
 
+SSV Software Systems GmbH DIL/Net-PC DNP/1110
+CONFIG_SA1100_DNP1110
+  The SSV Software Systems' DIL/Net-PC DNP/1110 is an IntelŪ StrongArmŪ 
+  SA-1110 based embedded PC which has the same size as the standard 
+  64 pin JEDEC DIL case. It is pin compatible to it's x86 (AMD Elan) 
+  based brother DNP/1486. 
+
+  http://www.dilnetpc.com                         (The actual hardware)
+  http://www.pengutronix.de/software/dnp_en.html  (Tips and Tricks)
+
+  Say Y here if you require support fot this target. 
+
 # Choice: cerf_ram
 Cerf on-board RAM size
 CONFIG_SA1100_CERF_8MB
diff -urN linux-2.4.19-rmk7/drivers/net/Config.in linux-2.4.19-rmk7-dnp1/drivers/net/Config.in
--- linux-2.4.19-rmk7/drivers/net/Config.in	2003-07-05 13:46:38.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/drivers/net/Config.in	2003-07-05 13:58:36.000000000 +0200
@@ -110,6 +110,7 @@
       dep_tristate '    SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA
       dep_tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
       dep_tristate '    SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
+      tristate     '    SMC 91C9x/91C1xx support' CONFIG_SMC91X
    fi
    bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
    if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
diff -urN linux-2.4.19-rmk7/drivers/net/Makefile linux-2.4.19-rmk7-dnp1/drivers/net/Makefile
--- linux-2.4.19-rmk7/drivers/net/Makefile	2003-07-05 13:46:38.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/drivers/net/Makefile	2003-07-05 13:58:07.000000000 +0200
@@ -116,6 +116,7 @@
 obj-$(CONFIG_SK_G16) += sk_g16.o
 obj-$(CONFIG_HP100) += hp100.o
 obj-$(CONFIG_SMC9194) += smc9194.o
+obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
 obj-$(CONFIG_ARM_ETHERH) += 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
diff -urN linux-2.4.19-rmk7/drivers/net/smc91x.c linux-2.4.19-rmk7-dnp1/drivers/net/smc91x.c
--- linux-2.4.19-rmk7/drivers/net/smc91x.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/drivers/net/smc91x.c	2003-07-05 18:37:28.000000000 +0200
@@ -0,0 +1,2165 @@
+/*
+ * NOTE: This driver is Nicolas Pitre's version, taken from 2.4.19-rmk7-pxa2. 
+ *       Some DNP specific tweaks have been added. The driver will probably
+ *       be merged with the mainline driver asap. [Robert Schwebel]
+ */
+
+/*------------------------------------------------------------------------
+ . smc91x.c
+ . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
+ .
+ . Copyright (C) 1996 by Erik Stahlman
+ . Copyright (C) 2001 Standard Microsystems Corporation
+ .	Developed by Simple Network Magic Corporation
+ . Copyright (C) 2003 Monta Vista Software, Inc.
+ .	Unified SMC91x driver by Nicolas Pitre
+ .
+ . This program is free software; you can redistribute it and/or modify
+ . it under the terms of the GNU General Public License as published by
+ . the Free Software Foundation; either version 2 of the License, or
+ . (at your option) any later version.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . Arguments:
+ . 	io	= for the base address
+ .	irq	= for the IRQ
+ .	nowait	= 0 for normal wait states, 1 eliminates additional wait states
+ .
+ . original author:
+ . 	Erik Stahlman <erik@vt.edu>
+ .
+ . hardware multicast code:
+ .    Peter Cammaert <pc@denkart.be>
+ .
+ . contributors:
+ . 	Daris A Nevil <dnevil@snmc.com>
+ .      Nicolas Pitre <nico@cam.org>
+ .
+ . History:
+ .   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet
+ .   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ"
+ .   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111
+ .   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111
+ .   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111
+ .   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support
+ .   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races,
+ .                                more bus abstraction, big cleanup, etc.
+ ----------------------------------------------------------------------------*/
+
+static const char version[] =
+	"smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
+
+/* Debugging level */
+#ifndef SMC_DEBUG
+#define SMC_DEBUG		0
+#endif
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+
+#include "smc91x.h"
+
+
+#ifdef CONFIG_ISA
+/*
+ . the LAN91C111 can be at any of the following port addresses.  To change,
+ . for a slightly different card, you can add it to the array.  Keep in
+ . mind that the array must end in zero.
+*/
+static unsigned int smc_portlist[] __initdata = {
+	0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
+	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
+};
+#endif  /* CONFIG_ISA */
+
+#ifndef SMC_IOADDR
+# define SMC_IOADDR		-1
+#endif
+static int io = SMC_IOADDR;
+
+#ifndef SMC_IRQ
+# define SMC_IRQ		-1
+#endif
+static int irq = SMC_IRQ;
+
+#ifndef SMC_NOWAIT
+# define SMC_NOWAIT		0
+#endif
+static int nowait = SMC_NOWAIT;
+
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(nowait, "i");
+MODULE_PARM_DESC(io, "I/O base address");
+MODULE_PARM_DESC(irq, "IRQ number");
+MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
+
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver.  If you are changing anything
+ . here with the SMC stuff, you should have the datasheet and know
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+#define CARDNAME "LAN91x"
+
+// Use power-down feature of the chip
+#define POWER_DOWN		1
+
+/*
+ . Wait time for memory to be free.  This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME	16
+
+/*
+ . This selects whether TX packets are sent one by one to the SMC91x internal
+ . memory ans throttled until transmission completes.  This may prevent
+ . RX overruns a litle by keeping much of the memory free for RX packets
+ . but to the expense of reduced TX throughput and increased IRQ overhead.
+ . Note this is not a cure for a too slow data bus or too high IRQ latency.
+ */
+#define THROTTLE_TX_PKTS	0
+
+
+/* store this information for the driver.. */
+struct smc_local {
+
+	// If I have to wait until memory is available to send
+	// a packet, I will store the skbuff here, until I get the
+	// desired memory.  Then, I'll send it out and free it.
+	struct sk_buff *saved_skb;
+
+ 	// these are things that the kernel wants me to keep, so users
+	// can find out semi-useless statistics of how well the card is
+	// performing
+	struct net_device_stats stats;
+
+	// version/revision of the SMC91x chip
+	int version;
+
+	// Set to true during the auto-negotiation sequence
+	int autoneg_active;
+
+	// Address of our PHY port
+	int	phyaddr;
+
+	// Type of PHY
+	int	phytype;
+
+	// Last contents of PHY Register 18
+	int	lastPhy18;
+
+	// Contains the current active transmission mode
+	int	tcr_cur_mode;
+
+	// Contains the current active receive mode
+	int	rcr_cur_mode;
+
+	// Contains the current active receive/phy mode
+	int	rpc_cur_mode;
+	int	ctl_autoneg;
+	int	ctl_rfduplx;
+	int	ctl_rspeed;
+
+#ifdef CONFIG_PM
+	struct	pm_dev* pm;
+#endif
+
+};
+
+
+#if SMC_DEBUG > 2
+#define PRINTK3(args...)  printk(args)
+#else
+#define PRINTK3(args...)  do { } while(0)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(args...)  printk(args)
+#else
+#define PRINTK2(args...)  do { } while(0)
+#endif
+
+#if SMC_DEBUG > 0
+#define PRINTK1(args...)  printk(args)
+#define PRINTK(args...)   printk(args)
+#else
+#define PRINTK1(args...)  do { } while(0)
+#define PRINTK(args...)   printk(KERN_DEBUG args)
+#endif
+
+#if SMC_DEBUG > 3
+static void PRINT_PKT(u_char *buf, int length)
+{
+	int i;
+	int remainder;
+	int lines;
+
+	lines = length / 16;
+	remainder = length % 16;
+
+	for (i = 0; i < lines ; i ++) {
+		int cur;
+		for (cur = 0; cur < 8; cur++) {
+			u_char a, b;
+			a = *buf++;
+			b = *buf++;
+			printk("%02x%02x ", a, b);
+		}
+		printk("\n");
+	}
+	for (i = 0; i < remainder/2 ; i++) {
+		u_char a, b;
+		a = *buf++;
+		b = *buf++;
+		printk("%02x%02x ", a, b );
+	}
+	printk("\n");
+}
+#else
+#define PRINT_PKT(x...)  do { } while(0)
+#endif
+
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) do {						\
+	unsigned long flags;						\
+	unsigned char mask;						\
+	local_irq_save(flags);						\
+	mask = SMC_GET_INT_MASK();					\
+	mask |= (x);							\
+	SMC_SET_INT_MASK(mask);						\
+	local_irq_restore(flags);					\
+} while (0)
+
+/* this disables an interrupt from the interrupt mask register */
+#define SMC_DISABLE_INT(x) do {						\
+	unsigned long flags;						\
+	unsigned char mask;						\
+	local_irq_save(flags);						\
+	mask = SMC_GET_INT_MASK();					\
+	mask &= ~(x);							\
+	SMC_SET_INT_MASK(mask);						\
+	local_irq_restore(flags);					\
+} while (0)
+
+/* wait while MMU is busy */
+#define SMC_WAIT_MMU_BUSY() do {					\
+	if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) {				\
+		unsigned long timeout = jiffies + 2;			\
+		while (SMC_GET_MMU_CMD() & MC_BUSY) {			\
+			if (time_after(jiffies, timeout)) {		\
+				printk("%s: timeout %s line %d\n",	\
+					dev->name, __FILE__, __LINE__);	\
+				break;					\
+			}						\
+		}							\
+	}								\
+} while (0)
+
+
+/* this does a soft reset on the device */
+static void
+smc_reset(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	/* This resets the registers mostly to defaults, but doesn't
+	   affect EEPROM.  That seems unnecessary */
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_RCR( RCR_SOFTRST );
+
+	/* Setup the Configuration Register */
+	/* This is necessary because the CONFIG_REG is not affected */
+	/* by a soft reset */
+	SMC_SELECT_BANK( 1 );
+	SMC_SET_CONFIG( CONFIG_DEFAULT );
+
+	/* Setup for fast accesses if requested */
+	/* If the card/system can't handle it then there will */
+	/* be no recovery except for a hard reset or power cycle */
+	if (nowait)
+		SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );
+
+#ifdef POWER_DOWN
+	/* Release from possible power-down state */
+	/* Configuration register is not affected by Soft Reset */
+	SMC_SELECT_BANK( 1 );
+	SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN );
+#endif
+
+	/* this should pause enough for the chip to be happy */
+	udelay(1);
+
+	/* Disable transmit and receive functionality */
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_RCR( RCR_CLEAR );
+	SMC_SET_TCR( TCR_CLEAR );
+
+	/* set the control register to automatically
+	   release successfully transmitted packets, to make the best
+	   use out of our limited memory */
+	SMC_SELECT_BANK( 1 );
+#if ! THROTTLE_TX_PKTS
+	SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE );
+#else
+	SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE );
+#endif
+
+	/* Disable all interrupts */
+	SMC_SELECT_BANK( 2 );
+	SMC_SET_INT_MASK( 0 );
+
+	/* Reset the MMU */
+	SMC_SET_MMU_CMD( MC_RESET );
+	SMC_WAIT_MMU_BUSY();
+}
+
+/* Enable Interrupts, Receive, and Transmit */
+static void
+smc_enable(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int mask;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	/* see the header file for options in TCR/RCR DEFAULT*/
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_TCR( lp->tcr_cur_mode );
+	SMC_SET_RCR( lp->rcr_cur_mode );
+
+	/* now, enable interrupts */
+	mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
+	if (lp->version >= 0x70)
+		mask |= IM_MDINT;
+	SMC_SELECT_BANK( 2 );
+	SMC_SET_INT_MASK( mask );
+}
+
+/* this puts the device in an inactive state */
+static void
+smc_shutdown(unsigned long ioaddr)
+{
+	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
+
+	/* no more interrupts for me */
+	SMC_SELECT_BANK( 2 );
+	SMC_SET_INT_MASK( 0 );
+
+	/* and tell the card to stay away from that nasty outside world */
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_RCR( RCR_CLEAR );
+	SMC_SET_TCR( TCR_CLEAR );
+
+#ifdef POWER_DOWN
+	/* finally, shut the chip down */
+	SMC_SELECT_BANK( 1 );
+	SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN );
+#endif
+}
+
+/* This is the procedure to handle the receipt of a packet. */
+static inline void 
+smc_rcv(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned int packet_number, status, packet_len;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	packet_number = SMC_GET_RXFIFO();
+	if (unlikely(packet_number & RXFIFO_REMPTY)) {
+		PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);
+		return;
+	}
+
+	/* read from start of packet */
+	SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC );
+
+	/* First two words are status and packet length */
+	SMC_GET_PKT_HDR(status, packet_len);
+	packet_len &= 0x07ff;  /* mask off top bits */
+	PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",
+		dev->name, packet_number, status,
+		packet_len, packet_len);
+
+	if (unlikely(status & RS_ERRORS)) {
+		lp->stats.rx_errors++;
+		if (status & RS_ALGNERR)
+			lp->stats.rx_frame_errors++;
+		if (status & (RS_TOOSHORT | RS_TOOLONG))
+			lp->stats.rx_length_errors++;
+		if (status & RS_BADCRC)
+			lp->stats.rx_crc_errors++;
+	} else {
+		struct sk_buff *skb;
+		unsigned char *data;
+		unsigned int data_len;
+
+		/* set multicast stats */
+		if (status & RS_MULTICAST)
+			lp->stats.multicast++;
+
+		/*
+		 * Actual payload is packet_len - 4 (or 3 if odd byte).
+		 * We want skb_reserve(2) and the final ctrl word
+		 * (2 bytes, possibly containing the payload odd byte).
+		 * Ence packet_len - 4 + 2 + 2.
+		 */
+		skb = dev_alloc_skb(packet_len);
+		if (unlikely(skb == NULL)) {
+			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+				dev->name);
+			lp->stats.rx_dropped++;
+			goto done;
+		}
+
+		/* Align IP header to 32 bits */
+		skb_reserve(skb, 2);
+
+		/* BUG: the LAN91C111 rev A never sets this bit. Force it. */
+		if (lp->version == 0x90)
+			status |= RS_ODDFRAME;
+
+		/*
+		 * If odd length: packet_len - 3,
+		 * otherwise packet_len - 4.
+		 */
+		data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4);
+		data = skb_put(skb, data_len);
+		SMC_PULL_DATA(data, packet_len - 2);
+
+		PRINT_PKT(data, packet_len - 2);
+
+		dev->last_rx = jiffies;
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+		lp->stats.rx_bytes += data_len;
+	}
+
+done:
+	SMC_WAIT_MMU_BUSY();
+	SMC_SET_MMU_CMD( MC_RELEASE );
+}
+
+/*
+ * This is called to actually send a packet to the chip.
+ * Returns non-zero when successful.
+ */
+static void
+smc_hardware_send_packet(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	struct sk_buff *skb = lp->saved_skb;
+	unsigned int packet_no, len;
+	unsigned char *buf;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	if (unlikely(!skb)) {
+		printk ("%s: In XMIT with no packet to send\n", dev->name);
+		return;
+	}
+
+	packet_no = SMC_GET_AR();
+	if (unlikely(packet_no & AR_FAILED)) {
+		printk("%s: Memory allocation failed.\n", dev->name);
+		lp->saved_skb = NULL;
+		lp->stats.tx_errors++;
+		lp->stats.tx_fifo_errors++;
+		dev_kfree_skb_any(skb);
+		return;
+	}
+
+	/* point to the beginning of the packet */
+	SMC_SET_PN( packet_no );
+	SMC_SET_PTR( PTR_AUTOINC );
+
+	buf = skb->data;
+	len = skb->len;
+	PRINTK2("%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 9x%p\n",
+		dev->name, packet_no, len, len, buf);
+	PRINT_PKT(buf, len);
+
+	/*
+	 * Send the packet length ( +6 for status words, length, and ctl.
+	 * The card will pad to 64 bytes with zeroes if packet is too small.
+	 */
+	SMC_PUT_PKT_HDR(0, len + 6);
+
+	/* send the actual data */
+	SMC_PUSH_DATA(buf, len & ~1);
+
+	/* Send final ctl word with the last byte if there is one */
+	SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG );
+
+	/* and let the chipset deal with it */
+	SMC_SET_MMU_CMD( MC_ENQUEUE );
+	SMC_ACK_INT( IM_TX_EMPTY_INT );
+
+	dev->trans_start = jiffies;
+	dev_kfree_skb_any(skb);
+	lp->saved_skb = NULL;
+	lp->stats.tx_packets++;
+	lp->stats.tx_bytes += len;
+}
+
+/*
+ . Since I am not sure if I will have enough room in the chip's ram
+ . to store the packet, I call this routine which either sends it
+ . now, or set the card to generates an interrupt when ready
+ . for the packet.
+ */
+static int
+smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev )
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned int numPages, poll_count, status, saved_bank;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	if (unlikely(lp->saved_skb != NULL)) {
+		/* THIS SHOULD NEVER HAPPEN. */
+		printk( KERN_CRIT
+			"%s: Bad Craziness - sent packet while busy.\n",
+			dev->name );
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		return 1;
+	}
+	lp->saved_skb = skb;
+
+	/*
+	** The MMU wants the number of pages to be the number of 256 bytes
+	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+	**
+	** The 91C111 ignores the size bits, but the code is left intact
+	** for backwards and future compatibility.
+	**
+	** Pkt size for allocating is data length +6 (for additional status
+	** words, length and ctl!)
+	**
+	** If odd size then last byte is included in ctl word.
+	*/
+	numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
+	if (unlikely(numPages > 7)) {
+		printk("%s: Far too big packet error.\n", dev->name);
+		lp->saved_skb = NULL;
+		lp->stats.tx_errors++;
+		lp->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* now, try to allocate the memory */
+	saved_bank = SMC_CURRENT_BANK();
+	SMC_SELECT_BANK( 2 );
+	SMC_SET_MMU_CMD( MC_ALLOC | numPages );
+
+	/*
+	 * Poll the chip for a short amount of time in case the
+	 * allocation succeeds quickly.
+	 */
+	poll_count = MEMORY_WAIT_TIME;
+	do {
+		status = SMC_GET_INT();
+		if (status & IM_ALLOC_INT) {
+			SMC_ACK_INT( IM_ALLOC_INT );
+  			break;
+		}
+   	} while (--poll_count);
+
+   	if (!poll_count) {
+		/* oh well, wait until the chip finds memory later */
+		netif_stop_queue(dev);
+		PRINTK2("%s: TX memory allocation deferred.\n", dev->name);
+		SMC_ENABLE_INT( IM_ALLOC_INT );
+   	} else {
+		/* Send current packet immediately.. */
+#if THROTTLE_TX_PKTS
+		netif_stop_queue(dev);
+#endif
+		smc_hardware_send_packet(dev);
+		SMC_ENABLE_INT( IM_TX_INT | IM_TX_EMPTY_INT );
+	}
+
+	SMC_SELECT_BANK( saved_bank );
+	return 0;
+}
+
+/*
+ . This handles a TX interrupt, which is only called when an error
+ . relating to a packet is sent or CTL_AUTO_RELEASE is not set.
+*/
+static void
+smc_tx(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned int saved_packet, packet_no, tx_status, pkt_len;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	/* If the TX FIFO is empty then nothing to do */
+	packet_no = SMC_GET_TXFIFO();
+	if (unlikely(packet_no & TXFIFO_TEMPTY)) {
+		PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name);
+		return;
+	}
+
+	/* select packet to read from */
+	saved_packet = SMC_GET_PN();
+	SMC_SET_PN( packet_no );
+
+	/* read the first word (status word) from this packet */
+	SMC_SET_PTR( PTR_AUTOINC | PTR_READ );
+	SMC_GET_PKT_HDR(tx_status, pkt_len);
+	PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n",
+		dev->name, tx_status, packet_no);
+
+	if (!(tx_status & TS_SUCCESS))
+		lp->stats.tx_errors++;
+	if (tx_status & TS_LOSTCAR)
+		lp->stats.tx_carrier_errors++;
+	if (tx_status & TS_LATCOL) {
+		printk( KERN_DEBUG
+			"%s: Late collision occurred on last xmit.\n",
+			dev->name);
+		lp->stats.tx_window_errors++;
+	}
+
+	/* kill the packet */
+	SMC_WAIT_MMU_BUSY();
+	SMC_SET_MMU_CMD( MC_FREEPKT );
+
+	/* Don't restore Packet Number Reg until busy bit is cleared */
+	SMC_WAIT_MMU_BUSY();
+	SMC_SET_PN( saved_packet );
+
+	/* re-enable transmit */
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_TCR( lp->tcr_cur_mode );
+	SMC_SELECT_BANK( 2 );
+}
+
+
+//---PHY CONTROL AND CONFIGURATION-----------------------------------------
+
+/*------------------------------------------------------------
+ . Debugging function for viewing MII Management serial bitstream
+ .-------------------------------------------------------------*/
+#if SMC_DEBUG > 3
+static void
+PRINT_MII_STREAM(u_char *bits, int size)
+{
+	int i;
+
+	printk("BIT#:");
+	for (i = 0; i < size; ++i)
+		printk("%d", i%10);
+
+	printk("\nMDOE:");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDOE)
+			printk("1");
+		else
+			printk("0");
+	}
+
+	printk("\nMDO :");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDO)
+			printk("1");
+		else
+			printk("0");
+	}
+
+	printk("\nMDI :");
+	for (i = 0; i < size; ++i) {
+		if (bits[i] & MII_MDI)
+			printk("1");
+		else
+			printk("0");
+	}
+
+	printk("\n");
+}
+#else
+#define PRINT_MII_STREAM(x...)
+#endif
+
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+static int
+smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg)
+{
+	int oldBank;
+	int i, mask, mii_reg;
+	u_char bits[64];
+	int input_idx, phydata;
+	int clk_idx = 0;
+
+	// 32 consecutive ones on MDO to establish sync
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Start code <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Read command <10>
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+	bits[clk_idx++] = MII_MDOE;
+
+	// Output the PHY address, msb first
+	mask = 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+	}
+
+	// Output the phy register number, msb first
+	mask = 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+	}
+
+	// Tristate and turnaround (2 bit times)
+	bits[clk_idx++] = 0;
+	//bits[clk_idx++] = 0;
+
+	// Input starts at this bit time
+	input_idx = clk_idx;
+
+	// Will input 16 bits
+	for (i = 0; i < 16; ++i)
+		bits[clk_idx++] = 0;
+
+	// Final clock bit
+	bits[clk_idx++] = 0;
+
+	// Save the current bank
+	oldBank = SMC_CURRENT_BANK();
+
+	// Select bank 3
+	SMC_SELECT_BANK( 3 );
+
+	// Get the current MII register value
+	mii_reg = SMC_GET_MII();
+
+	// Turn off all MII Interface bits
+	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+	// Clock all 64 cycles
+	for (i = 0; i < sizeof bits; ++i) {
+		// Clock Low - output data
+		SMC_SET_MII( mii_reg | bits[i] );
+		udelay(50);
+
+		// Clock Hi - input data
+		SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
+		udelay(50);
+		bits[i] |= SMC_GET_MII() & MII_MDI;
+	}
+
+	// Return to idle state
+	// Set clock to low, data to low, and output tristated
+	SMC_SET_MII( mii_reg );
+	udelay(50);
+
+	// Restore original bank select
+	SMC_SELECT_BANK( oldBank );
+
+	// Recover input data
+	phydata = 0;
+	for (i = 0; i < 16; ++i) {
+		phydata <<= 1;
+
+		if (bits[input_idx++] & MII_MDI)
+			phydata |= 0x0001;
+	}
+
+	PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+		__FUNCTION__, phyaddr, phyreg, phydata);
+	PRINT_MII_STREAM(bits, sizeof(bits));
+
+	return phydata;
+}
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void
+smc_write_phy_register( unsigned long ioaddr, int phyaddr,
+			int phyreg, int phydata )
+{
+	int oldBank;
+	int i, mask, mii_reg;
+	u_char bits[65];
+	int clk_idx = 0;
+
+	// 32 consecutive ones on MDO to establish sync
+	for (i = 0; i < 32; ++i)
+		bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Start code <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Write command <01>
+	bits[clk_idx++] = MII_MDOE;
+	bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+	// Output the PHY address, msb first
+	mask = 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyaddr & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+	}
+
+	// Output the phy register number, msb first
+	mask = 0x10;
+	for (i = 0; i < 5; ++i) {
+		if (phyreg & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+	}
+
+	// Tristate and turnaround (2 bit times)
+	bits[clk_idx++] = 0;
+	bits[clk_idx++] = 0;
+
+	// Write out 16 bits of data, msb first
+	mask = 0x8000;
+	for (i = 0; i < 16; ++i) {
+		if (phydata & mask)
+			bits[clk_idx++] = MII_MDOE | MII_MDO;
+		else
+			bits[clk_idx++] = MII_MDOE;
+
+		// Shift to next lowest bit
+		mask >>= 1;
+	}
+
+	// Final clock bit (tristate)
+	bits[clk_idx++] = 0;
+
+	// Save the current bank
+	oldBank = SMC_CURRENT_BANK();
+
+	// Select bank 3
+	SMC_SELECT_BANK( 3 );
+
+	// Get the current MII register value
+	mii_reg = SMC_GET_MII();
+
+	// Turn off all MII Interface bits
+	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+	// Clock all cycles
+	for (i = 0; i < sizeof bits; ++i) {
+		// Clock Low - output data
+		SMC_SET_MII( mii_reg | bits[i] );
+		udelay(50);
+
+		// Clock Hi - input data
+		SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
+		udelay(50);
+		bits[i] |= SMC_GET_MII() & MII_MDI;
+	}
+
+	// Return to idle state
+	// Set clock to low, data to low, and output tristated
+	SMC_SET_MII( mii_reg );
+	udelay(50);
+
+	// Restore original bank select
+	SMC_SELECT_BANK( oldBank );
+
+	PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+		__FUNCTION__, phyaddr, phyreg, phydata);
+	PRINT_MII_STREAM(bits, sizeof(bits));
+}
+
+
+/*------------------------------------------------------------
+ . Finds and reports the PHY address
+ .-------------------------------------------------------------*/
+static int smc_detect_phy(struct net_device* dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	int phy_id1, phy_id2;
+	int phyaddr;
+	int found = 0;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	// Scan all 32 PHY addresses if necessary
+	for (phyaddr = 0; phyaddr < 32; ++phyaddr) {
+		// Read the PHY identifiers
+		phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
+		phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
+
+		PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n",
+			dev->name, phy_id1, phy_id2);
+
+		// Make sure it is a valid identifier
+		if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
+		    (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) {
+			if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) {
+				// Save the PHY's address
+				lp->phyaddr = phyaddr;
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		PRINTK("%s: No PHY found\n", dev->name);
+		return(0);
+	}
+
+	// Set the PHY type
+	if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) {
+		lp->phytype = PHY_LAN83C183;
+		PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name);
+	}
+
+	if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) {
+		lp->phytype = PHY_LAN83C180;
+		PRINTK("%s: PHY=LAN83C180\n", dev->name);
+	}
+
+	return 1;
+}
+
+/*------------------------------------------------------------
+ . Waits the specified number of milliseconds - kernel friendly
+ .-------------------------------------------------------------*/
+static void
+smc_wait_ms(unsigned int ms)
+{
+	if (!in_interrupt()) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1 + ms * HZ / 1000);
+	} else {
+		/* if this happens it must be fixed */
+		printk( KERN_WARNING "%s: busy wait while in interrupt!\n",
+			__FUNCTION__);
+		mdelay(ms);
+	}
+}
+
+/*------------------------------------------------------------
+ . Sets the PHY to a configuration as determined by the user
+ .-------------------------------------------------------------*/
+static int
+smc_phy_fixed(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int phyaddr = lp->phyaddr;
+	int my_fixed_caps, cfg1;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	// Enter Link Disable state
+	cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG);
+	cfg1 |= PHY_CFG1_LNKDIS;
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1);
+
+	// Set our fixed capabilities
+	// Disable auto-negotiation
+	my_fixed_caps = 0;
+
+	if (lp->ctl_rfduplx)
+		my_fixed_caps |= PHY_CNTL_DPLX;
+
+	if (lp->ctl_rspeed == 100)
+		my_fixed_caps |= PHY_CNTL_SPEED;
+
+	// Write our capabilities to the phy control register
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps);
+
+	// Re-Configure the Receive/Phy Control register
+	SMC_SET_RPC( lp->rpc_cur_mode );
+
+	// Success
+	return(1);
+}
+
+/*------------------------------------------------------------
+ . Configures the specified PHY through the MII management interface
+ . using Autonegotiation.
+ . Calls smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+static void
+smc_phy_configure(struct net_device* dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int timeout;
+	int phyaddr;
+	int my_phy_caps; // My PHY capabilities
+	int my_ad_caps; // My Advertised capabilities
+	int status;
+
+	PRINTK3("%s:smc_program_phy()\n", dev->name);
+
+	// Set the blocking flag
+	lp->autoneg_active = 1;
+
+	// Find the address and type of our phy
+	if (!smc_detect_phy(dev))
+		goto smc_phy_configure_exit;
+
+	// Get the detected phy address
+	phyaddr = lp->phyaddr;
+
+	// Reset the PHY, setting all other bits to zero
+	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
+
+	// Wait for the reset to complete, or time out
+	timeout = 6; // Wait up to 3 seconds
+	while (timeout--) {
+		if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
+		    & PHY_CNTL_RST))
+			// reset complete
+			break;
+		smc_wait_ms(500); // wait 500 millisecs
+		if (signal_pending(current)) { // Exit anyway if signaled
+			PRINTK("%s: PHY reset interrupted by signal\n",
+				dev->name);
+			timeout = 0;
+			break;
+		}
+	}
+
+	if (timeout < 1) {
+		printk("%s: PHY reset timed out\n", dev->name);
+		goto smc_phy_configure_exit;
+	}
+
+	// Read PHY Register 18, Status Output
+	lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+	// Enable PHY Interrupts (for register 18)
+	// Interrupts listed here are disabled
+	smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
+		PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+		PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+		PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+	/* Configure the Receive/Phy Control register */
+	SMC_SELECT_BANK( 0 );
+	SMC_SET_RPC( lp->rpc_cur_mode );
+
+	// Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
+	my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+
+	// If the user requested no auto neg, then go set his request
+	if (!(lp->ctl_autoneg)) {
+		smc_phy_fixed(dev);
+		goto smc_phy_configure_exit;
+	}
+
+	if( !( my_phy_caps & PHY_STAT_CAP_ANEG))
+	{
+		printk(KERN_INFO "Auto negotiation NOT supported\n");
+		smc_phy_fixed(dev);
+		goto smc_phy_configure_exit;
+	}
+
+	my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
+
+	if (my_phy_caps & PHY_STAT_CAP_T4)
+		my_ad_caps |= PHY_AD_T4;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXF)
+		my_ad_caps |= PHY_AD_TX_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TXH)
+		my_ad_caps |= PHY_AD_TX_HDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TF)
+		my_ad_caps |= PHY_AD_10_FDX;
+
+	if (my_phy_caps & PHY_STAT_CAP_TH)
+		my_ad_caps |= PHY_AD_10_HDX;
+
+	// Disable capabilities not selected by our user
+	if (lp->ctl_rspeed != 100)
+		my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX);
+
+	if (!lp->ctl_rfduplx)
+		my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX);
+
+	// Update our Auto-Neg Advertisement Register
+	smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
+
+	// Read the register back.  Without this, it appears that when
+	// auto-negotiation is restarted, sometimes it isn't ready and
+	// the link does not come up.
+	status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG);
+
+	PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps);
+	PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps);
+
+	// Restart auto-negotiation process in order to advertise my caps
+	smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+		PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
+
+	// Wait for the auto-negotiation to complete.  This may take from
+	// 2 to 3 seconds.
+	// Wait for the reset to complete, or time out
+	timeout = 20; // Wait up to 10 seconds
+	while (timeout--) {
+		status = smc_read_phy_register(ioaddr, phyaddr, PHY_RMT_REG);
+		if (status & PHY_AD_ACK)
+			// auto-negotiate complete
+			break;
+
+		smc_wait_ms(500); // wait 500 millisecs
+		if (signal_pending(current)) { // Exit anyway if signaled
+			printk(KERN_DEBUG
+				"%s: PHY auto-negotiate interrupted by signal\n",
+				dev->name);
+			timeout = 0;
+			break;
+		}
+	}
+	status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+
+	if (timeout < 1) {
+		PRINTK("%s: PHY auto-negotiate timed out\n", dev->name);
+	}
+
+	// Fail if we detected an auto-negotiate remote fault
+	if (status & PHY_STAT_REM_FLT) {
+		PRINTK("%s: PHY remote fault detected\n", dev->name);
+	}
+
+	// Wait for link. Once the link is up, phy18 should be up to date
+        timeout = 200;
+        do              
+        {
+                udelay(100);
+                status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+        } while ( ((status & PHY_STAT_LINK)==0) && --timeout);
+
+        if (status & PHY_STAT_LINK)        
+        {                                      
+                PRINTK("%s: Ethernet Link Detected\n", dev->name); 
+        }       
+
+	// The smc_phy_interrupt() routine will be called to update lastPhy18
+
+	// Set our sysctl parameters to match auto-negotiation results
+	if ( lp->lastPhy18 & PHY_INT_SPDDET ) {
+		PRINTK("%s: PHY 100BaseT\n", dev->name);
+		lp->rpc_cur_mode |= RPC_SPEED;
+	} else {
+		PRINTK("%s: PHY 10BaseT\n", dev->name);
+		lp->rpc_cur_mode &= ~RPC_SPEED;
+	}
+
+	if ( lp->lastPhy18 & PHY_INT_DPLXDET ) {
+		PRINTK("%s: PHY Full Duplex\n", dev->name);
+		lp->rpc_cur_mode |= RPC_DPLX;
+		lp->tcr_cur_mode |= TCR_SWFDUP;
+	} else {
+		PRINTK("%s: PHY Half Duplex\n", dev->name);
+		lp->rpc_cur_mode &= ~RPC_DPLX;
+		lp->tcr_cur_mode &= ~TCR_SWFDUP;
+	}
+
+	// Re-Configure the Receive/Phy Control register and TCR
+	SMC_SET_RPC( lp->rpc_cur_mode );
+	SMC_SET_TCR( lp->tcr_cur_mode );
+
+smc_phy_configure_exit:
+	// Exit auto-negotiation
+	lp->autoneg_active = 0;
+}
+
+/*************************************************************************
+ . smc_phy_interrupt
+ .
+ . Purpose:  Handle interrupts relating to PHY register 18. This is
+ .  called from the "hard" interrupt handler.
+ .
+ ************************************************************************/
+static void
+smc_phy_interrupt(struct net_device* dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int phyaddr = lp->phyaddr;
+	int phy18;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	for(;;) {
+		// Read PHY Register 18, Status Output
+		phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+		// Exit if not more changes
+		if (phy18 == lp->lastPhy18)
+			break;
+
+#if SMC_DEBUG > 1
+		PRINTK2("%s:     phy18=0x%04x\n", dev->name, phy18);
+		PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18);
+
+		// Handle events
+		if ((phy18 & PHY_INT_LNKFAIL) !=
+				(lp->lastPhy18 & PHY_INT_LNKFAIL))
+			PRINTK2("%s: PHY Link Fail=%x\n", dev->name,
+					phy18 & PHY_INT_LNKFAIL);
+
+		if ((phy18 & PHY_INT_LOSSSYNC) !=
+				(lp->lastPhy18 & PHY_INT_LOSSSYNC))
+			PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name,
+					phy18 & PHY_INT_LOSSSYNC);
+
+		if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD))
+			PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name,
+					phy18 & PHY_INT_CWRD);
+
+		if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD))
+			PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name,
+					phy18 & PHY_INT_SSD);
+
+		if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD))
+
+			PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name,
+					phy18 & PHY_INT_ESD);
+
+		if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL))
+			PRINTK2("%s: PHY Reverse Polarity Detected=%x\n",
+					dev->name, phy18 & PHY_INT_RPOL);
+
+		if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB))
+			PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name,
+					phy18 & PHY_INT_JAB);
+
+		if ((phy18 & PHY_INT_SPDDET) !=
+				(lp->lastPhy18 & PHY_INT_SPDDET))
+			PRINTK2("%s: PHY Speed Detect=%x\n", dev->name,
+					phy18 & PHY_INT_SPDDET);
+
+		if ((phy18 & PHY_INT_DPLXDET) !=
+				(lp->lastPhy18 & PHY_INT_DPLXDET))
+			PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name,
+					phy18 & PHY_INT_DPLXDET);
+#endif
+		// Update the last phy 18 variable
+		lp->lastPhy18 = phy18;
+	}
+}
+
+//--- END PHY CONTROL AND CONFIGURATION-------------------------------------
+
+
+/*
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+static void
+smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	unsigned long ioaddr = dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	int status, mask, timeout, card_stats;
+	int saved_bank, saved_pointer;
+
+	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
+
+	saved_bank = SMC_CURRENT_BANK();
+	SMC_SELECT_BANK(2);
+	saved_pointer = SMC_GET_PTR();
+	mask = SMC_GET_INT_MASK();
+	SMC_SET_INT_MASK( 0 );
+
+	/* set a timeout value, so I don't stay here forever */
+	timeout = 8;
+
+	do {
+		status = SMC_GET_INT();
+
+		PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
+			dev->name, status, mask,
+			({ int meminfo; SMC_SELECT_BANK(0);
+			   meminfo = SMC_GET_MIR();
+			   SMC_SELECT_BANK(2); meminfo; }),
+			SMC_GET_FIFO());
+
+		status &= mask;
+		if (!status)
+			break;
+
+		if (status & IM_RCV_INT) {
+			PRINTK3("%s: RX irq\n", dev->name);
+			smc_rcv(dev);
+		} else if (status & IM_TX_INT) {
+			PRINTK3("%s: TX int\n", dev->name);
+			smc_tx(dev);
+			SMC_ACK_INT( IM_TX_INT );
+#if THROTTLE_TX_PKTS
+			netif_wake_queue(dev);
+#endif
+		} else if (status & IM_ALLOC_INT) {
+			PRINTK3("%s: Allocation irq\n", dev->name);
+			smc_hardware_send_packet(dev);
+			mask |= (IM_TX_INT | IM_TX_EMPTY_INT);
+			mask &= ~IM_ALLOC_INT;
+#if ! THROTTLE_TX_PKTS
+			netif_wake_queue(dev);
+#endif
+		} else if (status & IM_TX_EMPTY_INT) {
+			PRINTK3("%s: TX empty\n", dev->name);
+			mask &= ~IM_TX_EMPTY_INT;
+
+			/* update stats */
+			SMC_SELECT_BANK( 0 );
+			card_stats = SMC_GET_COUNTER();
+			SMC_SELECT_BANK( 2 );
+
+			/* single collisions */
+			lp->stats.collisions += card_stats & 0xF;
+			card_stats >>= 4;
+
+			/* multiple collisions */
+			lp->stats.collisions += card_stats & 0xF;
+		} else if (status & IM_RX_OVRN_INT) {
+			PRINTK1( "%s: RX overrun\n", dev->name);
+			SMC_ACK_INT( IM_RX_OVRN_INT );
+			lp->stats.rx_errors++;
+			lp->stats.rx_fifo_errors++;
+
+			/*
+			 * When this condition occurs, this some times
+			 * tends to confuse the chip and eventually
+			 * overruns keep on occurring even if MIR shows 
+			 * all memory is free.  If I_TX_EMPTY_INT is set
+			 * (which is a good indication that the chip
+			 * is actually confused) and no packets are in
+			 * the process of being sent then we force a full
+			 * reset right here to unwedge things.
+			 */
+			if (!lp->saved_skb && SMC_GET_INT() & IM_TX_EMPTY_INT) {
+				PRINTK1("%s: overrun workaround\n", dev->name);
+				smc_reset(dev);
+				SMC_SELECT_BANK( 0 );
+				SMC_SET_TCR( lp->tcr_cur_mode );
+				SMC_SET_RCR( lp->rcr_cur_mode );
+				SMC_SELECT_BANK( 2 );
+			}
+		} else if (status & IM_EPH_INT) {
+			PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name);
+		} else if (status & IM_MDINT) {
+			SMC_ACK_INT( IM_MDINT );
+			smc_phy_interrupt(dev);
+		} else if (status & IM_ERCV_INT ) {
+			SMC_ACK_INT( IM_ERCV_INT );
+			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
+		}
+	} while (--timeout);
+
+	/* restore register states */
+	SMC_SET_INT_MASK( mask );
+	SMC_SET_PTR( saved_pointer );
+	SMC_SELECT_BANK( saved_bank );
+
+	PRINTK3("%s: Interrupt done\n", dev->name);
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void
+smc_timeout(struct net_device *dev)
+{
+	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	smc_reset(dev);
+	smc_enable(dev);
+
+#if 0
+	/* Reconfiguring the PHY doesn't seem like a bad idea here, but
+	 * it introduced a problem.  Now that this is a timeout routine,
+	 * we are getting called from within an interrupt context.
+	 * smc_phy_configure() calls smc_wait_ms() which calls
+	 * schedule_timeout() which calls schedule().  When schedule()
+	 * is called from an interrupt context, it prints out
+	 * "Scheduling in interrupt" and then calls BUG().  This is
+	 * obviously not desirable.  This was worked around by removing
+	 * the call to smc_phy_configure() here because it didn't seem
+	 * absolutely necessary.  Ultimately, if smc_wait_ms() is
+	 * supposed to be usable from an interrupt context (which it
+	 * looks like it thinks it should handle), it should be fixed.
+	 */
+	/* Reconfigure the PHY */
+	smc_phy_configure(dev);
+#endif
+
+	/* clear anything saved */
+	if (lp->saved_skb != NULL) {
+		dev_kfree_skb (lp->saved_skb);
+		lp->saved_skb = NULL;
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+	}
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+/*
+ * Finds the CRC32 of a set of bytes.
+ * (from Peter Cammaert's code)
+ */
+static int
+crc32(char *s, int length)
+{
+	/* indices */
+	int perByte;
+	int perBit;
+	/* crc polynomial for Ethernet */
+	const unsigned long poly = 0xedb88320;
+	/* crc value - preinitialized to all 1's */
+	unsigned long crc_value = 0xffffffff;
+
+	for ( perByte = 0; perByte < length; perByte ++ ) {
+		unsigned char	c;
+
+		c = *(s++);
+		for ( perBit = 0; perBit < 8; perBit++ ) {
+			crc_value = (crc_value>>1)^
+				(((crc_value^c)&0x01)?poly:0);
+			c >>= 1;
+		}
+	}
+	return	crc_value;
+}
+
+/*
+ .    This sets the internal hardware table to filter out unwanted multicast
+ .    packets before they take up memory.
+ .
+ .    The SMC chip uses a hash table where the high 6 bits of the CRC of
+ .    address are the offset into the table.  If that bit is 1, then the
+ .    multicast packet is accepted.  Otherwise, it's dropped silently.
+ .
+ .    To use the 6 bits as an offset into the table, the high 3 bits are the
+ .    number of the 8 bit register, while the low 3 bits are the bit within
+ .    that register.
+ .
+ .    This routine is based very heavily on the one provided by Peter Cammaert.
+*/
+static void
+smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs)
+{
+	int			i;
+	unsigned char		multicast_table[ 8 ];
+	struct dev_mc_list	*cur_addr;
+
+	/* table for flipping the order of 3 bits */
+	static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+	/* start with a table of all zeros: reject all */
+	memset( multicast_table, 0, sizeof( multicast_table ) );
+
+	cur_addr = addrs;
+	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {
+		int position;
+
+		/* do we have a pointer here? */
+		if ( !cur_addr )
+			break;
+		/* make sure this is a multicast address - shouldn't this
+		   be a given if we have it here ? */
+		if ( !( *cur_addr->dmi_addr & 1 ) )
+			continue;
+
+		/* only use the low order bits */
+		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
+
+		/* do some messy swapping to put the bit in the right spot */
+		multicast_table[invert3[position&7]] |=
+					(1<<invert3[(position>>3)&7]);
+
+	}
+	/* now, the table can be loaded into the chipset */
+	SMC_SELECT_BANK( 3 );
+	SMC_SET_MCAST( multicast_table );
+}
+
+/*
+ . This routine will, depending on the values passed to it,
+ . either make it accept multicast packets, go into
+ . promiscuous mode ( for TCPDUMP and cousins ) or accept
+ . a select set of multicast packets
+*/
+static void smc_set_multicast_list(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	SMC_SELECT_BANK(0);
+	if ( dev->flags & IFF_PROMISC ) {
+		PRINTK2("%s: RCR_PRMS\n", dev->name);
+		lp->rcr_cur_mode |= RCR_PRMS;
+		SMC_SET_RCR( lp->rcr_cur_mode );
+	}
+
+/* BUG?  I never disable promiscuous mode if multicasting was turned on.
+   Now, I turn off promiscuous mode, but I don't do anything to multicasting
+   when promiscuous mode is turned on.
+*/
+
+	/* Here, I am setting this to accept all multicast packets.
+	   I don't need to zero the multicast table, because the flag is
+	   checked before the table is
+	*/
+	else if (dev->flags & IFF_ALLMULTI) {
+		lp->rcr_cur_mode |= RCR_ALMUL;
+		SMC_SET_RCR( lp->rcr_cur_mode );
+		PRINTK2("%s: RCR_ALMUL\n", dev->name);
+	}
+
+	/* We just get all multicast packets even if we only want them
+	 . from one source.  This will be changed at some future
+	 . point. */
+	else if (dev->mc_count )  {
+		/* support hardware multicasting */
+
+		/* be sure I get rid of flags I might have set */
+		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
+		SMC_SET_RCR( lp->rcr_cur_mode );
+		/* NOTE: this has to set the bank, so make sure it is the
+		   last thing called.  The bank is set to zero at the top */
+		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
+	} else  {
+		PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
+		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
+		SMC_SET_RCR( lp->rcr_cur_mode );
+
+		/*
+		  since I'm disabling all multicast entirely, I need to
+		  clear the multicast list
+		*/
+		SMC_SELECT_BANK( 3 );
+		SMC_CLEAR_MCAST();
+	}
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ */
+static int
+smc_open(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	/* clear out all the junk that was put here before... */
+	memset(dev->priv, 0, sizeof(struct smc_local));
+
+	// Setup the default Register Modes
+	lp->tcr_cur_mode = TCR_DEFAULT;
+	lp->rcr_cur_mode = RCR_DEFAULT;
+	lp->rpc_cur_mode = RPC_DEFAULT;
+
+	/* Set default parameters */
+#ifdef CONFIG_ARCH_RAMSES
+	lp->ctl_autoneg = 0;
+	lp->ctl_rfduplx = 0;
+	lp->ctl_rspeed = 10;
+#else
+	lp->ctl_autoneg = 1;
+	lp->ctl_rfduplx = 1;
+	lp->ctl_rspeed = 100;
+#endif
+
+	SMC_SELECT_BANK(3);
+	lp->version = SMC_GET_REV() & 0xff;
+
+	/* reset the hardware */
+	smc_reset(dev);
+	smc_enable(dev);
+
+	SMC_SELECT_BANK( 1 );
+	SMC_SET_MAC_ADDR(dev->dev_addr);
+
+	/* Configure the PHY */
+	if (lp->version >= 0x70)
+		smc_phy_configure(dev);
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*----------------------------------------------------
+ . smc_close
+ .
+ . this makes the board clean up everything that it can
+ . and not talk to the outside world.   Caused by
+ . an 'ifconfig ethX down'
+ .
+ -----------------------------------------------------*/
+static int
+smc_close(struct net_device *dev)
+{
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	netif_stop_queue(dev);
+
+	/* clear everything */
+	smc_shutdown(dev->base_addr);
+
+	return 0;
+}
+
+/*------------------------------------------------------------
+ . Get the current statistics.
+ . This may be called with the card open or closed.
+ .-------------------------------------------------------------*/
+static struct net_device_stats *
+smc_query_statistics(struct net_device *dev)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+
+	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
+
+	return &lp->stats;
+}
+
+/*----------------------------------------------------------------------
+ . smc_findirq
+ .
+ . This routine has a simple purpose -- make the SMC chip generate an
+ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ ------------------------------------------------------------------------
+*/
+int __init
+smc_findirq( unsigned long ioaddr )
+{
+	int timeout = 20;
+	unsigned long cookie;
+
+	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
+
+	cookie = probe_irq_on();
+
+	/*
+	 * What I try to do here is trigger an ALLOC_INT. This is done
+	 * by allocating a small chunk of memory, which will give an interrupt
+	 * when done.
+	 */
+
+	/* enable ALLOCation interrupts ONLY */
+	SMC_SELECT_BANK(2);
+	SMC_SET_INT_MASK( IM_ALLOC_INT );
+
+	/*
+ 	 . Allocate 512 bytes of memory.  Note that the chip was just
+	 . reset so all the memory is available
+	*/
+	SMC_SET_MMU_CMD( MC_ALLOC | 1 );
+
+	/*
+	 . Wait until positive that the interrupt has been generated
+	*/
+	do {
+		int int_status;
+		udelay(10);
+		int_status = SMC_GET_INT();
+		if (int_status & IM_ALLOC_INT)
+			break;		/* got the interrupt */
+	} while (--timeout);
+
+	/* there is really nothing that I can do here if timeout fails,
+	   as autoirq_report will return a 0 anyway, which is what I
+	   want in this case.   Plus, the clean up is needed in both
+	   cases.  */
+
+	/* and disable all interrupts again */
+	SMC_SET_INT_MASK( 0 );
+
+	/* and return what I found */
+	return probe_irq_off(cookie);
+}
+
+/*----------------------------------------------------------------------
+ . Function: smc_probe( unsigned long ioaddr )
+ .
+ . Purpose:
+ .	Tests to see if a given ioaddr points to an SMC91x chip.
+ .	Returns a 0 on success
+ .
+ . Algorithm:
+ .	(1) see if the high byte of BANK_SELECT is 0x33
+ . 	(2) compare the ioaddr with the base register's address
+ .	(3) see if I recognize the chip ID in the appropriate register
+ .
+ .---------------------------------------------------------------------
+ */
+/*---------------------------------------------------------------
+ . Here I do typical initialization tasks.
+ .
+ . o  Initialize the structure if needed
+ . o  print out my vanity message if not done so already
+ . o  print out what type of hardware is detected
+ . o  print out the ethernet address
+ . o  find the IRQ
+ . o  set up my private data
+ . o  configure the dev structure with my subroutines
+ . o  actually GRAB the irq.
+ . o  GRAB the region
+ .-----------------------------------------------------------------
+*/
+static int __init
+smc_probe(struct net_device *dev, unsigned long ioaddr)
+{
+	struct smc_local *lp = (struct smc_local *)dev->priv;
+	static int version_printed = 0;
+	int i, retval;
+	unsigned int val, revision_register;
+	const char *version_string;
+#ifdef CONFIG_SA1100_DNP1110
+	/* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */
+	unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010);
+#endif
+
+
+
+	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
+
+	/* Grab the region so that no one else tries to probe our ioports. */
+	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
+		return -EBUSY;
+
+	/* First, see if the high byte is 0x33 */
+	val = SMC_CURRENT_BANK();
+	PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
+	if ( (val & 0xFF00) != 0x3300 ) {
+		if ( (val & 0xFF) == 0x33 ) {
+			printk( KERN_WARNING
+				"%s: Detected possible byte-swapped interface"
+				" at IOADDR 0x%lx\n", CARDNAME, ioaddr);
+		}
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* The above MIGHT indicate a device, but I need to write to further
+ 	 	test this.  */
+	SMC_SELECT_BANK(0);
+	val = SMC_CURRENT_BANK();
+	if ( (val & 0xFF00 ) != 0x3300 ) {
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* well, we've already written once, so hopefully another time won't
+ 	   hurt.  This time, I need to switch the bank register to bank 1,
+	   so I can access the base address register */
+	SMC_SELECT_BANK(1);
+	val = SMC_GET_BASE();
+	val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
+	if ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) {
+		printk( "%s: IOADDR %lx doesn't match configuration (%x).\n",
+			CARDNAME, ioaddr, val );
+	}
+
+	/*  check if the revision register is something that I recognize.
+	    These might need to be added to later, as future revisions
+	    could be added.  */
+	SMC_SELECT_BANK(3);
+	revision_register = SMC_GET_REV();
+	PRINTK2("%s: revision = 0x%04x\n", CARDNAME, revision_register);
+	version_string = chip_ids[ (revision_register >> 4) & 0xF];
+	if (!version_string || (revision_register & 0xff00) != 0x3300) {
+		/* I don't recognize this chip, so... */
+		printk( "%s: IO 0x%lx: Unrecognized revision register 0x%04x"
+			", Contact author.\n", CARDNAME,
+			ioaddr, revision_register);
+
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* At this point I'll assume that the chip is an SMC91x. */
+	if (version_printed++ == 0)
+		printk("%s", version);
+
+	/* set the private data to zero by default */
+	memset(lp, 0, sizeof(struct smc_local));
+
+	/* fill in some of the fields */
+	dev->base_addr = ioaddr;
+	lp->version = revision_register & 0xff;
+
+	/* Get the MAC address */
+	SMC_SELECT_BANK( 1 );
+	SMC_GET_MAC_ADDR(dev->dev_addr);
+
+	/* now, reset the chip, and put it into a known state */
+	smc_reset( dev );
+
+	/*
+	 . If dev->irq is 0, then the device has to be banged on to see
+	 . what the IRQ is.
+ 	 .
+	 . This banging doesn't always detect the IRQ, for unknown reasons.
+	 . a workaround is to reset the chip and try again.
+	 .
+	 . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
+	 . be what is requested on the command line.   I don't do that, mostly
+	 . because the card that I have uses a non-standard method of accessing
+	 . the IRQs, and because this _should_ work in most configurations.
+	 .
+	 . Specifying an IRQ is done with the assumption that the user knows
+	 . what (s)he is doing.  No checking is done!!!!
+ 	 .
+	*/
+	if ( dev->irq < 1 ) {
+		int	trials;
+
+		trials = 3;
+		while ( trials-- ) {
+			dev->irq = smc_findirq( ioaddr );
+			if ( dev->irq )
+				break;
+			/* kick the card and try again */
+			smc_reset( dev );
+		}
+	}
+	if (dev->irq == 0 ) {
+		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+			dev->name);
+		retval = -ENODEV;
+		goto err_out;
+	}
+	dev->irq = irq_cannonicalize(dev->irq);
+
+	/* now, print out the card info, in a short format.. */
+	printk( "%s: %s (rev %d) at %#lx IRQ %d%s%s\n",
+		dev->name, version_string, revision_register & 0x0f,
+		ioaddr, dev->irq, nowait ? " [nowait]" : "",
+		THROTTLE_TX_PKTS ? " [throttle_tx]" : "" );
+
+#if defined(CONFIG_SA1100_DNP1110)
+	/* On DNP we have to set the ethernet address  */
+	/* FIXME: find a better place for this code... */
+        for (i=0; i<6; i++)
+            if ((dev->dev_addr[i] != 0) && (dev->dev_addr[i] != 0xff))
+                break;
+        if (i==6) {
+            dev->dev_addr[0] = *(dnp1110_mac+0);
+            dev->dev_addr[1] = *(dnp1110_mac+1);
+            dev->dev_addr[2] = *(dnp1110_mac+2);
+            dev->dev_addr[3] = *(dnp1110_mac+3);
+            dev->dev_addr[4] = *(dnp1110_mac+4);
+            dev->dev_addr[5] = *(dnp1110_mac+5);
+        }
+
+        for (i=0; i<6; i++)
+            if ((dev->dev_addr[i] != 0) && (dev->dev_addr[i] != 0xff))
+                break;
+        if (i==6) {
+                printk(CARDNAME": uninitialized MAC address detected -- using a dummy one\n");
+                for (i=0;i<6;i++)
+                        dev->dev_addr[i] = i;
+        }
+#endif
+	
+	/* Print the Ethernet address */
+	printk("%s: Ethernet addr: ", dev->name);
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i] );
+	printk("%2.2x\n", dev->dev_addr[5] );
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	/* Grab the IRQ */
+      	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+      	if (retval) {
+  	  	goto err_out;
+      	}
+
+	dev->open		        = smc_open;
+	dev->stop		        = smc_close;
+	dev->hard_start_xmit    	= smc_hard_start_xmit;
+	dev->tx_timeout		    	= smc_timeout;
+	dev->watchdog_timeo		= HZ/10;
+	dev->get_stats			= smc_query_statistics;
+	dev->set_multicast_list 	= smc_set_multicast_list;
+
+	return 0;
+
+err_out:
+	release_region(ioaddr, SMC_IO_EXTENT);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_init( void )
+ |   Input parameters:
+ |	dev->base_addr == 0, try to find all possible locations
+ |	dev->base_addr > 0x1ff, this is the address to check
+ |	dev->base_addr == <anything else>, return failure code
+ |
+ |   Output:
+ |	0 --> there is a device
+ |	anything else, error
+ |
+ ---------------------------------------------------------------------------
+*/
+static struct net_device *global_dev = NULL;  /* needs to be fixed */
+
+#ifdef CONFIG_PM
+
+static int smc_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	unsigned long ioaddr = global_dev->base_addr;
+	struct smc_local *lp = (struct smc_local *)global_dev->priv;
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		smc_shutdown(global_dev->base_addr);
+		break;
+	case PM_RESUME:
+		smc_reset(global_dev);
+		smc_enable(global_dev);
+		SMC_SELECT_BANK( 1 );
+	        SMC_SET_MAC_ADDR(global_dev->dev_addr);
+	        if (lp->version >= 0x70)
+        	        smc_phy_configure(global_dev);
+		break;
+	}
+	return 0;
+}
+
+#endif
+
+static int __init
+smc_init(void)
+{
+	int ret;
+
+	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
+
+#ifdef MODULE
+	if (io == -1)
+		printk( KERN_WARNING 
+			"%s: You shouldn't use auto-probing with insmod!\n",
+			CARDNAME );
+#endif
+
+	if (global_dev) {
+		printk("%s: already initialized.\n", CARDNAME);
+		return -EBUSY;
+	}
+
+	global_dev = init_etherdev(0, sizeof(struct smc_local));
+	if (!global_dev) {
+		printk("%s: could not allocate device.\n", CARDNAME);
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(global_dev);
+
+	/* copy the parameters from insmod into the device structure */
+	if (io != -1)
+		global_dev->base_addr	= io;
+	if (irq != -1)
+		global_dev->irq	= irq;
+
+#ifdef CONFIG_ISA
+	/*  try a specific location */
+	if (global_dev->base_addr > 0x1ff)
+		ret = smc_probe(global_dev, global_dev->base_addr);
+	else if (global_dev->base_addr != 0)
+		ret = -ENXIO;
+	else {
+		int i;
+
+		/* check every ethernet address */
+		for (i = 0; smc_portlist[i]; i++) {
+			ret = smc_probe(global_dev, smc_portlist[i]);
+			if (ret == 0)
+				break;
+		}
+	}
+#elif defined(CONFIG_ARCH_LUBBOCK)
+	{
+		int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2);
+		volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000);
+		unsigned long flags;
+
+		/* first reset, then enable the device. Sequence is critical */
+		local_irq_save(flags);
+		attaddr[ECOR] |= ECOR_RESET;
+		udelay(100);
+		attaddr[ECOR] &= ~ECOR_RESET;
+		attaddr[ECOR] |= ECOR_ENABLE;
+
+		/* force 16-bit mode */
+		attaddr[ECSR] &= ~ECSR_IOIS8;
+		mdelay(1);
+		local_irq_restore(flags);
+
+		global_dev->irq = LUBBOCK_ETH_IRQ;
+		ret = smc_probe(global_dev, ioaddr);
+	}
+#elif defined(CONFIG_ARCH_PXA_IDP)
+	{
+		int ioaddr = IDP_ETH_BASE + 0x300;
+		global_dev->irq = SMC_IRQ;
+		ret = smc_probe(global_dev, ioaddr);
+	}
+#elif defined(CONFIG_ARCH_RAMSES)
+	{
+		int ioaddr = RAMSES_ETH_BASE + 0x300;
+		global_dev->irq = SMC_IRQ;
+		ret = smc_probe(global_dev, ioaddr);
+	}
+#else
+	if (global_dev->base_addr == -1) {
+		printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME);
+		ret = -ENXIO;
+	} else {
+		void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT);
+		ret = smc_probe(global_dev, (unsigned long)ioaddr);
+		if (ret != 0)
+			iounmap(ioaddr);
+	}
+#endif
+
+#ifdef SMC_USE_PXA_DMA
+	if (ret == 0) {
+		int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW,
+					  smc_pxa_dma_irq, NULL);
+		if (dma >= 0) {
+			global_dev->dma = dma;
+			PRINTK("%s: using DMA channel %d\n", global_dev->name, dma);
+		} else {
+			global_dev->dma = -1;
+		}
+	}
+#endif
+
+#ifdef CONFIG_PM
+	if (ret == 0) {
+		struct smc_local *lp = (struct smc_local *)global_dev->priv;
+		lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback);
+	}
+#endif
+
+	if (ret != 0) {
+		printk("%s: not found.\n", CARDNAME);
+		kfree(global_dev->priv);
+		unregister_netdev(global_dev);
+		kfree(global_dev);
+	}
+
+	return ret;
+}
+
+static void __exit
+smc_cleanup(void)
+{
+	unregister_netdev(global_dev);
+#ifdef CONFIG_PM
+	{
+		struct smc_local *lp = (struct smc_local *)global_dev->priv;
+		pm_unregister(lp->pm);
+	}
+#endif
+	free_irq(global_dev->irq, global_dev);
+	release_region(global_dev->base_addr, SMC_IO_EXTENT);
+
+#ifndef CONFIG_ISA
+	iounmap((void *)global_dev->base_addr);
+#endif
+
+	kfree(global_dev);
+	global_dev = NULL;
+}
+
+module_init(smc_init);
+module_exit(smc_cleanup);
+
diff -urN linux-2.4.19-rmk7/drivers/net/smc91x.h linux-2.4.19-rmk7-dnp1/drivers/net/smc91x.h
--- linux-2.4.19-rmk7/drivers/net/smc91x.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/drivers/net/smc91x.h	2003-07-05 18:37:47.000000000 +0200
@@ -0,0 +1,849 @@
+/*
+ * NOTE: This driver is Nicolas Pitre's version, taken from 2.4.19-rmk7-pxa2. 
+ *       Some DNP specific tweaks have been added. The driver will probably
+ *       be merged with the mainline driver asap. [Robert Schwebel]
+ */
+
+/*------------------------------------------------------------------------
+ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device.
+ .
+ . Copyright (C) 1996 by Erik Stahlman
+ . Copyright (C) 2001 Standard Microsystems Corporation
+ .	Developed by Simple Network Magic Corporation
+ . Copyright (C) 2003 Monta Vista Software, Inc.
+ .	Unified SMC91x driver by Nicolas Pitre
+ .
+ . This program is free software; you can redistribute it and/or modify
+ . it under the terms of the GNU General Public License as published by
+ . the Free Software Foundation; either version 2 of the License, or
+ . (at your option) any later version.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ .	Erik Stahlman		<erik@vt.edu>
+ .	Daris A Nevil		<dnevil@snmc.com>
+ .	Nicolas Pitre 		<nico@cam.org>
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC91X_H_
+#define _SMC91X_H_
+
+
+/*
+ * Define your architecture specific configuration parameters here.
+ */
+
+#if	defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
+	defined(CONFIG_SA1100_PFS168) || \
+	defined(CONFIG_SA1100_FLEXANET) || \
+	defined(CONFIG_SA1100_GRAPHICSMASTER) || \
+	defined(CONFIG_SA1100_DNP1110) || \
+	defined(CONFIG_ARCH_LUBBOCK)
+
+/* We can only do 16-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+#define SMC_NOWAIT		1
+
+/* The first two address lines aren't connected... */
+#define SMC_IO_SHIFT		2
+
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_outw(v, a, r)	writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
+
+#ifdef CONFIG_ARCH_LUBBOCK
+#define SMC_IOADDR		LUBBOCK_ETH_PHYS
+#endif
+
+#ifdef CONFIG_SA1100_DNP1110
+#include <asm/arch/dnp1110.h>
+#define SMC_IOADDR		(DNP1110_ETH_VIRT + 0x300)
+#define SMC_IRQ			DNP1110_ETH_IRQ
+#define SMC_IO_SHIFT		0
+#endif
+
+#elif	defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_PXA_IDP) || defined(CONFIG_ARCH_RAMSES)
+
+#ifdef CONFIG_ARCH_MAINSTONE
+#include <asm/arch/mainstone.h>
+#define SMC_IOADDR		(MST_ETH_PHYS + 0x300)
+#define SMC_IRQ			MAINSTONE_IRQ(3)
+
+#elif CONFIG_ARCH_PXA_IDP
+#include <asm/arch/idp.h>
+#define SMC_IOADDR		(IDP_ETH_PHYS + 0x300)
+#define SMC_IRQ			ETHERNET_IRQ
+	
+#elif CONFIG_ARCH_RAMSES
+#include <asm/arch/ramses.h>
+#define SMC_IOADDR		(RAMSES_ETH_PHYS + 0x300)
+#define SMC_IRQ			ETHERNET_IRQ
+#endif
+	
+#define SMC_CAN_USE_8BIT	1
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	1
+#define SMC_IO_SHIFT		0
+#define SMC_NOWAIT		1
+#define SMC_USE_PXA_DMA		1
+
+#define SMC_inb(a, r)		readb((a) + (r))
+#define SMC_inw(a, r)		readw((a) + (r))
+#define SMC_inl(a, r)		readl((a) + (r))
+#define SMC_outb(v, a, r)	writeb(v, (a) + (r))
+#define SMC_outl(v, a, r)	writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l)	insl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)	outsl((a) + (r), p, l)
+
+/* We actually can't write halfwords properly if not word aligned */
+static inline void
+SMC_outw(u16 val, unsigned long ioaddr, int reg)
+{
+	if (reg & 2) {
+		unsigned int v = val << 16;
+		v |= readl(ioaddr + (reg & ~2)) & 0xffff;
+		writel(v, ioaddr + (reg & ~2));
+	} else {
+		writew(val, ioaddr + reg);
+	}
+}
+
+#elif	defined(CONFIG_ISA)
+
+#define SMC_CAN_USE_8BIT	1
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+
+#define SMC_inb(a, r)		inb((a) + (r))
+#define SMC_inw(a, r)		inw((a) + (r))
+#define SMC_outb(v, a, r)	outb(v, (a) + (r))
+#define SMC_outw(v, a, r)	outw(v, (a) + (r))
+#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
+
+#endif
+
+
+#ifdef SMC_USE_PXA_DMA
+/*
+ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
+ * always happening in irq context so no need to worry about races.  TX is
+ * different and probably not worth it for that reason, and not as critical
+ * as RX which can overrun memory and lose packets.
+ */
+#include <linux/pci.h>
+#include <asm/dma.h>
+
+#ifdef SMC_insl
+#undef SMC_insl
+#define SMC_insl(a, r, p, l)	smc_pxa_dma_insl(a, r, dev->dma, p, l)
+static inline void
+smc_pxa_dma_insl(u_long ioaddr, int reg, int dma, u_char *buf, int len)
+{
+	dma_addr_t dmabuf;
+
+	/* fallback if no DMA available */
+	if (dma == -1) {
+		insl(ioaddr + reg, buf, len);
+		return;
+	}
+
+	/* 64 bit alignment is required for memory to memory DMA */
+	if ((long)buf & 4) {
+		*((u32 *)buf)++ = SMC_inl(ioaddr, reg);
+		len--;
+	}
+
+	len *= 4;
+	dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
+	DCSR(dma) = DCSR_NODESC;
+	DTADR(dma) = dmabuf;
+	DSADR(dma) = SMC_IOADDR + reg;
+	DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+		     DCMD_WIDTH4 | (DCMD_LENGTH & len));
+	DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+	while (!(DCSR(dma) & DCSR_STOPSTATE));
+	DCSR(dma) = 0;
+	pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
+}
+#endif
+
+#ifdef SMC_insw
+#undef SMC_insw
+#define SMC_insw(a, r, p, l)	smc_pxa_dma_insw(a, r, dev->dma, p, l)
+static inline void
+smc_pxa_dma_insw(u_long ioaddr, int reg, int dma, u_char *buf, int len)
+{
+	dma_addr_t dmabuf;
+
+	/* fallback if no DMA available */
+	if (dma == -1) {
+		insw(ioaddr + reg, buf, len);
+		return;
+	}
+
+	/* 64 bit alignment is required for memory to memory DMA */
+	while ((long)buf & 6) {
+		*((u16 *)buf)++ = SMC_inw(ioaddr, reg);
+		len--;
+	}
+
+	len *= 2;
+	dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
+	DCSR(dma) = DCSR_NODESC;
+	DTADR(dma) = dmabuf;
+	DSADR(dma) = SMC_IOADDR + reg;
+	DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+		     DCMD_WIDTH2 | (DCMD_LENGTH & len));
+	DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+	while (!(DCSR(dma) & DCSR_STOPSTATE));
+	DCSR(dma) = 0;
+	pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
+}
+#endif
+
+static void
+smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
+{
+	DCSR(dma) = 0;
+}
+#endif  /* SMC_USE_PXA_DMA */
+
+
+/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
+#ifndef SMC_IO_SHIFT
+#define SMC_IO_SHIFT	0
+#endif
+#define SMC_IO_EXTENT	(16 << SMC_IO_SHIFT)
+
+
+/*
+ . Bank Select Register:
+ .
+ .		yyyy yyyy 0000 00xx
+ .		xx 		= bank number
+ .		yyyy yyyy	= 0x33, for identification purposes.
+*/
+#define BANK_SELECT		(14 << SMC_IO_SHIFT)
+
+
+// Transmit Control Register
+/* BANK 0  */
+#define TCR_REG 	SMC_REG(0x0000, 0)
+#define TCR_ENABLE	0x0001	// When 1 we can transmit
+#define TCR_LOOP	0x0002	// Controls output pin LBK
+#define TCR_FORCOL	0x0004	// When 1 will force a collision
+#define TCR_PAD_EN	0x0080	// When 1 will pad tx frames < 64 bytes w/0
+#define TCR_NOCRC	0x0100	// When 1 will not append CRC to tx frames
+#define TCR_MON_CSN	0x0400	// When 1 tx monitors carrier
+#define TCR_FDUPLX    	0x0800  // When 1 enables full duplex operation
+#define TCR_STP_SQET	0x1000	// When 1 stops tx if Signal Quality Error
+#define TCR_EPH_LOOP	0x2000	// When 1 enables EPH block loopback
+#define TCR_SWFDUP	0x8000	// When 1 enables Switched Full Duplex mode
+
+#define TCR_CLEAR	0	/* do NOTHING */
+/* the default settings for the TCR register : */
+#define TCR_DEFAULT	(TCR_ENABLE | TCR_PAD_EN)
+
+
+// EPH Status Register
+/* BANK 0  */
+#define EPH_STATUS_REG	SMC_REG(0x0002, 0)
+#define ES_TX_SUC	0x0001	// Last TX was successful
+#define ES_SNGL_COL	0x0002	// Single collision detected for last tx
+#define ES_MUL_COL	0x0004	// Multiple collisions detected for last tx
+#define ES_LTX_MULT	0x0008	// Last tx was a multicast
+#define ES_16COL	0x0010	// 16 Collisions Reached
+#define ES_SQET		0x0020	// Signal Quality Error Test
+#define ES_LTXBRD	0x0040	// Last tx was a broadcast
+#define ES_TXDEFR	0x0080	// Transmit Deferred
+#define ES_LATCOL	0x0200	// Late collision detected on last tx
+#define ES_LOSTCARR	0x0400	// Lost Carrier Sense
+#define ES_EXC_DEF	0x0800	// Excessive Deferral
+#define ES_CTR_ROL	0x1000	// Counter Roll Over indication
+#define ES_LINK_OK	0x4000	// Driven by inverted value of nLNK pin
+#define ES_TXUNRN	0x8000	// Tx Underrun
+
+
+// Receive Control Register
+/* BANK 0  */
+#define RCR_REG		SMC_REG(0x0004, 0)
+#define RCR_RX_ABORT	0x0001	// Set if a rx frame was aborted
+#define RCR_PRMS	0x0002	// Enable promiscuous mode
+#define RCR_ALMUL	0x0004	// When set accepts all multicast frames
+#define RCR_RXEN	0x0100	// IFF this is set, we can receive packets
+#define RCR_STRIP_CRC	0x0200	// When set strips CRC from rx packets
+#define RCR_ABORT_ENB	0x0200	// When set will abort rx on collision
+#define RCR_FILT_CAR	0x0400	// When set filters leading 12 bit s of carrier
+#define RCR_SOFTRST	0x8000 	// resets the chip
+
+/* the normal settings for the RCR register : */
+#define RCR_DEFAULT	(RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR	0x0	// set it to a base state
+
+
+// Counter Register
+/* BANK 0  */
+#define COUNTER_REG	SMC_REG(0x0006, 0)
+
+
+// Memory Information Register
+/* BANK 0  */
+#define MIR_REG		SMC_REG(0x0008, 0)
+
+
+// Receive/Phy Control Register
+/* BANK 0  */
+#define RPC_REG		SMC_REG(0x000A, 0)
+#define RPC_SPEED	0x2000	// When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX	0x1000	// When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG	0x0800	// When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT	5	// Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT	2	// Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10	(0x00)	// LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES	(0x01)	// LED = Reserved
+#define RPC_LED_10	(0x02)	// LED = 10Mbps link detect
+#define RPC_LED_FD	(0x03)	// LED = Full Duplex Mode
+#define RPC_LED_TX_RX	(0x04)	// LED = TX or RX packet occurred
+#define RPC_LED_100	(0x05)	// LED = 100Mbps link dectect
+#define RPC_LED_TX	(0x06)	// LED = TX packet occurred
+#define RPC_LED_RX	(0x07)	// LED = RX packet occurred
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+
+
+/* Bank 0 0x0C is reserved */
+
+// Bank Select Register
+/* All Banks */
+#define BSR_REG		0x000E
+
+
+// Configuration Reg
+/* BANK 1 */
+#define CONFIG_REG	SMC_REG(0x0000,	1)
+#define CONFIG_EXT_PHY	0x0200	// 1=external MII, 0=internal Phy
+#define CONFIG_GPCNTRL	0x0400	// Inverse value drives pin nCNTRL
+#define CONFIG_NO_WAIT	0x1000	// When 1 no extra wait states on ISA bus
+#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
+
+// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
+#define CONFIG_DEFAULT	(CONFIG_EPH_POWER_EN)
+
+
+// Base Address Register
+/* BANK 1 */
+#define BASE_REG	SMC_REG(0x0002, 1)
+
+
+// Individual Address Registers
+/* BANK 1 */
+#define ADDR0_REG	SMC_REG(0x0004, 1)
+#define ADDR1_REG	SMC_REG(0x0006, 1)
+#define ADDR2_REG	SMC_REG(0x0008, 1)
+
+
+// General Purpose Register
+/* BANK 1 */
+#define GP_REG		SMC_REG(0x000A, 1)
+
+
+// Control Register
+/* BANK 1 */
+#define CTL_REG		SMC_REG(0x000C, 1)
+#define CTL_RCV_BAD	0x4000 // When 1 bad CRC packets are received
+#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
+#define CTL_LE_ENABLE	0x0080 // When 1 enables Link Error interrupt
+#define CTL_CR_ENABLE	0x0040 // When 1 enables Counter Rollover interrupt
+#define CTL_TE_ENABLE	0x0020 // When 1 enables Transmit Error interrupt
+#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
+#define CTL_RELOAD	0x0002 // When set reads EEPROM into registers
+#define CTL_STORE	0x0001 // When set stores registers into EEPROM
+
+
+// MMU Command Register
+/* BANK 2 */
+#define MMU_CMD_REG	SMC_REG(0x0000, 2)
+#define MC_BUSY		1	// When 1 the last release has not completed
+#define MC_NOP		(0<<5)	// No Op
+#define MC_ALLOC	(1<<5) 	// OR with number of 256 byte packets
+#define MC_RESET	(2<<5)	// Reset MMU to initial state
+#define MC_REMOVE	(3<<5) 	// Remove the current rx packet
+#define MC_RELEASE  	(4<<5) 	// Remove and release the current rx packet
+#define MC_FREEPKT  	(5<<5) 	// Release packet in PNR register
+#define MC_ENQUEUE	(6<<5)	// Enqueue the packet for transmit
+#define MC_RSTTXFIFO	(7<<5)	// Reset the TX FIFOs
+
+
+// Packet Number Register
+/* BANK 2 */
+#define PN_REG		SMC_REG(0x0002, 2)
+
+
+// Allocation Result Register
+/* BANK 2 */
+#define AR_REG		SMC_REG(0x0003, 2)
+#define AR_FAILED	0x80	// Alocation Failed
+
+
+// TX FIFO Ports Register
+/* BANK 2 */
+#define FIFO_REG	SMC_REG(0x0004, 2)
+#define TXFIFO_REG	0x0004
+#define TXFIFO_TEMPTY	0x80	// TX FIFO Empty
+
+// RX FIFO Ports Register
+/* BANK 2 */
+#define RXFIFO_REG	SMC_REG(0x0005, 2)
+#define RXFIFO_REMPTY	0x80	// RX FIFO Empty
+
+
+// Pointer Register
+/* BANK 2 */
+#define PTR_REG		SMC_REG(0x0006, 2)
+#define PTR_RCV		0x8000 // 1=Receive area, 0=Transmit area
+#define PTR_AUTOINC 	0x4000 // Auto increment the pointer on each access
+#define PTR_READ	0x2000 // When 1 the operation is a read
+
+
+// Data Register
+/* BANK 2 */
+#define DATA_REG	SMC_REG(0x0008, 2)
+
+
+// Interrupt Status/Acknowledge Register
+/* BANK 2 */
+#define INT_REG		SMC_REG(0x000C, 2)
+
+
+// Interrupt Mask Register
+/* BANK 2 */
+#define IM_REG		SMC_REG(0x000D, 2)
+#define IM_MDINT	0x80 // PHY MI Register 18 Interrupt
+#define IM_ERCV_INT	0x40 // Early Receive Interrupt
+#define IM_EPH_INT	0x20 // Set by Ethernet Protocol Handler section
+#define IM_RX_OVRN_INT	0x10 // Set by Receiver Overruns
+#define IM_ALLOC_INT	0x08 // Set when allocation request is completed
+#define IM_TX_EMPTY_INT	0x04 // Set if the TX FIFO goes empty
+#define IM_TX_INT	0x02 // Transmit Interrupt
+#define IM_RCV_INT	0x01 // Receive Interrupt
+
+
+// Multicast Table Registers
+/* BANK 3 */
+#define MCAST_REG1	SMC_REG(0x0000, 3)
+#define MCAST_REG2	SMC_REG(0x0002, 3)
+#define MCAST_REG3	SMC_REG(0x0004, 3)
+#define MCAST_REG4	SMC_REG(0x0006, 3)
+
+
+// Management Interface Register (MII)
+/* BANK 3 */
+#define MII_REG		SMC_REG(0x0008, 3)
+#define MII_MSK_CRS100	0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE	0x0008 // MII Output Enable
+#define MII_MCLK	0x0004 // MII Clock, pin MDCLK
+#define MII_MDI		0x0002 // MII Input, pin MDI
+#define MII_MDO		0x0001 // MII Output, pin MDO
+
+
+// Revision Register
+/* BANK 3 */
+/* ( hi: chip id   low: rev # ) */
+#define REV_REG		SMC_REG(0x000A, 3)
+
+
+// Early RCV Register
+/* BANK 3 */
+/* this is NOT on SMC9192 */
+#define ERCV_REG	SMC_REG(0x000C, 3)
+#define ERCV_RCV_DISCRD	0x0080 // When 1 discards a packet being received
+#define ERCV_THRESHOLD	0x001F // ERCV Threshold Mask
+
+
+// External Register
+/* BANK 7 */
+#define EXT_REG		SMC_REG(0x0000, 7)
+
+
+#define CHIP_9192	3
+#define CHIP_9194	4
+#define CHIP_9195	5
+#define CHIP_9196	6
+#define CHIP_91100	7
+#define CHIP_91100FD	8
+#define CHIP_91111FD	9
+
+static const char * chip_ids[ 16 ] =  {
+	NULL, NULL, NULL,
+	/* 3 */ "SMC91C90/91C92",
+	/* 4 */ "SMC91C94",
+	/* 5 */ "SMC91C95",
+	/* 6 */ "SMC91C96",
+	/* 7 */ "SMC91C100",
+	/* 8 */ "SMC91C100FD",
+	/* 9 */ "SMC91C11xFD",
+	NULL, NULL, NULL,
+	NULL, NULL, NULL};
+
+
+/*
+ . Transmit status bits
+*/
+#define TS_SUCCESS 0x0001
+#define TS_LOSTCAR 0x0400
+#define TS_LATCOL  0x0200
+#define TS_16COL   0x0010
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR	0x8000
+#define RS_BRODCAST	0x4000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+
+// PHY Types
+enum {
+	PHY_LAN83C183 = 1,	// LAN91C111 Internal PHY
+	PHY_LAN83C180
+};
+
+
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG		0x00
+#define PHY_CNTL_RST		0x8000	// 1=PHY Reset
+#define PHY_CNTL_LPBK		0x4000	// 1=PHY Loopback
+#define PHY_CNTL_SPEED		0x2000	// 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN	0x1000	// 1=Enable Auto negotiation
+#define PHY_CNTL_PDN		0x0800	// 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS	0x0400	// 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST	0x0200	// 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX		0x0100	// 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST		0x0080	// 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG		0x01
+#define PHY_STAT_CAP_T4		0x8000	// 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF	0x4000	// 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH	0x2000	// 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF		0x1000	// 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH		0x0800	// 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR	0x0040	// 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK	0x0020	// 1=ANEG has completed
+#define PHY_STAT_REM_FLT	0x0010	// 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG	0x0008	// 1=Auto negotiate capable
+#define PHY_STAT_LINK		0x0004	// 1=valid link
+#define PHY_STAT_JAB		0x0002	// 1=10Mbps jabber condition
+#define PHY_STAT_EXREG		0x0001	// 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG		0x02	// PHY Identifier 1
+#define PHY_ID2_REG		0x03	// PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG		0x04
+#define PHY_AD_NP		0x8000	// 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK		0x4000	// 1=got link code word from remote
+#define PHY_AD_RF		0x2000	// 1=advertise remote fault
+#define PHY_AD_T4		0x0200	// 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX		0x0100	// 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX		0x0080	// 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX		0x0040	// 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX		0x0020	// 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA		0x0001	// 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG		0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG		0x10
+#define PHY_CFG1_LNKDIS		0x8000	// 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS		0x4000	// 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN		0x2000	// 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR		0x0400	// 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS		0x0200	// 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR		0x0100	// 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE		0x0080	// 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0		0x0040	// 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT	2	// Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK	0x003C
+#define PHY_CFG1_TRF_MASK	0x0003	// Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG		0x11
+#define PHY_CFG2_APOLDIS	0x0020	// 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS		0x0010	// 1=Jabber disabled
+#define PHY_CFG2_MREG		0x0008	// 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO	0x0004	// 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG		0x12	// Status Output (Interrupt Status)
+#define PHY_INT_INT		0x8000	// 1=bits have changed since last read
+#define PHY_INT_LNKFAIL		0x4000	// 1=Link Not detected
+#define PHY_INT_LOSSSYNC	0x2000	// 1=Descrambler has lost sync
+#define PHY_INT_CWRD		0x1000	// 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD		0x0800	// 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD		0x0400	// 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL		0x0200	// 1=Reverse Polarity detected
+#define PHY_INT_JAB		0x0100	// 1=Jabber detected
+#define PHY_INT_SPDDET		0x0080	// 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET		0x0040	// 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG		0x13	// Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
+/*
+ * SMC91C96 ethernet config and status registers.
+ * These are in the "attribute" space.
+ */
+#define ECOR			0x8000
+#define ECOR_RESET		0x80
+#define ECOR_LEVEL_IRQ		0x40
+#define ECOR_WR_ATTRIB		0x04
+#define ECOR_ENABLE		0x01
+
+#define ECSR			0x8002
+#define ECSR_IOIS8		0x20
+#define ECSR_PWRDWN		0x04
+#define ECSR_INT		0x02
+
+
+/*
+ * Macros to abstract register access according to the data bus
+ * capabilities.  Please try to use those and not the in/out primitives.
+ * Note: the following macros do *not* select the bank -- this must
+ * be done separately as needed in the main code.  The SMC_REG() macro
+ * only uses the bank argument for debugging purposes.
+ */
+
+#if SMC_DEBUG > 0
+#define SMC_REG(reg, bank)						\
+	({								\
+		int __b = SMC_CURRENT_BANK();				\
+		if ((__b & ~0xf0) != (0x3300 | bank)) {			\
+			printk( "%s: bank reg screwed (0x%04x)\n",	\
+				CARDNAME, __b );			\
+			BUG();						\
+		}							\
+		reg<<SMC_IO_SHIFT;					\
+	})
+#else
+#define SMC_REG(reg, bank)	(reg<<SMC_IO_SHIFT)
+#endif
+
+#if SMC_CAN_USE_8BIT
+#define SMC_GET_PN()		SMC_inb( ioaddr, PN_REG )
+#define SMC_SET_PN(x)		SMC_outb( x, ioaddr, PN_REG )
+#define SMC_GET_AR()		SMC_inb( ioaddr, AR_REG )
+#define SMC_GET_TXFIFO()	SMC_inb( ioaddr, TXFIFO_REG )
+#define SMC_GET_RXFIFO()	SMC_inb( ioaddr, RXFIFO_REG )
+#define SMC_GET_INT()		SMC_inb( ioaddr, INT_REG )
+#define SMC_ACK_INT(x)		SMC_outb( x, ioaddr, INT_REG )
+#define SMC_GET_INT_MASK()	SMC_inb( ioaddr, IM_REG )
+#define SMC_SET_INT_MASK(x)	SMC_outb( x, ioaddr, IM_REG )
+#else
+#define SMC_GET_PN()		(SMC_inw( ioaddr, PN_REG ) & 0xFF)
+#define SMC_SET_PN(x)		SMC_outw( x, ioaddr, PN_REG )
+#define SMC_GET_AR()		(SMC_inw( ioaddr, PN_REG ) >> 8)
+#define SMC_GET_TXFIFO()	(SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF)
+#define SMC_GET_RXFIFO()	(SMC_inw( ioaddr, TXFIFO_REG ) >> 8)
+#define SMC_GET_INT()		(SMC_inw( ioaddr, INT_REG ) & 0xFF)
+#define SMC_ACK_INT(x)							\
+	do {								\
+		unsigned long __flags;					\
+		int __mask;						\
+		local_irq_save(__flags);				\
+		__mask = SMC_inw( ioaddr, INT_REG ) & ~0xff;		\
+		SMC_outw( __mask | (x), ioaddr, INT_REG );		\
+		local_irq_restore(__flags);				\
+	} while (0)
+#define SMC_GET_INT_MASK()	(SMC_inw( ioaddr, INT_REG ) >> 8)
+#define SMC_SET_INT_MASK(x)	SMC_outw( (x) << 8, ioaddr, INT_REG )
+#endif
+
+#define SMC_CURRENT_BANK()	SMC_inw( ioaddr, BANK_SELECT )
+#define SMC_SELECT_BANK(x)	SMC_outw( x, ioaddr, BANK_SELECT )
+#define SMC_GET_BASE()		SMC_inw( ioaddr, BASE_REG )
+#define SMC_SET_BASE(x)		SMC_outw( x, ioaddr, BASE_REG )
+#define SMC_GET_CONFIG()	SMC_inw( ioaddr, CONFIG_REG )
+#define SMC_SET_CONFIG(x)	SMC_outw( x, ioaddr, CONFIG_REG )
+#define SMC_GET_COUNTER()	SMC_inw( ioaddr, COUNTER_REG )
+#define SMC_GET_CTL()		SMC_inw( ioaddr, CTL_REG )
+#define SMC_SET_CTL(x)		SMC_outw( x, ioaddr, CTL_REG )
+#define SMC_GET_MII()		SMC_inw( ioaddr, MII_REG )
+#define SMC_SET_MII(x)		SMC_outw( x, ioaddr, MII_REG )
+#define SMC_GET_MIR()		SMC_inw( ioaddr, MIR_REG )
+#define SMC_SET_MIR(x)		SMC_outw( x, ioaddr, MIR_REG )
+#define SMC_GET_MMU_CMD()	SMC_inw( ioaddr, MMU_CMD_REG )
+#define SMC_SET_MMU_CMD(x)	SMC_outw( x, ioaddr, MMU_CMD_REG )
+#define SMC_GET_FIFO()		SMC_inw( ioaddr, FIFO_REG )
+#define SMC_GET_PTR()		SMC_inw( ioaddr, PTR_REG )
+#define SMC_SET_PTR(x)		SMC_outw( x, ioaddr, PTR_REG )
+#define SMC_GET_RCR()		SMC_inw( ioaddr, RCR_REG )
+#define SMC_SET_RCR(x)		SMC_outw( x, ioaddr, RCR_REG )
+#define SMC_GET_REV()		SMC_inw( ioaddr, REV_REG )
+#define SMC_GET_RPC()		SMC_inw( ioaddr, RPC_REG )
+#define SMC_SET_RPC(x)		SMC_outw( x, ioaddr, RPC_REG )
+#define SMC_GET_TCR()		SMC_inw( ioaddr, TCR_REG )
+#define SMC_SET_TCR(x)		SMC_outw( x, ioaddr, TCR_REG )
+
+#ifndef SMC_GET_MAC_ADDR
+#define SMC_GET_MAC_ADDR(addr)						\
+	do {								\
+		unsigned int __v;					\
+		__v = SMC_inw( ioaddr, ADDR0_REG );			\
+		addr[0] = __v; addr[1] = __v >> 8;			\
+		__v = SMC_inw( ioaddr, ADDR1_REG );			\
+		addr[2] = __v; addr[3] = __v >> 8;			\
+		__v = SMC_inw( ioaddr, ADDR2_REG );			\
+		addr[4] = __v; addr[5] = __v >> 8;			\
+	} while (0)
+#endif
+
+#define SMC_SET_MAC_ADDR(addr)						\
+	do {								\
+		SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG );	\
+		SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG );	\
+		SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG );	\
+	} while (0)
+
+#define SMC_CLEAR_MCAST()						\
+	do {								\
+		SMC_outw( 0, ioaddr, MCAST_REG1 );			\
+		SMC_outw( 0, ioaddr, MCAST_REG2 );			\
+		SMC_outw( 0, ioaddr, MCAST_REG3 );			\
+		SMC_outw( 0, ioaddr, MCAST_REG4 );			\
+	} while (0)
+#define SMC_SET_MCAST(x)						\
+	do {								\
+		unsigned char *mt = (x);				\
+		SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 );	\
+		SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 );	\
+		SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 );	\
+		SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 );	\
+	} while (0)
+
+#if SMC_CAN_USE_32BIT
+/*
+ * Some setups just can't write 8 or 16 bits reliably when not aligned
+ * to a 32 bit boundary.  I tell you that exists!
+ * We do the ones that can have their low parts written to 0 here.
+ */
+#undef SMC_SELECT_BANK
+#define SMC_SELECT_BANK(x)	SMC_outl( (x)<<16, ioaddr, 12<<SMC_IO_SHIFT )
+#undef SMC_SET_RPC
+#define SMC_SET_RPC(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(8, 0) )
+#undef SMC_SET_PN
+#define SMC_SET_PN(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(0, 2) )
+#undef SMC_SET_PTR
+#define SMC_SET_PTR(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(4, 2) )
+#endif
+
+#if SMC_CAN_USE_32BIT
+#define SMC_PUT_PKT_HDR(status, length)					\
+	SMC_outl( (status) | (length) << 16, ioaddr, DATA_REG )
+#define SMC_GET_PKT_HDR(status, length)					\
+	do {								\
+		unsigned int __val = SMC_inl( ioaddr, DATA_REG );	\
+		(status) = __val & 0xffff;				\
+		(length) = __val >> 16;					\
+	} while (0)
+#else
+#define SMC_PUT_PKT_HDR(status, length)					\
+	do {								\
+		SMC_outw( status, ioaddr, DATA_REG );			\
+		SMC_outw( length, ioaddr, DATA_REG );			\
+	} while (0)
+#define SMC_GET_PKT_HDR(status, length)					\
+	do {								\
+		(status) = SMC_inw( ioaddr, DATA_REG );			\
+		(length) = SMC_inw( ioaddr, DATA_REG );			\
+	} while (0)
+#endif
+
+#if SMC_CAN_USE_32BIT
+#define SMC_PUSH_DATA(p, l)						\
+	do {								\
+		char *__ptr = (p);					\
+		int __len = (l);					\
+		if (__len >= 2 && (long)__ptr & 2) {			\
+			__len -= 2;					\
+			SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\
+		}							\
+		SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2);	\
+		if (__len & 2) {					\
+			__ptr += (__len & ~3);				\
+			SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG );	\
+		}							\
+	} while (0)
+#define SMC_PULL_DATA(p, l)						\
+	do {								\
+		char *__ptr = (p);					\
+		int __len = (l);					\
+		if ((long)__ptr & 2) {					\
+			/*						\
+			 * We want 32bit alignment here.		\
+			 * Since some buses perform a full 32bit	\
+			 * fetch even for 16bit data we can't use	\
+			 * SMC_inw() here.  Back both source (on chip	\
+			 * and destination) pointers of 2 bytes.	\
+			 */						\
+			(long)__ptr &= ~2;				\
+			__len += 2;					\
+			SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC );	\
+		}							\
+		__len += 2;						\
+		SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2);		\
+	} while (0)
+#elif SMC_CAN_USE_16BIT
+#define SMC_PUSH_DATA(p, l)	SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 )
+#define SMC_PULL_DATA(p, l)	SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 )
+#elif SMC_CAN_USE_8BIT
+#define SMC_PUSH_DATA(p, l)	SMC_outsb( ioaddr, DATA_REG, p, l )
+#define SMC_PULL_DATA(p, l)	SMC_insb ( ioaddr, DATA_REG, p, l )
+#endif
+
+#if ! SMC_CAN_USE_16BIT
+#define SMC_outw(x, ioaddr, reg)					\
+	do {								\
+		unsigned int __val16 = (x);				\
+		SMC_outb( __val16, ioaddr, reg );			\
+		SMC_outb( __val16 >> 8, ioaddr, reg + 1 );		\
+	} while (0)
+#define SMC_inw(ioaddr, reg)						\
+	({								\
+		unsigned int __val16;					\
+		__val16 =  SMC_inb( ioaddr, reg );			\
+		__val16 |= SMC_inb( ioaddr, reg + 1 ) << 8;		\
+		__val16;						\
+	})
+#endif
+
+
+#endif  /* _SMC91X_H_ */
diff -urN linux-2.4.19-rmk7/include/asm-arm/arch-sa1100/dnp1110.h linux-2.4.19-rmk7-dnp1/include/asm-arm/arch-sa1100/dnp1110.h
--- linux-2.4.19-rmk7/include/asm-arm/arch-sa1100/dnp1110.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.19-rmk7-dnp1/include/asm-arm/arch-sa1100/dnp1110.h	2003-07-05 16:59:36.000000000 +0200
@@ -0,0 +1,19 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/dnp1110.h
+ *
+ * Created 2001/08/18 by mha@ssv <m.hasewinkel@web.de>
+ *
+ * This file contains the hardware specific definitions for DNP/1110
+ *
+ */
+#ifndef _INCLUDE_ASM_ARCH_DNP1110_H
+#define _INCLUDE_ASM_ARCH_DNP1110_H
+
+#include <asm/arch/hardware.h>
+
+/* see arch/arm/mach-sa1100/dnp1110.c for mappings */
+#define DNP1110_ETH_PHYS	0x20000000
+#define DNP1110_ETH_VIRT	0xf6000000
+#define DNP1110_ETH_IRQ		IRQ_GPIO5
+
+#endif
diff -urN linux-2.4.19-rmk7/include/asm-arm/arch-sa1100/hardware.h linux-2.4.19-rmk7-dnp1/include/asm-arm/arch-sa1100/hardware.h
--- linux-2.4.19-rmk7/include/asm-arm/arch-sa1100/hardware.h	2003-07-05 13:46:42.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/include/asm-arm/arch-sa1100/hardware.h	2003-07-05 14:01:56.000000000 +0200
@@ -120,6 +120,10 @@
 
 #include "badge4.h"
 
+#ifdef CONFIG_SA1100_DNP1110
+#include "dnp1110.h"
+#endif
+
 #include "frodo.h"
 
 #include "h3600.h"
diff -urN linux-2.4.19-rmk7/Makefile linux-2.4.19-rmk7-dnp1/Makefile
--- linux-2.4.19-rmk7/Makefile	2003-07-05 13:46:35.000000000 +0200
+++ linux-2.4.19-rmk7-dnp1/Makefile	2003-07-05 14:00:05.000000000 +0200
@@ -1,11 +1,12 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 19
-EXTRAVERSION = -rmk7
+EXTRAVERSION = -rmk7-dnp1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+ARCH = arm
 KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
@@ -19,7 +20,7 @@
 HOSTCC  	= gcc
 HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
 
-CROSS_COMPILE 	=
+CROSS_COMPILE 	= arm-linux-
 
 #
 # Include the make variables (CC, etc...)
