--- /dev/null
+client
+packages
--- /dev/null
+$1 argument to scripts that have it should be dev or dongle, see autobuild
+for examples.
+
+autobuild - does full clean then full build
+prepare $1 - unpacks busybox tree into $1 dir
+ only to be used after fullclean (or just un-tarred package)
+build $1 $2 - work with busybox under $1 dir. copy config file $2 to busybox
+ and compile it
+ only to be used on a cleaned busybox tree
+clean $1 - runs make distclean on busybox tree in dir $1
+ makes it ready for build
+fullclean - removes busybox trees in order to start from scratch
+
+
--- /dev/null
+#!/bin/bash
+
+./fullclean
+
+./prepare dev
+./prepare dongle
+
+./build dev config-dev-3
+./build dongle config-dongle-2
+
--- /dev/null
+#!/bin/bash
+
+. ../crosstool/cross-var
+
+cd $1/busybox-1.00
+
+cp ../../$2 .config
+make CROSS=${CROSS}
+make CROSS=${CROSS} install
+
--- /dev/null
+#!/bin/bash
+
+cd $1/busybox-1.00
+make distclean
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+HAVE_DOT_CONFIG=y
+
+#
+# General Configuration
+#
+# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set
+CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+# CONFIG_FEATURE_VERBOSE_USAGE is not set
+# CONFIG_FEATURE_INSTALLER is not set
+# CONFIG_LOCALE_SUPPORT is not set
+# CONFIG_FEATURE_DEVFS is not set
+# CONFIG_FEATURE_DEVPTS is not set
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_SUID=y
+CONFIG_FEATURE_SUID_CONFIG=y
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+# CONFIG_SELINUX is not set
+
+#
+# Build Options
+#
+CONFIG_STATIC=y
+# CONFIG_LFS is not set
+USING_CROSS_COMPILER=y
+CROSS_COMPILER_PREFIX="/opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-"
+EXTRA_CFLAGS_OPTIONS=""
+
+#
+# Installation Options
+#
+# CONFIG_INSTALL_NO_USR is not set
+PREFIX="../install"
+
+#
+# Archival Utilities
+#
+# CONFIG_AR is not set
+# CONFIG_BUNZIP2 is not set
+# CONFIG_CPIO is not set
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+CONFIG_GUNZIP=y
+# CONFIG_FEATURE_GUNZIP_UNCOMPRESS is not set
+CONFIG_GZIP=y
+# CONFIG_RPM2CPIO is not set
+# CONFIG_RPM is not set
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+# CONFIG_FEATURE_TAR_BZIP2 is not set
+# CONFIG_FEATURE_TAR_FROM is not set
+CONFIG_FEATURE_TAR_GZIP=y
+# CONFIG_FEATURE_TAR_COMPRESS is not set
+# CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY is not set
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
+# CONFIG_UNCOMPRESS is not set
+# CONFIG_UNZIP is not set
+
+#
+# Common options for cpio and tar
+#
+# CONFIG_FEATURE_UNARCHIVE_TAPE is not set
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+# CONFIG_CAL is not set
+CONFIG_CAT=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_CHROOT=y
+# CONFIG_CMP is not set
+CONFIG_CP=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+
+#
+# date (forced enabled for use with watch)
+#
+CONFIG_FEATURE_DATE_ISOFMT=y
+CONFIG_DD=y
+CONFIG_DF=y
+CONFIG_DIRNAME=y
+# CONFIG_DOS2UNIX is not set
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_EXPR is not set
+CONFIG_FALSE=y
+# CONFIG_FOLD is not set
+CONFIG_HEAD=y
+# CONFIG_FEATURE_FANCY_HEAD is not set
+# CONFIG_HOSTID is not set
+CONFIG_ID=y
+# CONFIG_INSTALL is not set
+# CONFIG_LENGTH is not set
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+# CONFIG_FEATURE_LS_RECURSIVE is not set
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+# CONFIG_MD5SUM is not set
+CONFIG_MKDIR=y
+# CONFIG_MKFIFO is not set
+CONFIG_MKNOD=y
+CONFIG_MV=y
+# CONFIG_OD is not set
+# CONFIG_PRINTF is not set
+CONFIG_PWD=y
+# CONFIG_REALPATH is not set
+CONFIG_RM=y
+CONFIG_RMDIR=y
+# CONFIG_SEQ is not set
+# CONFIG_SHA1SUM is not set
+CONFIG_SLEEP=y
+# CONFIG_FEATURE_FANCY_SLEEP is not set
+CONFIG_SORT=y
+# CONFIG_STTY is not set
+CONFIG_SYNC=y
+CONFIG_TAIL=y
+# CONFIG_FEATURE_FANCY_TAIL is not set
+# CONFIG_TEE is not set
+CONFIG_TEST=y
+
+#
+# test (forced enabled for use with shell)
+#
+# CONFIG_FEATURE_TEST_64 is not set
+CONFIG_TOUCH=y
+# CONFIG_TR is not set
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_UNAME=y
+CONFIG_UNIQ=y
+# CONFIG_USLEEP is not set
+# CONFIG_UUDECODE is not set
+# CONFIG_UUENCODE is not set
+CONFIG_WATCH=y
+# CONFIG_WC is not set
+# CONFIG_WHO is not set
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options for cp and mv
+#
+# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
+
+#
+# Common options for ls and more
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Console Utilities
+#
+# CONFIG_CHVT is not set
+CONFIG_CLEAR=y
+# CONFIG_DEALLOCVT is not set
+# CONFIG_DUMPKMAP is not set
+# CONFIG_LOADFONT is not set
+# CONFIG_LOADKMAP is not set
+# CONFIG_OPENVT is not set
+CONFIG_RESET=y
+# CONFIG_SETKEYCODES is not set
+
+#
+# Debian Utilities
+#
+# CONFIG_MKTEMP is not set
+# CONFIG_PIPE_PROGRESS is not set
+# CONFIG_READLINK is not set
+# CONFIG_RUN_PARTS is not set
+# CONFIG_START_STOP_DAEMON is not set
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+# CONFIG_AWK is not set
+# CONFIG_PATCH is not set
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+# CONFIG_FEATURE_FIND_MTIME is not set
+# CONFIG_FEATURE_FIND_PERM is not set
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_GREP=y
+# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set
+CONFIG_FEATURE_GREP_FGREP_ALIAS=y
+# CONFIG_FEATURE_GREP_CONTEXT is not set
+# CONFIG_XARGS is not set
+
+#
+# Init Utilities
+#
+CONFIG_INIT=y
+CONFIG_FEATURE_USE_INITTAB=y
+# CONFIG_FEATURE_INITRD is not set
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+# CONFIG_FEATURE_EXTRA_QUIET is not set
+# CONFIG_HALT is not set
+# CONFIG_POWEROFF is not set
+CONFIG_REBOOT=y
+# CONFIG_MESG is not set
+
+#
+# Login/Password Management Utilities
+#
+# CONFIG_USE_BB_PWD_GRP is not set
+# CONFIG_ADDGROUP is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_ADDUSER is not set
+# CONFIG_DELUSER is not set
+# CONFIG_GETTY is not set
+# CONFIG_FEATURE_U_W_TMP is not set
+CONFIG_LOGIN=y
+CONFIG_FEATURE_SECURETTY=y
+# CONFIG_PASSWD is not set
+# CONFIG_SU is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Common options for adduser, deluser, login, su
+#
+# CONFIG_FEATURE_SHADOWPASSWDS is not set
+
+#
+# Miscellaneous Utilities
+#
+# CONFIG_ADJTIMEX is not set
+# CONFIG_CROND is not set
+# CONFIG_CRONTAB is not set
+# CONFIG_DC is not set
+# CONFIG_DEVFSD is not set
+# CONFIG_LAST is not set
+# CONFIG_HDPARM is not set
+# CONFIG_MAKEDEVS is not set
+# CONFIG_MT is not set
+# CONFIG_RX is not set
+# CONFIG_STRINGS is not set
+# CONFIG_TIME is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Linux Module Utilities
+#
+CONFIG_INSMOD=y
+CONFIG_FEATURE_2_4_MODULES=y
+# CONFIG_FEATURE_2_6_MODULES is not set
+CONFIG_FEATURE_INSMOD_VERSION_CHECKING=y
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+CONFIG_LSMOD=y
+CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y
+CONFIG_MODPROBE=y
+CONFIG_RMMOD=y
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+
+#
+# Networking Utilities
+#
+# CONFIG_FEATURE_IPV6 is not set
+# CONFIG_ARPING is not set
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+CONFIG_HOSTNAME=y
+# CONFIG_HTTPD is not set
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+CONFIG_FEATURE_IFCONFIG_HW=y
+# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
+# CONFIG_IFUPDOWN is not set
+# CONFIG_INETD is not set
+# CONFIG_IP is not set
+# CONFIG_IPCALC is not set
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_NAMEIF is not set
+# CONFIG_NC is not set
+CONFIG_NETSTAT=y
+CONFIG_NSLOOKUP=y
+CONFIG_PING=y
+CONFIG_FEATURE_FANCY_PING=y
+CONFIG_ROUTE=y
+# CONFIG_TELNET is not set
+CONFIG_TELNETD=y
+# CONFIG_FEATURE_TELNETD_INETD is not set
+# CONFIG_TFTP is not set
+# CONFIG_TRACEROUTE is not set
+# CONFIG_VCONFIG is not set
+# CONFIG_WGET is not set
+
+#
+# udhcp Server/Client
+#
+# CONFIG_UDHCPD is not set
+# CONFIG_UDHCPC is not set
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+# CONFIG_PIDOF is not set
+CONFIG_PS=y
+# CONFIG_RENICE is not set
+CONFIG_TOP=y
+FEATURE_CPU_USAGE_PERCENTAGE=y
+CONFIG_UPTIME=y
+# CONFIG_SYSCTL is not set
+
+#
+# Another Bourne-like Shell
+#
+CONFIG_FEATURE_SH_IS_ASH=y
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_LASH is not set
+# CONFIG_FEATURE_SH_IS_MSH is not set
+# CONFIG_FEATURE_SH_IS_NONE is not set
+CONFIG_ASH=y
+
+#
+# Ash Shell Options
+#
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_ALIAS=y
+CONFIG_ASH_MATH_SUPPORT=y
+# CONFIG_ASH_MATH_SUPPORT_64 is not set
+# CONFIG_ASH_GETOPTS is not set
+# CONFIG_ASH_CMDCMD is not set
+# CONFIG_ASH_MAIL is not set
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+# CONFIG_ASH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH is not set
+# CONFIG_LASH is not set
+# CONFIG_MSH is not set
+
+#
+# Bourne Shell Options
+#
+# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
+# CONFIG_FEATURE_SH_STANDALONE_SHELL is not set
+CONFIG_FEATURE_COMMAND_EDITING=y
+CONFIG_FEATURE_COMMAND_HISTORY=15
+# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set
+CONFIG_FEATURE_COMMAND_TAB_COMPLETION=y
+# CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION is not set
+CONFIG_FEATURE_SH_FANCY_PROMPT=y
+
+#
+# System Logging Utilities
+#
+CONFIG_SYSLOGD=y
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+# CONFIG_FEATURE_REMOTE_LOG is not set
+# CONFIG_FEATURE_IPC_SYSLOG is not set
+CONFIG_KLOGD=y
+CONFIG_LOGGER=y
+
+#
+# Linux System Utilities
+#
+CONFIG_DMESG=y
+# CONFIG_FBSET is not set
+# CONFIG_FDFLUSH is not set
+# CONFIG_FDFORMAT is not set
+# CONFIG_FDISK is not set
+# CONFIG_FREERAMDISK is not set
+# CONFIG_FSCK_MINIX is not set
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_GETOPT is not set
+# CONFIG_HEXDUMP is not set
+# CONFIG_HWCLOCK is not set
+# CONFIG_LOSETUP is not set
+# CONFIG_MKSWAP is not set
+CONFIG_MORE=y
+CONFIG_FEATURE_USE_TERMIOS=y
+# CONFIG_PIVOT_ROOT is not set
+# CONFIG_RDATE is not set
+# CONFIG_SWAPONOFF is not set
+CONFIG_MOUNT=y
+CONFIG_NFSMOUNT=y
+CONFIG_UMOUNT=y
+# CONFIG_FEATURE_MOUNT_FORCE is not set
+
+#
+# Common options for mount/umount
+#
+# CONFIG_FEATURE_MOUNT_LOOP is not set
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+HAVE_DOT_CONFIG=y
+
+#
+# General Configuration
+#
+# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set
+CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+# CONFIG_FEATURE_VERBOSE_USAGE is not set
+# CONFIG_FEATURE_INSTALLER is not set
+# CONFIG_LOCALE_SUPPORT is not set
+# CONFIG_FEATURE_DEVFS is not set
+# CONFIG_FEATURE_DEVPTS is not set
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_SUID=y
+CONFIG_FEATURE_SUID_CONFIG=y
+CONFIG_FEATURE_SUID_CONFIG_QUIET=y
+# CONFIG_SELINUX is not set
+
+#
+# Build Options
+#
+CONFIG_STATIC=y
+# CONFIG_LFS is not set
+USING_CROSS_COMPILER=y
+CROSS_COMPILER_PREFIX="/opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-"
+EXTRA_CFLAGS_OPTIONS=""
+
+#
+# Installation Options
+#
+# CONFIG_INSTALL_NO_USR is not set
+PREFIX="../install"
+
+#
+# Archival Utilities
+#
+# CONFIG_AR is not set
+# CONFIG_BUNZIP2 is not set
+# CONFIG_CPIO is not set
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+# CONFIG_GUNZIP is not set
+# CONFIG_GZIP is not set
+# CONFIG_RPM2CPIO is not set
+# CONFIG_RPM is not set
+# CONFIG_TAR is not set
+# CONFIG_UNCOMPRESS is not set
+# CONFIG_UNZIP is not set
+
+#
+# Coreutils
+#
+# CONFIG_BASENAME is not set
+# CONFIG_CAL is not set
+CONFIG_CAT=y
+# CONFIG_CHGRP is not set
+# CONFIG_CHMOD is not set
+# CONFIG_CHOWN is not set
+# CONFIG_CHROOT is not set
+# CONFIG_CMP is not set
+# CONFIG_CP is not set
+# CONFIG_CUT is not set
+CONFIG_DATE=y
+# CONFIG_FEATURE_DATE_ISOFMT is not set
+# CONFIG_DD is not set
+CONFIG_DF=y
+# CONFIG_DIRNAME is not set
+# CONFIG_DOS2UNIX is not set
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_EXPR is not set
+CONFIG_FALSE=y
+# CONFIG_FOLD is not set
+# CONFIG_HEAD is not set
+# CONFIG_HOSTID is not set
+CONFIG_ID=y
+# CONFIG_INSTALL is not set
+# CONFIG_LENGTH is not set
+# CONFIG_LN is not set
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+# CONFIG_FEATURE_LS_RECURSIVE is not set
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+# CONFIG_MD5SUM is not set
+# CONFIG_MKDIR is not set
+# CONFIG_MKFIFO is not set
+# CONFIG_MKNOD is not set
+# CONFIG_MV is not set
+# CONFIG_OD is not set
+# CONFIG_PRINTF is not set
+CONFIG_PWD=y
+# CONFIG_REALPATH is not set
+# CONFIG_RM is not set
+# CONFIG_RMDIR is not set
+# CONFIG_SEQ is not set
+# CONFIG_SHA1SUM is not set
+# CONFIG_SLEEP is not set
+# CONFIG_SORT is not set
+# CONFIG_STTY is not set
+# CONFIG_SYNC is not set
+# CONFIG_TAIL is not set
+# CONFIG_TEE is not set
+CONFIG_TEST=y
+
+#
+# test (forced enabled for use with shell)
+#
+# CONFIG_FEATURE_TEST_64 is not set
+# CONFIG_TOUCH is not set
+# CONFIG_TR is not set
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_UNAME=y
+# CONFIG_UNIQ is not set
+# CONFIG_USLEEP is not set
+# CONFIG_UUDECODE is not set
+# CONFIG_UUENCODE is not set
+# CONFIG_WATCH is not set
+# CONFIG_WC is not set
+# CONFIG_WHO is not set
+CONFIG_WHOAMI=y
+# CONFIG_YES is not set
+
+#
+# Common options for ls and more
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Console Utilities
+#
+# CONFIG_CHVT is not set
+CONFIG_CLEAR=y
+# CONFIG_DEALLOCVT is not set
+# CONFIG_DUMPKMAP is not set
+# CONFIG_LOADFONT is not set
+# CONFIG_LOADKMAP is not set
+# CONFIG_OPENVT is not set
+CONFIG_RESET=y
+# CONFIG_SETKEYCODES is not set
+
+#
+# Debian Utilities
+#
+# CONFIG_MKTEMP is not set
+# CONFIG_PIPE_PROGRESS is not set
+# CONFIG_READLINK is not set
+# CONFIG_RUN_PARTS is not set
+# CONFIG_START_STOP_DAEMON is not set
+# CONFIG_WHICH is not set
+
+#
+# Editors
+#
+# CONFIG_AWK is not set
+# CONFIG_PATCH is not set
+# CONFIG_SED is not set
+# CONFIG_VI is not set
+
+#
+# Finding Utilities
+#
+# CONFIG_FIND is not set
+# CONFIG_GREP is not set
+# CONFIG_XARGS is not set
+
+#
+# Init Utilities
+#
+CONFIG_INIT=y
+CONFIG_FEATURE_USE_INITTAB=y
+CONFIG_FEATURE_INITRD=y
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_FEATURE_EXTRA_QUIET=y
+# CONFIG_HALT is not set
+# CONFIG_POWEROFF is not set
+CONFIG_REBOOT=y
+# CONFIG_MESG is not set
+
+#
+# Login/Password Management Utilities
+#
+CONFIG_USE_BB_PWD_GRP=y
+# CONFIG_ADDGROUP is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_ADDUSER is not set
+# CONFIG_DELUSER is not set
+# CONFIG_GETTY is not set
+# CONFIG_FEATURE_U_W_TMP is not set
+CONFIG_LOGIN=y
+CONFIG_FEATURE_SECURETTY=y
+# CONFIG_PASSWD is not set
+# CONFIG_SU is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Common options for adduser, deluser, login, su
+#
+# CONFIG_FEATURE_SHADOWPASSWDS is not set
+
+#
+# Miscellaneous Utilities
+#
+# CONFIG_ADJTIMEX is not set
+# CONFIG_CROND is not set
+# CONFIG_CRONTAB is not set
+# CONFIG_DC is not set
+# CONFIG_DEVFSD is not set
+# CONFIG_LAST is not set
+# CONFIG_HDPARM is not set
+# CONFIG_MAKEDEVS is not set
+# CONFIG_MT is not set
+# CONFIG_RX is not set
+# CONFIG_STRINGS is not set
+# CONFIG_TIME is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Linux Module Utilities
+#
+CONFIG_INSMOD=y
+CONFIG_FEATURE_2_4_MODULES=y
+# CONFIG_FEATURE_2_6_MODULES is not set
+CONFIG_FEATURE_INSMOD_VERSION_CHECKING=y
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+CONFIG_LSMOD=y
+CONFIG_FEATURE_QUERY_MODULE_INTERFACE=y
+CONFIG_MODPROBE=y
+CONFIG_RMMOD=y
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+
+#
+# Networking Utilities
+#
+# CONFIG_FEATURE_IPV6 is not set
+# CONFIG_ARPING is not set
+# CONFIG_FTPGET is not set
+# CONFIG_FTPPUT is not set
+CONFIG_HOSTNAME=y
+# CONFIG_HTTPD is not set
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+CONFIG_FEATURE_IFCONFIG_HW=y
+# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
+# CONFIG_IFUPDOWN is not set
+# CONFIG_INETD is not set
+# CONFIG_IP is not set
+# CONFIG_IPCALC is not set
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_NAMEIF is not set
+# CONFIG_NC is not set
+CONFIG_NETSTAT=y
+# CONFIG_NSLOOKUP is not set
+CONFIG_PING=y
+CONFIG_FEATURE_FANCY_PING=y
+CONFIG_ROUTE=y
+# CONFIG_TELNET is not set
+CONFIG_TELNETD=y
+# CONFIG_FEATURE_TELNETD_INETD is not set
+# CONFIG_TFTP is not set
+# CONFIG_TRACEROUTE is not set
+# CONFIG_VCONFIG is not set
+# CONFIG_WGET is not set
+
+#
+# udhcp Server/Client
+#
+# CONFIG_UDHCPD is not set
+# CONFIG_UDHCPC is not set
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+# CONFIG_PIDOF is not set
+CONFIG_PS=y
+# CONFIG_RENICE is not set
+CONFIG_TOP=y
+FEATURE_CPU_USAGE_PERCENTAGE=y
+CONFIG_UPTIME=y
+# CONFIG_SYSCTL is not set
+
+#
+# Another Bourne-like Shell
+#
+CONFIG_FEATURE_SH_IS_ASH=y
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_LASH is not set
+# CONFIG_FEATURE_SH_IS_MSH is not set
+# CONFIG_FEATURE_SH_IS_NONE is not set
+CONFIG_ASH=y
+
+#
+# Ash Shell Options
+#
+CONFIG_ASH_JOB_CONTROL=y
+# CONFIG_ASH_ALIAS is not set
+# CONFIG_ASH_MATH_SUPPORT is not set
+# CONFIG_ASH_GETOPTS is not set
+# CONFIG_ASH_CMDCMD is not set
+# CONFIG_ASH_MAIL is not set
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+# CONFIG_ASH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH is not set
+# CONFIG_LASH is not set
+# CONFIG_MSH is not set
+
+#
+# Bourne Shell Options
+#
+# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
+# CONFIG_FEATURE_SH_STANDALONE_SHELL is not set
+CONFIG_FEATURE_COMMAND_EDITING=y
+CONFIG_FEATURE_COMMAND_HISTORY=15
+# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set
+CONFIG_FEATURE_COMMAND_TAB_COMPLETION=y
+# CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION is not set
+CONFIG_FEATURE_SH_FANCY_PROMPT=y
+
+#
+# System Logging Utilities
+#
+CONFIG_SYSLOGD=y
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+CONFIG_FEATURE_REMOTE_LOG=y
+# CONFIG_FEATURE_IPC_SYSLOG is not set
+CONFIG_KLOGD=y
+CONFIG_LOGGER=y
+
+#
+# Linux System Utilities
+#
+CONFIG_DMESG=y
+# CONFIG_FBSET is not set
+# CONFIG_FDFLUSH is not set
+# CONFIG_FDFORMAT is not set
+# CONFIG_FDISK is not set
+# CONFIG_FREERAMDISK is not set
+# CONFIG_FSCK_MINIX is not set
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_GETOPT is not set
+# CONFIG_HEXDUMP is not set
+# CONFIG_HWCLOCK is not set
+# CONFIG_LOSETUP is not set
+# CONFIG_MKSWAP is not set
+# CONFIG_MORE is not set
+# CONFIG_PIVOT_ROOT is not set
+# CONFIG_RDATE is not set
+# CONFIG_SWAPONOFF is not set
+CONFIG_MOUNT=y
+# CONFIG_NFSMOUNT is not set
+CONFIG_UMOUNT=y
+# CONFIG_FEATURE_MOUNT_FORCE is not set
+
+#
+# Common options for mount/umount
+#
+# CONFIG_FEATURE_MOUNT_LOOP is not set
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
--- /dev/null
+#!/bin/bash
+
+rm -rf dev dongle
--- /dev/null
+#!/bin/bash
+
+mkdir $1
+cd $1
+tar -jxvf ../../packages/busybox-1.00.tar.bz2
+
--- /dev/null
+autobuild - does full clean, unpacks crosstool and runs build
+prepare - unpacks the crosstool sources
+build - uses crosstool to build a compiler
+clean - removes everything except files downloaded by crosstool
+fullclean - removes everything
--- /dev/null
+#!/bin/bash
+
+./fullclean
+./prepare
+./build
--- /dev/null
+#!/bin/sh
+# Adapted from the demo-powerpc-405 script in crosstool
+
+set -ex
+TARBALLS_DIR=`pwd`/downloads
+RESULT_TOP=`pwd`
+export TARBALLS_DIR RESULT_TOP
+GCC_LANGUAGES="c,c++"
+export GCC_LANGUAGES
+
+cd crosstool-0.43
+eval `cat powerpc-405.dat gcc-3.4.5-glibc-2.2.5.dat` sh all.sh --notest
+cd ..
+
+echo export CROSS=`pwd`/gcc-3.4.5-glibc-2.2.5/powerpc-405-linux-gnu/bin/powerpc-405-linux-gnu- > cross-var
+
+echo Done.
--- /dev/null
+#!/bin/bash
+
+rm -rf cross-var crosstool-0.43 gcc-3.4.5-glibc-2.2.5
--- /dev/null
+#!/bin/bash
+
+rm -rf cross-var crosstool-0.43 gcc-3.4.5-glibc-2.2.5 downloads
+
--- /dev/null
+Fixes\r
+checking version of powerpc-405-linux-gnu-gcc ... 4.0.0, bad\r
+checking for gnumake... no\r
+checking for gmake... no\r
+checking for make... make\r
+checking version of make... 3.80, ok\r
+configure: error:\r
+*** These critical programs are missing or too old:gcc \r
+\r
+\r
+--- glibc-2.2.5/configure.old 2005-03-10 00:23:46.374213600 -0800\r
++++ glibc-2.2.5/configure 2005-03-10 00:25:13.313996744 -0800\r
+@@ -1476,7 +1476,7 @@\r
+ ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`\r
+ case $ac_prog_version in\r
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;\r
+- *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*)\r
++ *gcc-2.9[5-9].*|*2.8.[1-9]*|*2.9|*2.9.[0-9]*|2.9[5-9]*|3.[0-9]*|4.[01234]*|cygnus-2.9[1-9]*|gcc-2.9[5-9]|gcc-2.1[0-9][0-9]|sgicc-*)\r
+ ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;\r
+ *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;\r
+ \r
+\r
--- /dev/null
+#!/bin/bash
+
+# Avoid downloading from GNU
+mkdir downloads
+ln -s ../../packages/binutils-2.15.tar.bz2 downloads
+ln -s ../../packages/glibc-2.2.5.tar.gz downloads
+ln -s ../../packages/linux-2.6.8.tar.bz2 downloads
+ln -s ../../packages/gcc-3.4.5.tar.bz2 downloads
+ln -s ../../packages/glibc-linuxthreads-2.2.5.tar.gz downloads
+
+tar -zxvf ../packages/crosstool-0.43.tar.gz
+rm -fv crosstool-0.43/patches/glibc-2.2.5/glibc-2.2.5-allow-gcc-4.0-configure.patch
+cp -v glibc-2.2.5-allow-gcc-4.0-configure.patch crosstool-0.43/patches/glibc-2.2.5
--- /dev/null
+autobuild - does fullclean, prepare, build
+prepare - sets up genext2fs
+build - builds the dongle
+fullclean - removes temporary build files, genext2fs and the dongle
--- /dev/null
+#!/bin/bash
+./fullclean
+./prepare
+./build
--- /dev/null
+#!/bin/bash
+
+. ../crosstool/cross-var
+
+LKERN=../kernel/dongle/linux-2.4.31
+LGENFS=genext2fs-1.4/genext2fs
+OUTFILE=vomp-dongle
+
+# Create initial file system
+
+cp -a ../busybox/dongle/install fs
+cp -a tofs/* fs
+
+# Insert vompclient
+
+cp -fv ../client/vompclient fs
+cp -fv ../client/other/*.jpg fs
+cp -fv ../lbox_border/lbox_border.o fs/lib/modules/2.4.31
+
+# Get kernel files temp dir ready
+
+mkdir kernel_temp
+BOOT=${LKERN}/arch/ppc/boot
+CFILES=${BOOT}/common/{dummy,misc-common,ns16550,relocate,string,util,serial_stub}.o
+SFILES=${BOOT}/simple/{embed_config,head,misc-embedded}.o
+KFILE=${BOOT}/images/vmlinux.gz
+FILES=`sh -c "echo $CFILES $SFILES $KFILE ${BOOT}/lib/zlib.a ${BOOT}/ld.script"`
+cp $FILES kernel_temp
+
+# Check filesystem size
+
+RAMDISK_SIZE=`du -ks fs | cut -f 1`
+let RAMDISK_SIZE=$RAMDISK_SIZE+300
+if [ $RAMDISK_SIZE -gt 4096 ] ; then
+ echo "ramdisk too big"
+ exit
+fi
+
+# Create the ramdisk out of the fs directory
+
+${LGENFS} -d fs -b ${RAMDISK_SIZE} -D devtable ramdisk
+/bin/gzip ramdisk
+
+# Put it all together
+
+mkdir build_temp
+
+# make_dongle() - this is straight out of arch/ppc in the linux tree
+
+OBJCOPY=${CROSS}objcopy
+LD=${CROSS}ld
+
+$OBJCOPY -O elf32-powerpc \
+ --add-section=.ramdisk=ramdisk.gz \
+ --set-section-flags=.ramdisk=contents,alloc,load,readonly,data \
+ --add-section=.image=kernel_temp/vmlinux.gz \
+ --set-section-flags=.image=contents,alloc,load,readonly,data \
+ kernel_temp/dummy.o build_temp/image.o
+
+$LD -T kernel_temp/ld.script -Ttext 0x00400000 -Bstatic -o build_temp/zvmlinux.initrd \
+ kernel_temp/head.o kernel_temp/relocate.o kernel_temp/misc-embedded.o \
+ kernel_temp/misc-common.o kernel_temp/string.o kernel_temp/util.o kernel_temp/serial_stub.o \
+ kernel_temp/embed_config.o kernel_temp/ns16550.o build_temp/image.o \
+ kernel_temp/zlib.a
+
+$OBJCOPY -O elf32-powerpc build_temp/zvmlinux.initrd build_temp/zvmlinux.initrd \
+ -R .comment -R .stab -R .stabstr -R .sysmap
+
+${LKERN}/arch/ppc/boot/utils/mktree build_temp/zvmlinux.initrd $OUTFILE
+
+# Clean up
+
+rm -f ramdisk.gz
+rm -rf build_temp
+rm -rf kernel_temp
+rm -rf fs
+
+# Install to tftp location
+
+if [ -d /diskless/tftp/mvp ] && [ -w /diskless/tftp/mvp ]
+then
+ cp -v $OUTFILE /diskless/tftp/mvp
+fi
+
+if [ -d /diskless/tftp/wmvp ] && [ -w /diskless/tftp/wmvp ]
+then
+ cp -v $OUTFILE /diskless/tftp/wmvp
+fi
--- /dev/null
+# name type mode uid gid major minor start inc count
+
+/dev/adec_ac3 c 600 0 0 202 1 0 0
+/dev/adec_dev c 600 0 0 202 0 0 0
+/dev/adec_mixer c 600 0 0 202 3 0 0
+/dev/adec_mpg c 600 0 0 202 0 0 0
+/dev/adec_pcm c 600 0 0 202 2 0 0
+/dev/aud_mpeg c 600 0 0 202 0 0 0
+/dev/console c 600 0 0 5 1 0 0
+/dev/fb0 c 600 0 0 29 0 0 0
+/dev/fb1 c 600 0 0 29 1 0 0
+/dev/full c 600 0 0 1 7 0 0
+/dev/irmouse c 600 0 0 10 11 0 0
+/dev/kmem c 600 0 0 1 2 0 0
+/dev/mem c 600 0 0 1 1 0 0
+/dev/mtd0 c 600 0 0 90 0 0 0
+/dev/mtd1 c 600 0 0 90 2 0 0
+/dev/mtd2 c 600 0 0 90 4 0 0
+/dev/mtd3 c 600 0 0 90 6 0 0
+/dev/mtd4 c 600 0 0 90 8 0 0
+/dev/mtdblock0 b 600 0 0 31 0 0 0
+/dev/mtdblock1 b 600 0 0 31 1 0 0
+/dev/null c 600 0 0 1 3 0 0
+/dev/port c 600 0 0 1 4 0 0
+/dev/ptyp0 c 600 0 0 2 0 0 0
+/dev/ptyp1 c 600 0 0 2 1 0 0
+/dev/ptyp2 c 600 0 0 2 2 0 0
+/dev/ptyp3 c 600 0 0 2 3 0 0
+/dev/ptyp4 c 600 0 0 2 4 0 0
+/dev/ram0 b 600 0 0 1 0 0 0
+/dev/ram1 b 600 0 0 1 1 0 0
+/dev/ram2 b 600 0 0 1 2 0 0
+/dev/random c 600 0 0 1 8 0 0
+/dev/rawir c 600 0 0 100 0 0 0
+/dev/stbgfx c 600 0 0 251 0 0 0
+/dev/tty c 600 0 0 5 0 0 0
+/dev/tty0 c 600 0 0 4 0 0 0
+/dev/tty5 c 600 0 0 4 5 0 0
+/dev/ttyS0 c 600 0 0 4 64 0 0
+/dev/ttyp0 c 600 0 0 3 0 0 0
+/dev/ttyp1 c 600 0 0 3 1 0 0
+/dev/ttyp2 c 600 0 0 3 2 0 0
+/dev/ttyp3 c 600 0 0 3 3 0 0
+/dev/urandom c 600 0 0 1 9 0 0
+/dev/vdec_dev c 600 0 0 203 0 0 0
+/dev/vid c 600 0 0 203 0 0 0
+/dev/xram c 600 0 0 63 0 0 0
+/dev/zero c 600 0 0 1 5 0 0
--- /dev/null
+#!/bin/bash
+
+rm -rf ramdisk.gz build_temp kernel_temp fs vomp-dongle genext2fs-1.4
+
--- /dev/null
+#!/bin/bash
+
+tar -zxvf ../packages/genext2fs-1.4.tar.gz
+cd genext2fs-1.4
+./configure
+make
--- /dev/null
+fb0
\ No newline at end of file
--- /dev/null
+../proc/kcore
\ No newline at end of file
--- /dev/null
+irmouse
\ No newline at end of file
--- /dev/null
+ram1
\ No newline at end of file
--- /dev/null
+ram0
\ No newline at end of file
--- /dev/null
+../proc/self/fd/2
\ No newline at end of file
--- /dev/null
+../proc/self/fd/0
\ No newline at end of file
--- /dev/null
+../proc/self/fd/1
\ No newline at end of file
--- /dev/null
+/proc /proc proc defaults 0 0
--- /dev/null
+127.0.0.1 localhost localhost
--- /dev/null
+::sysinit:/etc/rcS
+::restart:/sbin/init
--- /dev/null
+VOMP Client
+
+
--- /dev/null
+root::0:0:root:/:/bin/sh
--- /dev/null
+
+# default timezone
+#TZ=CST+6CDT,M4.1.0/2,M10.5.0/2
+#export TZ
+
+# if shell.config exist then source it.
+# shell.config should be created by dongle.config
+# eg: to set timezone to EST
+# echo "TZ=EST+5EDT,M4.1.0/2,M10.5.0/2; export TZ" > /etc/shell.config
+#
+#if [ -r /etc/shell.config ]; then
+# . /etc/shell.config
+#fi
--- /dev/null
+#!/bin/sh
+#
+# Mount everything in /etc/fstab
+#
+/bin/umount -a
+/bin/mount -a -o rw
+
+#
+# Configure lo0
+# eth0 will be autoconfigured by the kernel
+#
+/sbin/ifconfig lo 127.0.0.1
+
+#
+# Start telnetd
+#
+/usr/sbin/telnetd
+
+#
+# Load kernel modules
+#
+insmod -f os_core
+insmod -f av_core _fmt=1
+insmod -f ircombo
+insmod -f gfx
+insmod -f osdfb
+#insmod ac3_mod
+#insmod xrmod
+insmod lbox_border
+
+#udhcpc
+#. /etc/udhcpc.config
+
+/vompclient
--- /dev/null
+
+autobuild - runs fullclean, prepare, build
+prepare - unpacks the jpeg library sources
+build - builds the jpeg library
+clean - cleans the jpeg library source tree
+fullclean - removes the jpeg library source tree
--- /dev/null
+#!/bin/bash
+./fullclean
+./prepare
+./build
--- /dev/null
+#!/bin/bash
+
+. ../crosstool/cross-var
+
+export CC=${CROSS}gcc
+export AR=${CROSS}ar
+export RANLIB=${CROSS}ranlib
+
+cd jpeg-6b
+./configure
+make
--- /dev/null
+#!/bin/bash
+
+cd jpeg-6b
+make distclean
--- /dev/null
+#!/bin/bash
+
+rm -rf jpeg-6b
--- /dev/null
+#!/bin/bash
+
+tar -zxvf ../packages/jpegsrc.v6b.tar.gz
--- /dev/null
+$1 argument to scripts that have it should be dev or dongle, see autobuild
+for examples.
+
+autobuild - does full clean then full build
+prepare $1 - unpacks kernel tree into $1 dir and runs patch on it
+ only to be used after fullclean (or just un-tarred package)
+patch $1 - applies patches to kernel under $1 dir
+build $1 $2 - work with kernel under $1 dir. copy config file $2 to kernel
+ and compile kernel
+ only to be used on a cleaned and patched kernel tree
+clean $1 - runs make mrproper on kernel tree in dir $1
+ makes it ready for build
+fullclean - removes kernel trees in order to start from scratch
+
+
--- /dev/null
+#!/bin/bash
+
+./fullclean
+
+./prepare dev
+./prepare dongle
+
+./build dev config-dev-5
+./build dongle config-dongle-2
+
--- /dev/null
+#!/bin/bash
+
+. ../crosstool/cross-var
+
+export ARCH=ppc
+export CROSS_COMPILE=${CROSS}
+export EXTRAVERSION=-v1.1-hcwmvp
+
+cd $1/linux-2.4.31
+cp ../../$2 .config
+make oldconfig
+make dep
+make zImage
--- /dev/null
+#!/bin/bash
+
+cd $1/linux-2.4.31
+make mrproper
--- /dev/null
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+CONFIG_REDWOOD_6=y
+# CONFIG_OAK is not set
+# CONFIG_WALNUT is not set
+CONFIG_HCW_MVP=y
+# CONFIG_SMP is not set
+CONFIG_KEXEC=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_STB03xxx=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_STBXXX_DMA=y
+CONFIG_IBM_OPENBIOS=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_PCI is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 profile=3 root=/dev/nfs ip=:::::eth0:dhcp"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_TQM8XXL is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_MBX860 is not set
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+CONFIG_MTD_REDWOOD=y
+CONFIG_MTD_MVP_RAM=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS 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=y
+# CONFIG_PACKET_MMAP 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=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK 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
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET 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_SMC91111=y
+CONFIG_SMC91111_ADVANCED=y
+CONFIG_SMC91111_BYTE_SWAP=y
+# CONFIG_SMC91111_USE_8_BIT is not set
+# CONFIG_SMC91111_USE_32_BIT is not set
+# CONFIG_NET_VENDOR_RACAL 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_E1000 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_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# On-chip net devices
+#
+# CONFIG_IBM_OCP_ENET 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
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# 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
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_PPC405_ALGO is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# 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
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_PROC_FS is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 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_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG 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_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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 is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG 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_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP 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
+
+#
+# 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
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=0
--- /dev/null
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8xx is not set
+CONFIG_4xx=y
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+CONFIG_REDWOOD_6=y
+# CONFIG_OAK is not set
+# CONFIG_WALNUT is not set
+CONFIG_HCW_MVP=y
+# CONFIG_SMP is not set
+CONFIG_KEXEC=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_STB03xxx=y
+CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
+CONFIG_405=y
+CONFIG_IBM405_ERR51=y
+CONFIG_IBM405_ERR77=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_STBXXX_DMA=y
+CONFIG_IBM_OPENBIOS=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_PCI is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_PPC_RTC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 ip=:::::eth0:dhcp root=/dev/ram0"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_OBSOLETE_CHIPS=y
+CONFIG_MTD_AMDSTD=y
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_TQM8XXL is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_MBX860 is not set
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+CONFIG_MTD_REDWOOD=y
+# CONFIG_MTD_MVP_RAM is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND 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_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS 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=y
+# CONFIG_PACKET_MMAP 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=y
+# 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_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK 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
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI 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_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_OAKNET 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_SMC91111=y
+CONFIG_SMC91111_ADVANCED=y
+CONFIG_SMC91111_BYTE_SWAP=y
+# CONFIG_SMC91111_USE_8_BIT is not set
+# CONFIG_SMC91111_USE_32_BIT is not set
+# CONFIG_NET_VENDOR_RACAL 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_E1000 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_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# On-chip net devices
+#
+# CONFIG_IBM_OCP_ENET 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
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# 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
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_PPC405_ALGO is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+
+#
+# Mice
+#
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# 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
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_PROC_FS is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 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_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG 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=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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 is not set
+# CONFIG_DEVFS_MOUNT is not set
+# 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=y
+# 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
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# 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
+
+#
+# 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
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=0
--- /dev/null
+#!/bin/bash
+
+rm -rf dev dongle
--- /dev/null
+diff -Naur linux-2.4.31-orig/Makefile linux-2.4.31/Makefile
+--- linux-2.4.31-orig/Makefile 2007-01-26 23:52:46.000000000 +0000
++++ linux-2.4.31/Makefile 2007-01-26 23:53:13.000000000 +0000
+@@ -21,8 +21,8 @@
+
+ #CROSS_COMPILE =
+
+-ARCH=ppc
+-CROSS_COMPILE = powerpc-405-linux-gnu-
++#ARCH=ppc
++#CROSS_COMPILE = powerpc-405-linux-gnu-
+
+ #
+ # Include the make variables (CC, etc...)
--- /dev/null
+diff -Naur linux-2.4.31.orig/scripts/Configure linux-2.4.31/scripts/Configure
+--- linux-2.4.31.orig/scripts/Configure 2005-04-04 03:42:20.000000000 +0200
++++ linux-2.4.31/scripts/Configure 2011-11-01 12:37:25.000000000 +0100
+@@ -546,10 +546,10 @@
+ echo "#"
+ echo "# Using defaults found in" $DEFAULTS
+ echo "#"
+- . $DEFAULTS
++ . `pwd`/$DEFAULTS
+ sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
+- . .config-is-not.$$
+- rm .config-is-not.$$
++ . `pwd`/.config-is-not.$$
++ rm `pwd`/.config-is-not.$$
+ else
+ echo "#"
+ echo "# No defaults found"
--- /dev/null
+/* _______________________________________________________________________
+ dongle_version.h - Contains constants for current compatible and build
+ Versions
+
+ first created: 9/8/2005
+ last modified: 9/8/2005
+
+ tab size = 4
+
+ copyright © 1999-2005 by Hauppauge Computer Works - all rights reserved.
+ _______________________________________________________________________*/
+
+#ifndef _dongle_version_
+#define _dongle_version_
+
+#define HCW_COMPATIBLE_VERSION 0x01010003
+#define HCW_BUILD_VERSION 0x01012C03
+
+#endif /* _dongle_version_ */
+
+/*______________________________________________________________________*/
--- /dev/null
+diff -Narup kernel/drivers/net/smc91111.c dev/mvpdist/kernel/drivers/net/smc91111.c
+--- kernel/drivers/net/smc91111.c 2003-11-13 23:14:34.000000000 +0100
++++ kernel/drivers/net/smc91111.c 2006-11-27 02:22:29.000000000 +0100
+@@ -1400,7 +1400,7 @@ static int smc_open(struct net_device *d
+ lp->ctl_ephloop = 0;
+ lp->ctl_miiop = 0;
+ lp->ctl_autoneg = 1; //1
+- lp->ctl_rfduplx = 0; //Haup=> negotiate for HALF?
++ lp->ctl_rfduplx = 1; //1
+ lp->ctl_rspeed = 100; //100
+ lp->ctl_afduplx = 0; //1
+ lp->ctl_aspeed = 100; //100
+@@ -3742,5 +3742,25 @@ static void smc_phy_interrupt(struct net
+ #endif
+ // Update the last phy 18 variable
+ lp->lastPhy18 = phy18;
++
++ // if Fullduplex and 100MBit detected we set swfdup
++ if (lp->lastPhy18 & PHY_INT_DPLXDET &&
++ lp->lastPhy18 & PHY_INT_SPDDET)
++ {
++ if (!(lp->tcr_cur_mode & TCR_SWFDUP))
++ {
++ PRINTK2 ("SMC91111 detect 100MBit Full Duplex.. enable swfdup\n");
++ lp->tcr_cur_mode |= TCR_SWFDUP;
++ lp->ctl_swfdup = 1;
++ smc_modify_regbit (0, ioaddr, TCR_REG, TCR_SWFDUP, 1);
++ }
++ }
++ else if (lp->tcr_cur_mode & TCR_SWFDUP)
++ {
++ PRINTK2 ("SMC91111 no 100MBit Full Duplex detected.. disable swfdup\n");
++ lp->tcr_cur_mode &= ~TCR_SWFDUP;
++ lp->ctl_swfdup = 0;
++ smc_modify_regbit (0, ioaddr, TCR_REG, TCR_SWFDUP, 0);
++ }
+ }
+ }
--- /dev/null
+diff -Narup linux-2.4.31-orig/arch/ppc/boot/utils/mktree.c linux-2.4.31/arch/ppc/boot/utils/mktree.c
+--- linux-2.4.31-orig/arch/ppc/boot/utils/mktree.c 2004-08-03 16:31:09.568992888 -0500
++++ linux-2.4.31/arch/ppc/boot/utils/mktree.c 2004-08-04 11:06:39.799051328 -0500
+@@ -15,19 +15,20 @@
+ #include <sys/stat.h>
+ #include <unistd.h>
+ #include <netinet/in.h>
++#include <stdint.h>
+
+ /* This gets tacked on the front of the image. There are also a few
+ * bytes allocated after the _start label used by the boot rom (see
+ * head.S for details).
+ */
+ typedef struct boot_block {
+- unsigned long bb_magic; /* 0x0052504F */
+- unsigned long bb_dest; /* Target address of the image */
+- unsigned long bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */
+- unsigned long bb_debug_flag; /* Run debugger or image after load */
+- unsigned long bb_entry_point; /* The image address to start */
+- unsigned long bb_checksum; /* 32 bit checksum including header */
+- unsigned long reserved[2];
++ uint32_t bb_magic; /* 0x0052504F */
++ uint32_t bb_dest; /* Target address of the image */
++ uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */
++ uint32_t bb_debug_flag; /* Run debugger or image after load */
++ uint32_t bb_entry_point; /* The image address to start */
++ uint32_t bb_checksum; /* 32 bit checksum including header */
++ uint32_t reserved[2];
+ } boot_block_t;
+
+ #define IMGBLK 512
--- /dev/null
+#!/bin/bash
+
+for j in $( ls patches-2.4.31/*.patch); do
+ patch -f -N -p1 -d $1/linux-2.4.31 < $j
+done
+
+for j in $( ls otherpatches/*.patch); do
+ patch -f -N -p1 -d $1/linux-2.4.31 < $j
+done
+
+cp -vf patches-2.4.31/redwood.c $1/linux-2.4.31/drivers/mtd/maps
+cp -vf otherpatches/dongle_version.h $1/linux-2.4.31/arch/ppc
--- /dev/null
+diff -Narup linux-2.4.31-orig/Makefile linux-2.4.31/Makefile
+--- linux-2.4.31-orig/Makefile 2005-08-09 11:30:57.000000000 -0700
++++ linux-2.4.31/Makefile 2005-08-09 11:33:15.000000000 -0700
+@@ -5,7 +5,7 @@ EXTRAVERSION =
+
+ 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/)
+ KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+
+ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+@@ -19,7 +19,10 @@ FINDHPATH = $(HPATH)/asm $(HPATH)/linux
+ HOSTCC = gcc
+ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+-CROSS_COMPILE =
++#CROSS_COMPILE =
++
++ARCH=ppc
++CROSS_COMPILE = powerpc-405-linux-gnu-
+
+ #
+ # Include the make variables (CC, etc...)
--- /dev/null
+diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/embed_config.c linux-2.4.31/arch/ppc/boot/simple/embed_config.c
+--- linux-2.4.31-orig/arch/ppc/boot/simple/embed_config.c 2004-04-14 06:05:27.000000000 -0700
++++ linux-2.4.31/arch/ppc/boot/simple/embed_config.c 2005-10-06 00:05:18.000000000 -0700
+@@ -711,6 +711,9 @@ embed_config(bd_t **bdp)
+ bd->bi_tbfreq = bd->bi_intfreq;
+ #endif
+ }
++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6)
++ bd->bi_tbfreq = 27 * 1000 * 1000;
++#endif
+ }
+ #endif
+
--- /dev/null
+diff -Narup linux-2.4.31-orig/arch/ppc/config.in linux-2.4.31/arch/ppc/config.in
+--- linux-2.4.31-orig/arch/ppc/config.in 2004-08-07 16:26:04.000000000 -0700
++++ linux-2.4.31/arch/ppc/config.in 2005-08-24 22:14:47.000000000 -0700
+@@ -167,6 +167,8 @@ if [ "$CONFIG_SMP" = "y" ]; then
+ int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+ fi
+
++bool 'kexec system call' CONFIG_KEXEC
++
+ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
+ bool 'AltiVec Support' CONFIG_ALTIVEC
+ bool 'Thermal Management Support' CONFIG_TAU
+diff -Narup linux-2.4.31-orig/arch/ppc/kernel/Makefile linux-2.4.31/arch/ppc/kernel/Makefile
+--- linux-2.4.31-orig/arch/ppc/kernel/Makefile 2004-04-14 06:05:27.000000000 -0700
++++ linux-2.4.31/arch/ppc/kernel/Makefile 2005-08-24 22:17:32.000000000 -0700
+@@ -49,6 +49,7 @@ obj-$(CONFIG_PCI) += pci-dma.o
+ obj-$(CONFIG_KGDB) += ppc-stub.o
+ obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o
+ obj-$(CONFIG_SMP) += smp.o
++obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+ obj-$(CONFIG_TAU) += temp.o
+ ifeq ($(CONFIG_SERIAL)$(CONFIG_GEN550),yy)
+ obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o
+diff -Narup linux-2.4.31-orig/arch/ppc/kernel/machine_kexec.c linux-2.4.31/arch/ppc/kernel/machine_kexec.c
+--- linux-2.4.31-orig/arch/ppc/kernel/machine_kexec.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/arch/ppc/kernel/machine_kexec.c 2005-08-24 23:43:17.000000000 -0700
+@@ -0,0 +1,121 @@
++/*
++ * machine_kexec.c - handle transition of Linux booting another kernel
++ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
++ *
++ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
++ *
++ * This source code is licensed under the GNU General Public License,
++ * Version 2. See the file COPYING for more details.
++ */
++
++#include <linux/mm.h>
++#include <linux/kexec.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/mmu_context.h>
++#include <asm/io.h>
++#include <asm/hw_irq.h>
++//#include <asm/cacheflush.h>
++#include <asm/machdep.h>
++
++typedef NORET_TYPE void (*relocate_new_kernel_t)(
++ unsigned long indirection_page, unsigned long reboot_code_buffer,
++ unsigned long start_address) ATTRIB_NORET;
++
++const extern unsigned char relocate_new_kernel[];
++const extern unsigned int relocate_new_kernel_size;
++
++void machine_shutdown(void)
++{
++ if (ppc_md.machine_shutdown) {
++ ppc_md.machine_shutdown();
++ }
++}
++
++void machine_crash_shutdown(void)
++{
++ if (ppc_md.machine_crash_shutdown) {
++ ppc_md.machine_crash_shutdown();
++ }
++}
++
++/*
++ * Do what every setup is needed on image and the
++ * reboot code buffer to allow us to avoid allocations
++ * later.
++ */
++int machine_kexec_prepare(struct kimage *image)
++{
++ if (ppc_md.machine_kexec_prepare) {
++ return ppc_md.machine_kexec_prepare(image);
++ }
++ /*
++ * Fail if platform doesn't provide its own machine_kexec_prepare
++ * implementation.
++ */
++ return -ENOSYS;
++}
++
++void machine_kexec_cleanup(struct kimage *image)
++{
++ if (ppc_md.machine_kexec_cleanup) {
++ ppc_md.machine_kexec_cleanup(image);
++ }
++}
++
++/*
++ * Do not allocate memory (or fail in any way) in machine_kexec().
++ * We are past the point of no return, committed to rebooting now.
++ */
++NORET_TYPE void machine_kexec(struct kimage *image)
++{
++ if (ppc_md.machine_kexec) {
++ ppc_md.machine_kexec(image);
++ } else {
++ /*
++ * Fall back to normal restart if platform doesn't provide
++ * its own kexec function, and user insist to kexec...
++ */
++ machine_restart(NULL);
++ }
++ for(;;);
++}
++
++
++/*
++ * This is a generic machine_kexec function suitable at least for
++ * non-OpenFirmware embedded platforms.
++ * It merely copies the image relocation code to the control page and
++ * jumps to it.
++ * A platform specific function may just call this one.
++ */
++void machine_kexec_simple(struct kimage *image)
++{
++ unsigned long page_list;
++ unsigned long reboot_code_buffer, reboot_code_buffer_phys;
++ relocate_new_kernel_t rnk;
++
++ /* Interrupts aren't acceptable while we reboot */
++ local_irq_disable();
++
++ page_list = image->head;
++
++ /* we need both effective and real address here */
++ reboot_code_buffer =
++ (unsigned long)page_address(image->control_code_page);
++ reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
++
++ /* copy our kernel relocation code to the control code page */
++ memcpy((void *)reboot_code_buffer,
++ relocate_new_kernel, relocate_new_kernel_size);
++
++ flush_icache_range(reboot_code_buffer,
++ reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
++ printk(KERN_INFO "Bye!\n");
++
++ /* now call it */
++ rnk = (relocate_new_kernel_t) reboot_code_buffer;
++ (*rnk)(page_list, reboot_code_buffer_phys, image->start);
++}
+diff -Narup linux-2.4.31-orig/arch/ppc/kernel/misc.S linux-2.4.31/arch/ppc/kernel/misc.S
+--- linux-2.4.31-orig/arch/ppc/kernel/misc.S 2004-04-14 06:05:27.000000000 -0700
++++ linux-2.4.31/arch/ppc/kernel/misc.S 2005-08-24 22:22:21.000000000 -0700
+@@ -1310,6 +1310,25 @@ _GLOBAL(sys_call_table)
+ .long sys_ni_syscall /* reserved for sys_clock_getres */
+ .long sys_ni_syscall /* reserved for sys_clock_nanosleep */
+ .long sys_swapcontext
++ .long sys_ni_syscall /* 250 */
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall /* 255 */
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall /* 260 */
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_ni_syscall /* 265 */
++ .long sys_ni_syscall
++ .long sys_ni_syscall
++ .long sys_kexec_load /* and finally, 268 sys_kexec_load... */
+
+ .rept NR_syscalls-(.-sys_call_table)/4
+ .long sys_ni_syscall
+diff -Narup linux-2.4.31-orig/arch/ppc/kernel/relocate_kernel.S linux-2.4.31/arch/ppc/kernel/relocate_kernel.S
+--- linux-2.4.31-orig/arch/ppc/kernel/relocate_kernel.S 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/arch/ppc/kernel/relocate_kernel.S 2005-08-24 11:37:15.000000000 -0700
+@@ -0,0 +1,122 @@
++/*
++ * relocate_kernel.S - put the kernel image in place to boot
++ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
++ *
++ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
++ *
++ * This source code is licensed under the GNU General Public License,
++ * Version 2. See the file COPYING for more details.
++ */
++
++#include <asm/ppc_asm.h>
++#include <asm/processor.h>
++
++#include <asm/kexec.h>
++
++#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
++
++ /*
++ * Must be relocatable PIC code callable as a C function.
++ */
++ .globl relocate_new_kernel
++relocate_new_kernel:
++ /* r3 = page_list */
++ /* r4 = reboot_code_buffer */
++ /* r5 = start_address */
++
++ li r0, 0
++
++ /*
++ * Set Machine Status Register to a known status,
++ * switch the MMU off and jump to 1: in a single step.
++ */
++
++ mr r8, r0
++ ori r8, r8, MSR_RI|MSR_ME
++ mtspr SPRN_SRR1, r8
++ addi r8, r4, 1f - relocate_new_kernel
++ mtspr SPRN_SRR0, r8
++ sync
++ rfi
++
++1:
++ /* from this point address translation is turned off */
++ /* and interrupts are disabled */
++
++ /* set a new stack at the bottom of our page... */
++ /* (not really needed now) */
++ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
++ stw r0, 0(r1)
++
++ /* Do the copies */
++ li r6, 0 /* checksum */
++ mr r0, r3
++ b 1f
++
++0: /* top, read another word for the indirection page */
++ lwzu r0, 4(r3)
++
++1:
++ /* is it a destination page? (r8) */
++ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
++ beq 2f
++
++ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
++ b 0b
++
++2: /* is it an indirection page? (r3) */
++ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
++ beq 2f
++
++ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
++ subi r3, r3, 4
++ b 0b
++
++2: /* are we done? */
++ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
++ beq 2f
++ b 3f
++
++2: /* is it a source page? (r9) */
++ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
++ beq 0b
++
++ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
++
++ li r7, PAGE_SIZE / 4
++ mtctr r7
++ subi r9, r9, 4
++ subi r8, r8, 4
++9:
++ lwzu r0, 4(r9) /* do the copy */
++ xor r6, r6, r0
++ stwu r0, 4(r8)
++ dcbst 0, r8
++ sync
++ icbi 0, r8
++ bdnz 9b
++
++ addi r9, r9, 4
++ addi r8, r8, 4
++ b 0b
++
++3:
++
++ /* To be certain of avoiding problems with self-modifying code
++ * execute a serializing instruction here.
++ */
++ isync
++ sync
++
++ /* jump to the entry point, usually the setup routine */
++ mtlr r5
++ blrl
++
++1: b 1b
++
++relocate_new_kernel_end:
++
++ .globl relocate_new_kernel_size
++relocate_new_kernel_size:
++ .long relocate_new_kernel_end - relocate_new_kernel
++
+diff -Narup linux-2.4.31-orig/arch/ppc/platforms/redwood6.c linux-2.4.31/arch/ppc/platforms/redwood6.c
+--- linux-2.4.31-orig/arch/ppc/platforms/redwood6.c 2004-04-14 06:05:27.000000000 -0700
++++ linux-2.4.31/arch/ppc/platforms/redwood6.c 2005-08-24 22:57:12.000000000 -0700
+@@ -168,7 +168,26 @@ board_setup_irq(void)
+ {
+ }
+
++#ifdef CONFIG_KEXEC
++int redwood6_kexec_prepare(struct kimage *image)
++{
++ /* here, we can place additional preparations */
++ return 0; /* yes, we support kexec */
++}
++
++
++void redwood6_kexec(struct kimage *image)
++{
++ /* just call the simple kexec version... */
++ machine_kexec_simple(image);
++}
++#endif /* CONFIG_KEXEC */
++
+ void __init
+ board_init(void)
+ {
++#ifdef CONFIG_KEXEC
++ ppc_md.machine_kexec_prepare = redwood6_kexec_prepare;
++ ppc_md.machine_kexec = redwood6_kexec;
++#endif
+ }
+diff -Narup linux-2.4.31-orig/include/asm-ppc/io.h linux-2.4.31/include/asm-ppc/io.h
+--- linux-2.4.31-orig/include/asm-ppc/io.h 2003-11-28 10:26:21.000000000 -0800
++++ linux-2.4.31/include/asm-ppc/io.h 2005-08-24 23:28:30.000000000 -0700
+@@ -275,6 +275,10 @@ extern inline void * phys_to_virt(unsign
+ #define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART)
+ #define page_to_bus(page) (page_to_phys(page) + PCI_DRAM_OFFSET)
+
++/* added for kexec support */
++#define pfn_to_page(pfn) (mem_map + ((pfn) - PPC_PGSTART))
++#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PPC_PGSTART)
++
+ /*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+diff -Narup linux-2.4.31-orig/include/asm-ppc/kexec.h linux-2.4.31/include/asm-ppc/kexec.h
+--- linux-2.4.31-orig/include/asm-ppc/kexec.h 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/include/asm-ppc/kexec.h 2005-08-24 22:58:28.000000000 -0700
+@@ -0,0 +1,38 @@
++#ifndef _PPC_KEXEC_H
++#define _PPC_KEXEC_H
++
++#ifdef CONFIG_KEXEC
++
++/*
++ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
++ * I.e. Maximum page that is mapped directly into kernel memory,
++ * and kmap is not required.
++ *
++ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
++ * calculation for the amount of memory directly mappable into the
++ * kernel memory space.
++ */
++
++/* Maximum physical address we can use pages from */
++#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
++/* Maximum address we can reach in physical address mode */
++#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
++/* Maximum address we can use for the control code buffer */
++#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
++
++#define KEXEC_CONTROL_CODE_SIZE 4096
++
++/* The native architecture */
++#define KEXEC_ARCH KEXEC_ARCH_PPC
++
++#ifndef __ASSEMBLY__
++
++struct kimage;
++
++extern void machine_kexec_simple(struct kimage *image);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* CONFIG_KEXEC */
++
++#endif /* _PPC_KEXEC_H */
+diff -Narup linux-2.4.31-orig/include/asm-ppc/machdep.h linux-2.4.31/include/asm-ppc/machdep.h
+--- linux-2.4.31-orig/include/asm-ppc/machdep.h 2005-08-24 22:05:10.000000000 -0700
++++ linux-2.4.31/include/asm-ppc/machdep.h 2005-08-24 23:41:01.000000000 -0700
+@@ -3,6 +3,7 @@
+ #define _PPC_MACHDEP_H
+
+ #include <linux/config.h>
++#include <linux/kexec.h>
+
+ #ifdef CONFIG_APUS
+ #include <asm-m68k/machdep.h>
+@@ -113,6 +114,36 @@ struct machdep_calls {
+ /* functions for dealing with other cpus */
+ struct smp_ops_t *smp_ops;
+ #endif /* CONFIG_SMP */
++
++#ifdef CONFIG_KEXEC
++ /* Called to shutdown machine specific hardware not already controlled
++ * by other drivers.
++ * XXX Should we move this one out of kexec scope?
++ */
++ void (*machine_shutdown)(void);
++
++ /* Called to do the minimal shutdown needed to run a kexec'd kernel
++ * to run successfully.
++ * XXX Should we move this one out of kexec scope?
++ */
++ void (*machine_crash_shutdown)(void);
++
++ /* Called to do what every setup is needed on image and the
++ * reboot code buffer. Returns 0 on success.
++ * Provide your own (maybe dummy) implementation if your platform
++ * claims to support kexec.
++ */
++ int (*machine_kexec_prepare)(struct kimage *image);
++
++ /* Called to handle any machine specific cleanup on image */
++ void (*machine_kexec_cleanup)(struct kimage *image);
++
++ /* Called to perform the _real_ kexec.
++ * Do NOT allocate memory or fail here. We are past the point of
++ * no return.
++ */
++ void (*machine_kexec)(struct kimage *image);
++#endif /* CONFIG_KEXEC */
+ };
+
+ extern struct machdep_calls ppc_md;
+diff -Narup linux-2.4.31-orig/include/asm-ppc/page.h linux-2.4.31/include/asm-ppc/page.h
+--- linux-2.4.31-orig/include/asm-ppc/page.h 2003-11-28 10:26:21.000000000 -0800
++++ linux-2.4.31/include/asm-ppc/page.h 2005-08-24 23:27:19.000000000 -0700
+@@ -104,6 +104,7 @@ extern unsigned long ppc_memstart;
+ extern unsigned long ppc_memoffset;
+ #ifndef CONFIG_APUS
+ #define PPC_MEMSTART 0
++#define PPC_PGSTART 0
+ #define PPC_MEMOFFSET PAGE_OFFSET
+ #else
+ #define PPC_MEMSTART ppc_memstart
+diff -Narup linux-2.4.31-orig/include/asm-ppc/unistd.h linux-2.4.31/include/asm-ppc/unistd.h
+--- linux-2.4.31-orig/include/asm-ppc/unistd.h 2004-11-17 03:54:22.000000000 -0800
++++ linux-2.4.31/include/asm-ppc/unistd.h 2005-08-24 22:49:47.000000000 -0700
+@@ -257,6 +257,8 @@
+ #endif
+ #define __NR_swapcontext 249
+
++#define __NR_kexec_load 268
++
+ #define __NR(n) #n
+
+ /* On powerpc a system call basically clobbers the same registers like a
+diff -Narup linux-2.4.31-orig/include/linux/kexec.h linux-2.4.31/include/linux/kexec.h
+--- linux-2.4.31-orig/include/linux/kexec.h 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/include/linux/kexec.h 2005-08-24 23:40:30.000000000 -0700
+@@ -0,0 +1,115 @@
++#ifndef LINUX_KEXEC_H
++#define LINUX_KEXEC_H
++
++#ifdef CONFIG_KEXEC
++#include <linux/compiler.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/linkage.h>
++#include <asm/kexec.h>
++
++/* Verify architecture specific macros are defined */
++
++#ifndef KEXEC_SOURCE_MEMORY_LIMIT
++#error KEXEC_SOURCE_MEMORY_LIMIT not defined
++#endif
++
++#ifndef KEXEC_DESTINATION_MEMORY_LIMIT
++#error KEXEC_DESTINATION_MEMORY_LIMIT not defined
++#endif
++
++#ifndef KEXEC_CONTROL_MEMORY_LIMIT
++#error KEXEC_CONTROL_MEMORY_LIMIT not defined
++#endif
++
++#ifndef KEXEC_CONTROL_CODE_SIZE
++#error KEXEC_CONTROL_CODE_SIZE not defined
++#endif
++
++#ifndef KEXEC_ARCH
++#error KEXEC_ARCH not defined
++#endif
++
++/*
++ * This structure is used to hold the arguments that are used when loading
++ * kernel binaries.
++ */
++
++typedef unsigned long kimage_entry_t;
++#define IND_DESTINATION 0x1
++#define IND_INDIRECTION 0x2
++#define IND_DONE 0x4
++#define IND_SOURCE 0x8
++
++#define KEXEC_SEGMENT_MAX 8
++struct kexec_segment {
++ void __user *buf;
++ size_t bufsz;
++ unsigned long mem; /* User space sees this as a (void *) ... */
++ size_t memsz;
++};
++
++struct kimage {
++ kimage_entry_t head;
++ kimage_entry_t *entry;
++ kimage_entry_t *last_entry;
++
++ unsigned long destination;
++
++ unsigned long start;
++ struct page *control_code_page;
++
++ unsigned long nr_segments;
++ struct kexec_segment segment[KEXEC_SEGMENT_MAX];
++
++ struct list_head control_pages;
++ struct list_head dest_pages;
++ struct list_head unuseable_pages;
++
++ /* Address of next control page to allocate for crash kernels. */
++ unsigned long control_page;
++
++ /* Flags to indicate special processing */
++ unsigned int type : 1;
++#define KEXEC_TYPE_DEFAULT 0
++#define KEXEC_TYPE_CRASH 1
++};
++
++
++
++/* kexec interface functions */
++extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET;
++extern int machine_kexec_prepare(struct kimage *image);
++extern void machine_kexec_cleanup(struct kimage *image);
++extern asmlinkage long sys_kexec_load(unsigned long entry,
++ unsigned long nr_segments, struct kexec_segment __user *segments,
++ unsigned long flags);
++extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order);
++extern void crash_kexec(void);
++extern struct kimage *kexec_image;
++extern struct kimage *kexec_crash_image;
++
++#define KEXEC_ON_CRASH 0x00000001
++#define KEXEC_ARCH_MASK 0xffff0000
++
++/* These values match the ELF architecture values.
++ * Unless there is a good reason that should continue to be the case.
++ */
++#define KEXEC_ARCH_DEFAULT ( 0 << 16)
++#define KEXEC_ARCH_386 ( 3 << 16)
++#define KEXEC_ARCH_X86_64 (62 << 16)
++#define KEXEC_ARCH_PPC (20 << 16)
++#define KEXEC_ARCH_PPC64 (21 << 16)
++#define KEXEC_ARCH_IA_64 (50 << 16)
++
++#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */
++
++/* Location of a reserved region to hold the crash kernel.
++ */
++extern struct resource crashk_res;
++
++#else /* !CONFIG_KEXEC */
++static inline void crash_kexec(void) { }
++#endif /* CONFIG_KEXEC */
++#endif /* LINUX_KEXEC_H */
+diff -Narup linux-2.4.31-orig/include/linux/mm.h linux-2.4.31/include/linux/mm.h
+--- linux-2.4.31-orig/include/linux/mm.h 2005-01-19 06:10:12.000000000 -0800
++++ linux-2.4.31/include/linux/mm.h 2005-08-24 23:27:57.000000000 -0700
+@@ -165,6 +165,8 @@ typedef struct page {
+ struct page **pprev_hash; /* Complement to *next_hash. */
+ struct buffer_head * buffers; /* Buffer maps us to a disk block. */
+
++ unsigned long private; /* added for kexec */
++
+ /*
+ * On machines where all RAM is mapped into kernel address space,
+ * we can simply calculate the virtual address. On machines with
+diff -Narup linux-2.4.31-orig/include/linux/reboot.h linux-2.4.31/include/linux/reboot.h
+--- linux-2.4.31-orig/include/linux/reboot.h 2001-02-09 14:46:13.000000000 -0800
++++ linux-2.4.31/include/linux/reboot.h 2005-08-24 23:00:54.000000000 -0700
+@@ -20,6 +20,7 @@
+ * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
+ * POWER_OFF Stop OS and remove all power from system, if possible.
+ * RESTART2 Restart system using given command string.
++ * KEXEC Restart system using a previously loaded Linux kernel
+ */
+
+ #define LINUX_REBOOT_CMD_RESTART 0x01234567
+@@ -28,6 +29,7 @@
+ #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
+ #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
+ #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
++#define LINUX_REBOOT_CMD_KEXEC 0x45584543
+
+
+ #ifdef __KERNEL__
+@@ -45,6 +47,8 @@ extern int unregister_reboot_notifier(st
+ extern void machine_restart(char *cmd);
+ extern void machine_halt(void);
+ extern void machine_power_off(void);
++extern void machine_shutdown(void);
++extern void machine_crash_shutdown(void);
+
+ #endif
+
+diff -Narup linux-2.4.31-orig/kernel/Makefile linux-2.4.31/kernel/Makefile
+--- linux-2.4.31-orig/kernel/Makefile 2001-09-16 21:22:40.000000000 -0700
++++ linux-2.4.31/kernel/Makefile 2005-08-24 22:38:41.000000000 -0700
+@@ -19,6 +19,7 @@ obj-y = sched.o dma.o fork.o exec_do
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += ksyms.o
+ obj-$(CONFIG_PM) += pm.o
++obj-$(CONFIG_KEXEC) += kexec.o
+
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff -Narup linux-2.4.31-orig/kernel/kexec.c linux-2.4.31/kernel/kexec.c
+--- linux-2.4.31-orig/kernel/kexec.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/kernel/kexec.c 2005-08-24 23:30:47.000000000 -0700
+@@ -0,0 +1,993 @@
++/*
++ * kexec.c - kexec system call
++ * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com>
++ *
++ * This source code is licensed under the GNU General Public License,
++ * Version 2. See the file COPYING for more details.
++ */
++
++#include <linux/mm.h>
++#include <linux/file.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/kexec.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include <linux/highmem.h>
++#include <linux/reboot.h>
++//#include <linux/syscalls.h>
++#include <linux/ioport.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/system.h>
++#include <asm/semaphore.h>
++
++/* Location of the reserved area for the crash kernel */
++struct resource crashk_res = {
++ .name = "Crash kernel",
++ .start = 0,
++ .end = 0,
++ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
++};
++
++/*
++ * When kexec transitions to the new kernel there is a one-to-one
++ * mapping between physical and virtual addresses. On processors
++ * where you can disable the MMU this is trivial, and easy. For
++ * others it is still a simple predictable page table to setup.
++ *
++ * In that environment kexec copies the new kernel to its final
++ * resting place. This means I can only support memory whose
++ * physical address can fit in an unsigned long. In particular
++ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
++ * If the assembly stub has more restrictive requirements
++ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
++ * defined more restrictively in <asm/kexec.h>.
++ *
++ * The code for the transition from the current kernel to the
++ * the new kernel is placed in the control_code_buffer, whose size
++ * is given by KEXEC_CONTROL_CODE_SIZE. In the best case only a single
++ * page of memory is necessary, but some architectures require more.
++ * Because this memory must be identity mapped in the transition from
++ * virtual to physical addresses it must live in the range
++ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
++ * modifiable.
++ *
++ * The assembly stub in the control code buffer is passed a linked list
++ * of descriptor pages detailing the source pages of the new kernel,
++ * and the destination addresses of those source pages. As this data
++ * structure is not used in the context of the current OS, it must
++ * be self-contained.
++ *
++ * The code has been made to work with highmem pages and will use a
++ * destination page in its final resting place (if it happens
++ * to allocate it). The end product of this is that most of the
++ * physical address space, and most of RAM can be used.
++ *
++ * Future directions include:
++ * - allocating a page table with the control code buffer identity
++ * mapped, to simplify machine_kexec and make kexec_on_panic more
++ * reliable.
++ */
++
++/*
++ * KIMAGE_NO_DEST is an impossible destination address..., for
++ * allocating pages whose destination address we do not care about.
++ */
++#define KIMAGE_NO_DEST (-1UL)
++
++static int kimage_is_destination_range(
++ struct kimage *image, unsigned long start, unsigned long end);
++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest);
++
++static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,
++ unsigned long nr_segments, struct kexec_segment __user *segments)
++{
++ size_t segment_bytes;
++ struct kimage *image;
++ unsigned long i;
++ int result;
++
++ /* Allocate a controlling structure */
++ result = -ENOMEM;
++ image = kmalloc(sizeof(*image), GFP_KERNEL);
++ if (!image) {
++ goto out;
++ }
++ memset(image, 0, sizeof(*image));
++ image->head = 0;
++ image->entry = &image->head;
++ image->last_entry = &image->head;
++ image->control_page = ~0; /* By default this does not apply */
++ image->start = entry;
++ image->type = KEXEC_TYPE_DEFAULT;
++
++ /* Initialize the list of control pages */
++ INIT_LIST_HEAD(&image->control_pages);
++
++ /* Initialize the list of destination pages */
++ INIT_LIST_HEAD(&image->dest_pages);
++
++ /* Initialize the list of unuseable pages */
++ INIT_LIST_HEAD(&image->unuseable_pages);
++
++ /* Read in the segments */
++ image->nr_segments = nr_segments;
++ segment_bytes = nr_segments * sizeof(*segments);
++ result = copy_from_user(image->segment, segments, segment_bytes);
++ if (result)
++ goto out;
++
++ /*
++ * Verify we have good destination addresses. The caller is
++ * responsible for making certain we don't attempt to load
++ * the new image into invalid or reserved areas of RAM. This
++ * just verifies it is an address we can use.
++ *
++ * Since the kernel does everything in page size chunks ensure
++ * the destination addreses are page aligned. Too many
++ * special cases crop of when we don't do this. The most
++ * insidious is getting overlapping destination addresses
++ * simply because addresses are changed to page size
++ * granularity.
++ */
++ result = -EADDRNOTAVAIL;
++ for (i = 0; i < nr_segments; i++) {
++ unsigned long mstart, mend;
++ mstart = image->segment[i].mem;
++ mend = mstart + image->segment[i].memsz;
++ if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK))
++ goto out;
++ if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
++ goto out;
++ }
++
++ /* Verify our destination addresses do not overlap.
++ * If we alloed overlapping destination addresses
++ * through very weird things can happen with no
++ * easy explanation as one segment stops on another.
++ */
++ result = -EINVAL;
++ for(i = 0; i < nr_segments; i++) {
++ unsigned long mstart, mend;
++ unsigned long j;
++ mstart = image->segment[i].mem;
++ mend = mstart + image->segment[i].memsz;
++ for(j = 0; j < i; j++) {
++ unsigned long pstart, pend;
++ pstart = image->segment[j].mem;
++ pend = pstart + image->segment[j].memsz;
++ /* Do the segments overlap ? */
++ if ((mend > pstart) && (mstart < pend))
++ goto out;
++ }
++ }
++
++ /* Ensure our buffer sizes are strictly less than
++ * our memory sizes. This should always be the case,
++ * and it is easier to check up front than to be surprised
++ * later on.
++ */
++ result = -EINVAL;
++ for(i = 0; i < nr_segments; i++) {
++ if (image->segment[i].bufsz > image->segment[i].memsz)
++ goto out;
++ }
++
++
++ result = 0;
++ out:
++ if (result == 0) {
++ *rimage = image;
++ } else {
++ kfree(image);
++ }
++ return result;
++
++}
++
++static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry,
++ unsigned long nr_segments, struct kexec_segment __user *segments)
++{
++ int result;
++ struct kimage *image;
++
++ /* Allocate and initialize a controlling structure */
++ image = NULL;
++ result = do_kimage_alloc(&image, entry, nr_segments, segments);
++ if (result) {
++ goto out;
++ }
++ *rimage = image;
++
++ /*
++ * Find a location for the control code buffer, and add it
++ * the vector of segments so that it's pages will also be
++ * counted as destination pages.
++ */
++ result = -ENOMEM;
++ image->control_code_page = kimage_alloc_control_pages(image,
++ get_order(KEXEC_CONTROL_CODE_SIZE));
++ if (!image->control_code_page) {
++ printk(KERN_ERR "Could not allocate control_code_buffer\n");
++ goto out;
++ }
++
++ result = 0;
++ out:
++ if (result == 0) {
++ *rimage = image;
++ } else {
++ kfree(image);
++ }
++ return result;
++}
++
++static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry,
++ unsigned long nr_segments, struct kexec_segment *segments)
++{
++ int result;
++ struct kimage *image;
++ unsigned long i;
++
++ image = NULL;
++ /* Verify we have a valid entry point */
++ if ((entry < crashk_res.start) || (entry > crashk_res.end)) {
++ result = -EADDRNOTAVAIL;
++ goto out;
++ }
++
++ /* Allocate and initialize a controlling structure */
++ result = do_kimage_alloc(&image, entry, nr_segments, segments);
++ if (result) {
++ goto out;
++ }
++
++ /* Enable the special crash kernel control page
++ * allocation policy.
++ */
++ image->control_page = crashk_res.start;
++ image->type = KEXEC_TYPE_CRASH;
++
++ /*
++ * Verify we have good destination addresses. Normally
++ * the caller is responsible for making certain we don't
++ * attempt to load the new image into invalid or reserved
++ * areas of RAM. But crash kernels are preloaded into a
++ * reserved area of ram. We must ensure the addresses
++ * are in the reserved area otherwise preloading the
++ * kernel could corrupt things.
++ */
++ result = -EADDRNOTAVAIL;
++ for (i = 0; i < nr_segments; i++) {
++ unsigned long mstart, mend;
++ mstart = image->segment[i].mem;
++ mend = mstart + image->segment[i].memsz;
++ /* Ensure we are within the crash kernel limits */
++ if ((mstart < crashk_res.start) || (mend > crashk_res.end))
++ goto out;
++ }
++
++
++ /*
++ * Find a location for the control code buffer, and add
++ * the vector of segments so that it's pages will also be
++ * counted as destination pages.
++ */
++ result = -ENOMEM;
++ image->control_code_page = kimage_alloc_control_pages(image,
++ get_order(KEXEC_CONTROL_CODE_SIZE));
++ if (!image->control_code_page) {
++ printk(KERN_ERR "Could not allocate control_code_buffer\n");
++ goto out;
++ }
++
++ result = 0;
++ out:
++ if (result == 0) {
++ *rimage = image;
++ } else {
++ kfree(image);
++ }
++ return result;
++}
++
++static int kimage_is_destination_range(
++ struct kimage *image, unsigned long start, unsigned long end)
++{
++ unsigned long i;
++
++ for (i = 0; i < image->nr_segments; i++) {
++ unsigned long mstart, mend;
++ mstart = image->segment[i].mem;
++ mend = mstart + image->segment[i].memsz;
++ if ((end > mstart) && (start < mend)) {
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static struct page *kimage_alloc_pages(unsigned int gfp_mask, unsigned int order)
++{
++ struct page *pages;
++ pages = alloc_pages(gfp_mask, order);
++ if (pages) {
++ unsigned int count, i;
++ pages->mapping = NULL;
++ pages->private = order;
++ count = 1 << order;
++ for(i = 0; i < count; i++) {
++ SetPageReserved(pages + i);
++ }
++ }
++ return pages;
++}
++
++static void kimage_free_pages(struct page *page)
++{
++ unsigned int order, count, i;
++ order = page->private;
++ count = 1 << order;
++ for(i = 0; i < count; i++) {
++ ClearPageReserved(page + i);
++ }
++ __free_pages(page, order);
++}
++
++static void kimage_free_page_list(struct list_head *list)
++{
++ struct list_head *pos, *next;
++ list_for_each_safe(pos, next, list) {
++ struct page *page;
++
++ page = list_entry(pos, struct page, lru);
++ list_del(&page->lru);
++
++ kimage_free_pages(page);
++ }
++}
++
++static struct page *kimage_alloc_normal_control_pages(
++ struct kimage *image, unsigned int order)
++{
++ /* Control pages are special, they are the intermediaries
++ * that are needed while we copy the rest of the pages
++ * to their final resting place. As such they must
++ * not conflict with either the destination addresses
++ * or memory the kernel is already using.
++ *
++ * The only case where we really need more than one of
++ * these are for architectures where we cannot disable
++ * the MMU and must instead generate an identity mapped
++ * page table for all of the memory.
++ *
++ * At worst this runs in O(N) of the image size.
++ */
++ struct list_head extra_pages;
++ struct page *pages;
++ unsigned int count;
++
++ count = 1 << order;
++ INIT_LIST_HEAD(&extra_pages);
++
++ /* Loop while I can allocate a page and the page allocated
++ * is a destination page.
++ */
++ do {
++ unsigned long pfn, epfn, addr, eaddr;
++ pages = kimage_alloc_pages(GFP_KERNEL, order);
++ if (!pages)
++ break;
++ pfn = page_to_pfn(pages);
++ epfn = pfn + count;
++ addr = pfn << PAGE_SHIFT;
++ eaddr = epfn << PAGE_SHIFT;
++ if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) ||
++ kimage_is_destination_range(image, addr, eaddr))
++ {
++ list_add(&pages->lru, &extra_pages);
++ pages = NULL;
++ }
++ } while(!pages);
++ if (pages) {
++ /* Remember the allocated page... */
++ list_add(&pages->lru, &image->control_pages);
++
++ /* Because the page is already in it's destination
++ * location we will never allocate another page at
++ * that address. Therefore kimage_alloc_pages
++ * will not return it (again) and we don't need
++ * to give it an entry in image->segment[].
++ */
++ }
++ /* Deal with the destination pages I have inadvertently allocated.
++ *
++ * Ideally I would convert multi-page allocations into single
++ * page allocations, and add everyting to image->dest_pages.
++ *
++ * For now it is simpler to just free the pages.
++ */
++ kimage_free_page_list(&extra_pages);
++ return pages;
++
++}
++
++static struct page *kimage_alloc_crash_control_pages(
++ struct kimage *image, unsigned int order)
++{
++ /* Control pages are special, they are the intermediaries
++ * that are needed while we copy the rest of the pages
++ * to their final resting place. As such they must
++ * not conflict with either the destination addresses
++ * or memory the kernel is already using.
++ *
++ * Control pages are also the only pags we must allocate
++ * when loading a crash kernel. All of the other pages
++ * are specified by the segments and we just memcpy
++ * into them directly.
++ *
++ * The only case where we really need more than one of
++ * these are for architectures where we cannot disable
++ * the MMU and must instead generate an identity mapped
++ * page table for all of the memory.
++ *
++ * Given the low demand this implements a very simple
++ * allocator that finds the first hole of the appropriate
++ * size in the reserved memory region, and allocates all
++ * of the memory up to and including the hole.
++ */
++ unsigned long hole_start, hole_end, size;
++ struct page *pages;
++ pages = NULL;
++ size = (1 << order) << PAGE_SHIFT;
++ hole_start = (image->control_page + (size - 1)) & ~(size - 1);
++ hole_end = hole_start + size - 1;
++ while(hole_end <= crashk_res.end) {
++ unsigned long i;
++ if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT) {
++ break;
++ }
++ if (hole_end > crashk_res.end) {
++ break;
++ }
++ /* See if I overlap any of the segments */
++ for(i = 0; i < image->nr_segments; i++) {
++ unsigned long mstart, mend;
++ mstart = image->segment[i].mem;
++ mend = mstart + image->segment[i].memsz - 1;
++ if ((hole_end >= mstart) && (hole_start <= mend)) {
++ /* Advance the hole to the end of the segment */
++ hole_start = (mend + (size - 1)) & ~(size - 1);
++ hole_end = hole_start + size - 1;
++ break;
++ }
++ }
++ /* If I don't overlap any segments I have found my hole! */
++ if (i == image->nr_segments) {
++ pages = pfn_to_page(hole_start >> PAGE_SHIFT);
++ break;
++ }
++ }
++ if (pages) {
++ image->control_page = hole_end;
++ }
++ return pages;
++}
++
++
++struct page *kimage_alloc_control_pages(
++ struct kimage *image, unsigned int order)
++{
++ struct page *pages = NULL;
++ switch(image->type) {
++ case KEXEC_TYPE_DEFAULT:
++ pages = kimage_alloc_normal_control_pages(image, order);
++ break;
++ case KEXEC_TYPE_CRASH:
++ pages = kimage_alloc_crash_control_pages(image, order);
++ break;
++ }
++ return pages;
++}
++
++static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
++{
++ if (*image->entry != 0) {
++ image->entry++;
++ }
++ if (image->entry == image->last_entry) {
++ kimage_entry_t *ind_page;
++ struct page *page;
++ page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
++ if (!page) {
++ return -ENOMEM;
++ }
++ ind_page = page_address(page);
++ *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
++ image->entry = ind_page;
++ image->last_entry =
++ ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
++ }
++ *image->entry = entry;
++ image->entry++;
++ *image->entry = 0;
++ return 0;
++}
++
++static int kimage_set_destination(
++ struct kimage *image, unsigned long destination)
++{
++ int result;
++
++ destination &= PAGE_MASK;
++ result = kimage_add_entry(image, destination | IND_DESTINATION);
++ if (result == 0) {
++ image->destination = destination;
++ }
++ return result;
++}
++
++
++static int kimage_add_page(struct kimage *image, unsigned long page)
++{
++ int result;
++
++ page &= PAGE_MASK;
++ result = kimage_add_entry(image, page | IND_SOURCE);
++ if (result == 0) {
++ image->destination += PAGE_SIZE;
++ }
++ return result;
++}
++
++
++static void kimage_free_extra_pages(struct kimage *image)
++{
++ /* Walk through and free any extra destination pages I may have */
++ kimage_free_page_list(&image->dest_pages);
++
++ /* Walk through and free any unuseable pages I have cached */
++ kimage_free_page_list(&image->unuseable_pages);
++
++}
++static int kimage_terminate(struct kimage *image)
++{
++ if (*image->entry != 0) {
++ image->entry++;
++ }
++ *image->entry = IND_DONE;
++ return 0;
++}
++
++#define for_each_kimage_entry(image, ptr, entry) \
++ for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
++ ptr = (entry & IND_INDIRECTION)? \
++ phys_to_virt((entry & PAGE_MASK)): ptr +1)
++
++static void kimage_free_entry(kimage_entry_t entry)
++{
++ struct page *page;
++
++ page = pfn_to_page(entry >> PAGE_SHIFT);
++ kimage_free_pages(page);
++}
++
++static void kimage_free(struct kimage *image)
++{
++ kimage_entry_t *ptr, entry;
++ kimage_entry_t ind = 0;
++
++ if (!image)
++ return;
++ kimage_free_extra_pages(image);
++ for_each_kimage_entry(image, ptr, entry) {
++ if (entry & IND_INDIRECTION) {
++ /* Free the previous indirection page */
++ if (ind & IND_INDIRECTION) {
++ kimage_free_entry(ind);
++ }
++ /* Save this indirection page until we are
++ * done with it.
++ */
++ ind = entry;
++ }
++ else if (entry & IND_SOURCE) {
++ kimage_free_entry(entry);
++ }
++ }
++ /* Free the final indirection page */
++ if (ind & IND_INDIRECTION) {
++ kimage_free_entry(ind);
++ }
++
++ /* Handle any machine specific cleanup */
++ machine_kexec_cleanup(image);
++
++ /* Free the kexec control pages... */
++ kimage_free_page_list(&image->control_pages);
++ kfree(image);
++}
++
++static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page)
++{
++ kimage_entry_t *ptr, entry;
++ unsigned long destination = 0;
++
++ for_each_kimage_entry(image, ptr, entry) {
++ if (entry & IND_DESTINATION) {
++ destination = entry & PAGE_MASK;
++ }
++ else if (entry & IND_SOURCE) {
++ if (page == destination) {
++ return ptr;
++ }
++ destination += PAGE_SIZE;
++ }
++ }
++ return 0;
++}
++
++static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination)
++{
++ /*
++ * Here we implement safeguards to ensure that a source page
++ * is not copied to its destination page before the data on
++ * the destination page is no longer useful.
++ *
++ * To do this we maintain the invariant that a source page is
++ * either its own destination page, or it is not a
++ * destination page at all.
++ *
++ * That is slightly stronger than required, but the proof
++ * that no problems will not occur is trivial, and the
++ * implementation is simply to verify.
++ *
++ * When allocating all pages normally this algorithm will run
++ * in O(N) time, but in the worst case it will run in O(N^2)
++ * time. If the runtime is a problem the data structures can
++ * be fixed.
++ */
++ struct page *page;
++ unsigned long addr;
++
++ /*
++ * Walk through the list of destination pages, and see if I
++ * have a match.
++ */
++ list_for_each_entry(page, &image->dest_pages, lru) {
++ addr = page_to_pfn(page) << PAGE_SHIFT;
++ if (addr == destination) {
++ list_del(&page->lru);
++ return page;
++ }
++ }
++ page = NULL;
++ while (1) {
++ kimage_entry_t *old;
++
++ /* Allocate a page, if we run out of memory give up */
++ page = kimage_alloc_pages(gfp_mask, 0);
++ if (!page) {
++ return 0;
++ }
++ /* If the page cannot be used file it away */
++ if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
++ list_add(&page->lru, &image->unuseable_pages);
++ continue;
++ }
++ addr = page_to_pfn(page) << PAGE_SHIFT;
++
++ /* If it is the destination page we want use it */
++ if (addr == destination)
++ break;
++
++ /* If the page is not a destination page use it */
++ if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE))
++ break;
++
++ /*
++ * I know that the page is someones destination page.
++ * See if there is already a source page for this
++ * destination page. And if so swap the source pages.
++ */
++ old = kimage_dst_used(image, addr);
++ if (old) {
++ /* If so move it */
++ unsigned long old_addr;
++ struct page *old_page;
++
++ old_addr = *old & PAGE_MASK;
++ old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
++ copy_highpage(page, old_page);
++ *old = addr | (*old & ~PAGE_MASK);
++
++ /* The old page I have found cannot be a
++ * destination page, so return it.
++ */
++ addr = old_addr;
++ page = old_page;
++ break;
++ }
++ else {
++ /* Place the page on the destination list I
++ * will use it later.
++ */
++ list_add(&page->lru, &image->dest_pages);
++ }
++ }
++ return page;
++}
++
++static int kimage_load_normal_segment(struct kimage *image,
++ struct kexec_segment *segment)
++{
++ unsigned long maddr;
++ unsigned long ubytes, mbytes;
++ int result;
++ unsigned char *buf;
++
++ result = 0;
++ buf = segment->buf;
++ ubytes = segment->bufsz;
++ mbytes = segment->memsz;
++ maddr = segment->mem;
++
++ result = kimage_set_destination(image, maddr);
++ if (result < 0) {
++ goto out;
++ }
++ while(mbytes) {
++ struct page *page;
++ char *ptr;
++ size_t uchunk, mchunk;
++ page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
++ if (page == 0) {
++ result = -ENOMEM;
++ goto out;
++ }
++ result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT);
++ if (result < 0) {
++ goto out;
++ }
++ ptr = kmap(page);
++ /* Start with a clear page */
++ memset(ptr, 0, PAGE_SIZE);
++ ptr += maddr & ~PAGE_MASK;
++ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
++ if (mchunk > mbytes) {
++ mchunk = mbytes;
++ }
++ uchunk = mchunk;
++ if (uchunk > ubytes) {
++ uchunk = ubytes;
++ }
++ result = copy_from_user(ptr, buf, uchunk);
++ kunmap(page);
++ if (result) {
++ result = (result < 0) ? result : -EIO;
++ goto out;
++ }
++ ubytes -= uchunk;
++ maddr += mchunk;
++ buf += mchunk;
++ mbytes -= mchunk;
++ }
++ out:
++ return result;
++}
++
++static int kimage_load_crash_segment(struct kimage *image,
++ struct kexec_segment *segment)
++{
++ /* For crash dumps kernels we simply copy the data from
++ * user space to it's destination.
++ * We do things a page at a time for the sake of kmap.
++ */
++ unsigned long maddr;
++ unsigned long ubytes, mbytes;
++ int result;
++ unsigned char *buf;
++
++ result = 0;
++ buf = segment->buf;
++ ubytes = segment->bufsz;
++ mbytes = segment->memsz;
++ maddr = segment->mem;
++ while(mbytes) {
++ struct page *page;
++ char *ptr;
++ size_t uchunk, mchunk;
++ page = pfn_to_page(maddr >> PAGE_SHIFT);
++ if (page == 0) {
++ result = -ENOMEM;
++ goto out;
++ }
++ ptr = kmap(page);
++ ptr += maddr & ~PAGE_MASK;
++ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
++ if (mchunk > mbytes) {
++ mchunk = mbytes;
++ }
++ uchunk = mchunk;
++ if (uchunk > ubytes) {
++ uchunk = ubytes;
++ /* Zero the trailing part of the page */
++ memset(ptr + uchunk, 0, mchunk - uchunk);
++ }
++ result = copy_from_user(ptr, buf, uchunk);
++ kunmap(page);
++ if (result) {
++ result = (result < 0) ? result : -EIO;
++ goto out;
++ }
++ ubytes -= uchunk;
++ maddr += mchunk;
++ buf += mchunk;
++ mbytes -= mchunk;
++ }
++ out:
++ return result;
++}
++
++static int kimage_load_segment(struct kimage *image,
++ struct kexec_segment *segment)
++{
++ int result = -ENOMEM;
++ switch(image->type) {
++ case KEXEC_TYPE_DEFAULT:
++ result = kimage_load_normal_segment(image, segment);
++ break;
++ case KEXEC_TYPE_CRASH:
++ result = kimage_load_crash_segment(image, segment);
++ break;
++ }
++ return result;
++}
++
++/*
++ * Exec Kernel system call: for obvious reasons only root may call it.
++ *
++ * This call breaks up into three pieces.
++ * - A generic part which loads the new kernel from the current
++ * address space, and very carefully places the data in the
++ * allocated pages.
++ *
++ * - A generic part that interacts with the kernel and tells all of
++ * the devices to shut down. Preventing on-going dmas, and placing
++ * the devices in a consistent state so a later kernel can
++ * reinitialize them.
++ *
++ * - A machine specific part that includes the syscall number
++ * and the copies the image to it's final destination. And
++ * jumps into the image at entry.
++ *
++ * kexec does not sync, or unmount filesystems so if you need
++ * that to happen you need to do that yourself.
++ */
++struct kimage *kexec_image = NULL;
++struct kimage *kexec_crash_image = NULL;
++/*
++ * A home grown binary mutex.
++ * Nothing can wait so this mutex is safe to use
++ * in interrupt context :)
++ */
++static int kexec_lock = 0;
++
++asmlinkage long sys_kexec_load(unsigned long entry,
++ unsigned long nr_segments, struct kexec_segment __user *segments,
++ unsigned long flags)
++{
++ struct kimage **dest_image, *image;
++ int locked;
++ int result;
++
++ /* We only trust the superuser with rebooting the system. */
++ if (!capable(CAP_SYS_BOOT))
++ return -EPERM;
++
++ /*
++ * Verify we have a legal set of flags
++ * This leaves us room for future extensions.
++ */
++ if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK))
++ return -EINVAL;
++
++ /* Verify we are on the appropriate architecture */
++ if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) &&
++ ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
++ {
++ return -EINVAL;
++ }
++
++ /* Put an artificial cap on the number
++ * of segments passed to kexec_load.
++ */
++ if (nr_segments > KEXEC_SEGMENT_MAX)
++ return -EINVAL;
++
++ image = NULL;
++ result = 0;
++
++ /* Because we write directly to the reserved memory
++ * region when loading crash kernels we need a mutex here to
++ * prevent multiple crash kernels from attempting to load
++ * simultaneously, and to prevent a crash kernel from loading
++ * over the top of a in use crash kernel.
++ *
++ * KISS: always take the mutex.
++ */
++ locked = xchg(&kexec_lock, 1);
++ if (locked) {
++ return -EBUSY;
++ }
++ dest_image = &kexec_image;
++ if (flags & KEXEC_ON_CRASH) {
++ dest_image = &kexec_crash_image;
++ }
++ if (nr_segments > 0) {
++ unsigned long i;
++ /* Loading another kernel to reboot into */
++ if ((flags & KEXEC_ON_CRASH) == 0) {
++ result = kimage_normal_alloc(&image, entry, nr_segments, segments);
++ }
++ /* Loading another kernel to switch to if this one crashes */
++ else if (flags & KEXEC_ON_CRASH) {
++ /* Free any current crash dump kernel before
++ * we corrupt it.
++ */
++ kimage_free(xchg(&kexec_crash_image, NULL));
++ result = kimage_crash_alloc(&image, entry, nr_segments, segments);
++ }
++ if (result) {
++ goto out;
++ }
++ result = machine_kexec_prepare(image);
++ if (result) {
++ goto out;
++ }
++ for(i = 0; i < nr_segments; i++) {
++ result = kimage_load_segment(image, &image->segment[i]);
++ if (result) {
++ goto out;
++ }
++ }
++ result = kimage_terminate(image);
++ if (result) {
++ goto out;
++ }
++ }
++ /* Install the new kernel, and Uninstall the old */
++ image = xchg(dest_image, image);
++
++ out:
++ xchg(&kexec_lock, 0); /* Release the mutex */
++ kimage_free(image);
++ return result;
++}
++
++void crash_kexec(void)
++{
++ struct kimage *image;
++ int locked;
++
++
++ /* Take the kexec_lock here to prevent sys_kexec_load
++ * running on one cpu from replacing the crash kernel
++ * we are using after a panic on a different cpu.
++ *
++ * If the crash kernel was not located in a fixed area
++ * of memory the xchg(&kexec_crash_image) would be
++ * sufficient. But since I reuse the memory...
++ */
++ locked = xchg(&kexec_lock, 1);
++ if (!locked) {
++ image = xchg(&kexec_crash_image, NULL);
++ if (image) {
++ machine_crash_shutdown();
++ machine_kexec(image);
++ }
++ xchg(&kexec_lock, 0);
++ }
++}
+diff -Narup linux-2.4.31-orig/kernel/panic.c linux-2.4.31/kernel/panic.c
+--- linux-2.4.31-orig/kernel/panic.c 2004-11-17 03:54:22.000000000 -0800
++++ linux-2.4.31/kernel/panic.c 2005-08-24 22:40:47.000000000 -0700
+@@ -17,6 +17,7 @@
+ #include <linux/sysrq.h>
+ #include <linux/interrupt.h>
+ #include <linux/console.h>
++#include <linux/kexec.h>
+
+ asmlinkage void sys_sync(void); /* it's really int */
+
+@@ -70,6 +71,11 @@ NORET_TYPE void panic(const char * fmt,
+ sys_sync();
+ bust_spinlocks(0);
+
++ /* if we crash and have a crash kernel loaded
++ * let it handle everything else
++ */
++ crash_kexec();
++
+ #ifdef CONFIG_SMP
+ smp_send_stop();
+ #endif
+diff -Narup linux-2.4.31-orig/kernel/sys.c linux-2.4.31/kernel/sys.c
+--- linux-2.4.31-orig/kernel/sys.c 2003-11-28 10:26:21.000000000 -0800
++++ linux-2.4.31/kernel/sys.c 2005-08-24 23:01:24.000000000 -0700
+@@ -15,6 +15,9 @@
+ #include <linux/init.h>
+ #include <linux/highuid.h>
+
++#include <linux/kernel.h>
++#include <linux/kexec.h>
++
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+
+@@ -342,6 +345,21 @@ asmlinkage long sys_reboot(int magic1, i
+ machine_restart(buffer);
+ break;
+
++ case LINUX_REBOOT_CMD_KEXEC:
++ {
++ struct kimage *image;
++ image = xchg(&kexec_image, 0);
++ if (!image) {
++ unlock_kernel();
++ return -EINVAL;
++ }
++ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
++ printk(KERN_EMERG "Starting new kernel\n");
++ machine_shutdown();
++ machine_kexec(image);
++ break;
++ }
++
+ default:
+ unlock_kernel();
+ return -EINVAL;
--- /dev/null
+diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c
+--- linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c 2006-03-16 23:13:06.000000000 +0800
++++ linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c 2006-03-16 12:43:57.000000000 +0800
+@@ -112,6 +112,9 @@ load_kernel(unsigned long load_addr, int
+ /* Set end of memory available to us. It is always the highest
+ * memory address provided by the board information.
+ */
++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6)
++ bp->bi_memsize = (16 * 1024 * 1024); // memory limited to 16 MBytes
++#endif
+ end_avail = (char *)(bp->bi_memsize);
+
+ puts("\nloaded at: "); puthex(load_addr);
+diff -Narup linux-2.4.31-orig/arch/ppc/kernel/ppc4xx_setup.c linux-2.4.31/arch/ppc/kernel/ppc4xx_setup.c
+--- linux-2.4.31-orig/arch/ppc/kernel/ppc4xx_setup.c 2006-03-16 23:13:28.000000000 +0800
++++ linux-2.4.31/arch/ppc/kernel/ppc4xx_setup.c 2006-03-16 12:45:35.000000000 +0800
+@@ -161,6 +161,9 @@ ppc4xx_find_end_of_memory(void)
+ {
+ bd_t *bip = (bd_t *) __res;
+
++#if defined (CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6)
++ bip->bi_memsize = 0x1000000; // memory was limited 16MB.
++#endif
+ return ((unsigned long) bip->bi_memsize);
+ }
+
--- /dev/null
+diff -Narup -x .DS_Store linux-2.4.31/arch/ppc/boot/simple/head.S linux-2.4.31-mod/arch/ppc/boot/simple/head.S
+--- linux-2.4.31/arch/ppc/boot/simple/head.S 2003-11-28 10:26:19.000000000 -0800
++++ linux-2.4.31-mod/arch/ppc/boot/simple/head.S 2005-09-08 11:09:48.000000000 -0700
+@@ -45,6 +45,25 @@ start:
+ .long bootrom_cmdline # address of *bootrom_cmdline
+ #endif
+
++#ifdef CONFIG_HCW_MVP
++ /* This is a versioning structure for use with the Hauppauge MediaMVP
++ * it is provided with no warranty whatsoever. Use at your own risk.
++ */
++#include <dongle_version.h>
++mvp_start:
++ .long 0x48435720 # structure magic - "HCW MVP" (null terminated)
++ .long 0x4D565000
++ .long (mvp_end - mvp_start) # size
++ .long 0x00010000 # struct version (1.0)
++ .long HCW_COMPATIBLE_VERSION # compatible version
++ .long HCW_BUILD_VERSION # build version
++ .long 0 # reserved[4]
++ .long 0
++ .long 0
++ .long 0
++mvp_end:
++#endif
++
+ start_:
+ #ifdef CONFIG_FORCE
+ /* We have some really bad firmware. We must disable the L1
+diff -Narup -x .DS_Store linux-2.4.31/arch/ppc/config.in linux-2.4.31-mod/arch/ppc/config.in
+--- linux-2.4.31/arch/ppc/config.in 2005-09-08 11:04:56.000000000 -0700
++++ linux-2.4.31-mod/arch/ppc/config.in 2005-09-08 11:09:01.000000000 -0700
+@@ -81,6 +81,10 @@ if [ "$CONFIG_40x" = "y" ]; then
+ if [ "$CONFIG_EP405" = "y" ]; then
+ bool 'EP405PC Support' CONFIG_EP405PC
+ fi
++
++ if [ "$CONFIG_REDWOOD_6" = "y" ]; then
++ bool 'Hauppauge MediaMVP support' CONFIG_HCW_MVP
++ fi
+ fi
+
+ if [ "$CONFIG_44x" = "y" ]; then
--- /dev/null
+diff -Narup linux-2.4.31-orig/drivers/char/Config.in linux-2.4.31/drivers/char/Config.in
+--- linux-2.4.31-orig/drivers/char/Config.in 2004-08-07 16:26:04.000000000 -0700
++++ linux-2.4.31/drivers/char/Config.in 2005-08-10 15:01:02.000000000 -0700
+@@ -270,6 +270,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
+ fi
+ fi
+ tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT
++ dep_tristate ' PPC405 Watchdog Timer' CONFIG_PPC405_WDT $CONFIG_4xx
+ if [ "$CONFIG_SGI_IP22" = "y" ]; then
+ dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22
+ fi
+diff -Narup linux-2.4.31-orig/drivers/char/Makefile linux-2.4.31/drivers/char/Makefile
+--- linux-2.4.31-orig/drivers/char/Makefile 2004-08-07 16:26:04.000000000 -0700
++++ linux-2.4.31/drivers/char/Makefile 2005-08-10 15:00:48.000000000 -0700
+@@ -323,6 +323,7 @@ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.
+ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+ obj-$(CONFIG_INDYDOG) += indydog.o
+ obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
++obj-$(CONFIG_PPC405_WDT) += ppc405_wdt.o
+
+ subdir-$(CONFIG_MWAVE) += mwave
+ ifeq ($(CONFIG_MWAVE),y)
+diff -Narup linux-2.4.31-orig/drivers/char/ppc405_wdt.c linux-2.4.31/drivers/char/ppc405_wdt.c
+--- linux-2.4.31-orig/drivers/char/ppc405_wdt.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/drivers/char/ppc405_wdt.c 2005-08-10 14:56:02.000000000 -0700
+@@ -0,0 +1,305 @@
++/*
++ * IBM PowerPC 405 Watchdog: A Simple Hardware Watchdog Device
++ * Based on PowerPC 8xx driver by Scott Anderson which was
++ * based on MixCom driver by Gergely Madarasz which was
++ * based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
++ *
++ * FILE NAME ppc405_wdt.c
++ *
++ * Armin Kuster akuster@mvista.com or source@mvista.com
++ * Sept, 2001
++ *
++ * Orignial driver
++ * Author: MontaVista Software, Inc. <source@mvista.com>
++ * Debbie Chu <debbie_chu@mvista.com>
++ * Frank Rowand <frank_rowand@mvista.com>
++ *
++ * Copyright 2000 MontaVista Software Inc.
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * 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.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Version 0.1 (00/06/05):
++ * Version 0.2 (00/07/12) by Debbie Chu
++ * Version 0.4 (01/09/19) by Armin kuster
++ * Version 0.5 (01/10/10) Akuster
++ * - removed ppc4xx_restart w/ machine_restart
++ */
++
++#define VERSION "0.5"
++
++#define WDT_DEFAULT_PERIOD 120 /* system default 2 minutes */
++#define MAXONEHOUR 3600UL /* Max timeout period 60 minutes */
++#define TENMSBASE 10000UL /* 10 ms */
++#define MICROSECBASE 1000000
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/machdep.h>
++
++#define WDIOC_GETPERIOD _IOR(WATCHDOG_IOCTL_BASE, 6, int)
++#define WDIOC_SETPERIOD _IOW(WATCHDOG_IOCTL_BASE, 7, int)
++
++int wdt_enable;
++unsigned long wdt_period;
++unsigned long wdt_heartbeat_count;
++static unsigned long wdt_count;
++int wdt_default = 1;
++
++static int ppc405wd_opened;
++
++static inline void
++ppc405wd_update_timer(void)
++{
++ wdt_heartbeat_count = wdt_count;
++}
++
++void
++ppc4xx_wdt_heartbeat(void)
++{
++ if (wdt_default ){
++ /* default used until wdt inits */
++ wdt_heartbeat_count = wdt_period * HZ;
++ wdt_default = 0;
++ }
++ if ((wdt_heartbeat_count > 0) || ( !wdt_enable )) {
++ if (wdt_heartbeat_count > 0)
++ wdt_heartbeat_count--;
++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS));
++ } else
++ machine_restart("Watchdog Timer Timed out, system reset!");
++ ppc_md.heartbeat_count = 0;
++}
++
++/*
++ * Allow only one person to hold it open
++ */
++static int ppc405wd_open(struct inode *inode, struct file *file)
++{
++ unsigned int tcr_value;
++
++ if(test_and_set_bit(0,&ppc405wd_opened))
++ return -EBUSY;
++
++ MOD_INC_USE_COUNT;
++
++ /*
++ * There are three ways to enable the watchdog timer:
++ * 1. turn on the watchdog in the bootrom.
++ * 2. turn on the watchdog using the boot command line option,
++ * you can specifiy "wdt=<timeout>" on the boot cmdline
++ * 3. turn on the watchdog in this routine,
++ * the default timer period is set to 2 minutes.
++ */
++
++ tcr_value = mfspr(SPRN_TCR);
++
++ if ((tcr_value & TCR_WRC_MASK) != TCR_WRC(WRC_SYSTEM)) {
++ /*
++ * watchdog reset not enabled yet, enable it
++ * The default timer period is set to 2 minutes.
++ */
++#ifdef DEBUG_WDT
++ mtspr(SPRN_TCR,
++ (mfspr(SPRN_TCR) & ~TCR_WP_MASK & ~TCR_WRC_MASK) |
++ TCR_WP(WP_2_29) |
++ TCR_WRC(WRC_SYSTEM));
++#else
++ mtspr(SPRN_TCR,
++ (mfspr(SPRN_TCR) & ~TCR_WP_MASK & ~TCR_WRC_MASK) |
++ TCR_WP(WP_2_25) |
++ TCR_WRC(WRC_SYSTEM));
++#endif
++ }
++
++ if (wdt_period == 0)
++ wdt_period = WDT_DEFAULT_PERIOD;
++
++ wdt_count = wdt_period * HZ;
++ ppc405wd_update_timer();
++ wdt_enable = 1;
++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS));
++ return 0;
++}
++
++static int ppc405wd_release(struct inode *inode, struct file *file)
++{
++ MOD_DEC_USE_COUNT;
++
++ clear_bit(0,&ppc405wd_opened);
++ return 0;
++}
++
++static ssize_t ppc405wd_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++ /* Can't seek (pwrite) on this device */
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++
++ if (len) {
++ ppc405wd_update_timer();
++ return 1;
++ }
++ return 0;
++}
++
++static int ppc405wd_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned long period;
++ int status;
++ int state;
++ static struct watchdog_info ident = {
++ WDIOF_KEEPALIVEPING,
++ 0,
++ "PPC 405 watchdog"
++ };
++
++ switch (cmd) {
++ case WDIOC_GETSTATUS:
++ status = ppc405wd_opened;
++
++ if (copy_to_user((int *)arg, &status, sizeof(int)))
++ return -EFAULT;
++ break;
++ case WDIOC_GETSUPPORT:
++ if (copy_to_user((struct watchdog_info *)arg, &ident,
++ sizeof(ident))) {
++ return -EFAULT;
++ }
++ break;
++ case WDIOC_KEEPALIVE:
++ ppc405wd_update_timer();
++ break;
++ case WDIOC_SETOPTIONS:
++ if(copy_from_user(&state, (int*) arg, sizeof(int)))
++ return -EFAULT;
++ if (state & WDIOS_DISABLECARD) {
++ wdt_enable = 0;
++ printk(KERN_NOTICE "Soft watchdog timer is disabled\n");
++ break;
++ }
++ if (state & WDIOS_ENABLECARD) {
++ ppc405wd_update_timer();
++ wdt_enable = 1;
++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS));
++ printk(KERN_NOTICE "Soft watchdog timer is enabled\n");
++ break;
++ }
++ case WDIOC_GETPERIOD:
++ /* return watchdog period (units = microseconds) */
++ period = (wdt_period / HZ) * MICROSECBASE;
++ if (copy_to_user((unsigned long *)arg, &period,
++ sizeof(period))) {
++ return -EFAULT;
++ }
++ break;
++ case WDIOC_SETPERIOD:
++ /*
++ ** set watchdog period (units = microseconds)
++ ** value of zero means maximum
++ **
++ ** Don't set a watchdog period to a value less than
++ ** the requested value (period will be rounded up to
++ ** next available interval the watchdog supports).
++ **
++ ** The software watchdog will expire at some point in
++ ** the range of (rounded up period) ..
++ ** (rounded up period + 1 jiffie). If interrupts are
++ ** disabled so that the software watchdog is unable to
++ ** reset the system, then the hardware watchdog will
++ ** eventually reset the system.
++ */
++ if (copy_from_user(&period, (unsigned long *)arg,
++ sizeof(period))) {
++ return -EFAULT;
++ }
++
++ /*
++ ** This code assumes HZ is 100. Need to remove that
++ ** assumption.
++ */
++
++ /*
++ ** The minimum period of ppc405wd_timer is a jiffie,
++ ** which is 10 msec when HZ is 100. The units of
++ ** wdt_period is jiffies.
++ **
++ ** The new timer period will be used at the next
++ ** heartbeat.
++ */
++ if (period == 0)
++ period = MAXONEHOUR * MICROSECBASE;
++
++ wdt_count = (period / TENMSBASE) + (period % TENMSBASE ? 1 : 0);
++ ppc405wd_update_timer();
++
++ break;
++ default:
++ return -ENOIOCTLCMD;
++
++ }
++ return 0;
++}
++
++static struct file_operations ppc405wd_fops =
++{
++ owner: THIS_MODULE,
++ write: ppc405wd_write,
++ ioctl: ppc405wd_ioctl,
++ open: ppc405wd_open,
++ release: ppc405wd_release,
++};
++
++static struct miscdevice ppc405wd_miscdev =
++{
++ WATCHDOG_MINOR,
++ "405_watchdog",
++ &ppc405wd_fops
++};
++
++static int __init ppc405wd_init(void)
++{
++ misc_register(&ppc405wd_miscdev);
++ printk(KERN_NOTICE "PPC 405 watchdog driver v%s\n", VERSION);
++ if (wdt_period == 0)
++ wdt_period = WDT_DEFAULT_PERIOD;
++ wdt_count = wdt_period * HZ;
++ ppc405wd_update_timer();
++ mtspr(SPRN_TSR, (TSR_ENW | TSR_WIS));
++ mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
++ return 0;
++}
++
++void __exit ppc405wd_exit(void)
++{
++ misc_deregister(&ppc405wd_miscdev);
++}
++
++module_init(ppc405wd_init);
++module_exit(ppc405wd_exit);
+diff -Narup linux-2.4.31-orig/include/asm-ppc/machdep.h linux-2.4.31/include/asm-ppc/machdep.h
+--- linux-2.4.31-orig/include/asm-ppc/machdep.h 2003-08-25 04:44:44.000000000 -0700
++++ linux-2.4.31/include/asm-ppc/machdep.h 2005-08-10 15:13:37.000000000 -0700
+@@ -41,6 +41,8 @@ struct machdep_calls {
+ unsigned long (*get_rtc_time)(void);
+ void (*calibrate_decr)(void);
+ void (*heartbeat)(void);
++ unsigned long heartbeat_reset;
++ unsigned long heartbeat_count;
+
+ unsigned long (*find_end_of_memory)(void);
+ void (*setup_io_mappings)(void);
+diff -Narup linux-2.4.31-orig/include/asm-ppc/processor.h linux-2.4.31/include/asm-ppc/processor.h
+--- linux-2.4.31-orig/include/asm-ppc/processor.h 2005-04-03 18:42:20.000000000 -0700
++++ linux-2.4.31/include/asm-ppc/processor.h 2005-08-10 15:10:17.000000000 -0700
+@@ -455,11 +455,13 @@
+ #define WP_2_21 1 /* 2^21 clocks */
+ #define WP_2_25 2 /* 2^25 clocks */
+ #define WP_2_29 3 /* 2^29 clocks */
++#define TCR_WP_MASK TCR_WP(3)
+ #define TCR_WRC(x) (((x)&0x3)<<28) /* WDT Reset Control */
+ #define WRC_NONE 0 /* No reset will occur */
+ #define WRC_CORE 1 /* Core reset will occur */
+ #define WRC_CHIP 2 /* Chip reset will occur */
+ #define WRC_SYSTEM 3 /* System reset will occur */
++#define TCR_WRC_MASK TCR_WRC(3)
+ #define TCR_WIE 0x08000000 /* WDT Interrupt Enable */
+ #define TCR_PIE 0x04000000 /* PIT Interrupt Enable */
+ #define TCR_DIE TCR_PIE /* DEC Interrupt Enable */
--- /dev/null
+/*
+ * redwood.c - mapper for IBM Redwood-4/5/6 board.
+ *
+ *
+ * Copyright 2001 - 2002 MontaVista Softare Inc.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History: 12/17/2001 - Armin
+ * migrated to use do_map_probe
+ *
+ * : 07/11/02 - Armin
+ * added redwood 6 support
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#define STBXX_VPD_SZ 0x10000
+#define STBXX_OB_SZ 0x20000
+#define STBXX_4MB 0x4000000
+
+#if !defined (CONFIG_REDWOOD_6)
+
+#define WINDOW_ADDR 0xffc00000
+#define WINDOW_SIZE 0x00400000
+
+#define RW_PART0_OF 0
+#define RW_PART0_SZ 0x10000
+#define RW_PART1_OF RW_PART0_SZ
+#define RW_PART1_SZ 0x200000 - 0x10000
+#define RW_PART2_OF 0x200000
+#define RW_PART2_SZ 0x10000
+#define RW_PART3_OF 0x210000
+#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000)
+#define RW_PART4_OF 0x3e0000
+#define RW_PART4_SZ 0x20000
+static struct mtd_partition redwood_flash_partitions[] = {
+ {
+ name: "Redwood OpenBIOS Vital Product Data",
+ offset: RW_PART0_OF,
+ size: RW_PART0_SZ,
+ mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "Redwood kernel",
+ offset: RW_PART1_OF,
+ size: RW_PART1_SZ
+ },
+ {
+ name: "Redwood OpenBIOS non-volatile storage",
+ offset: RW_PART2_OF,
+ size: RW_PART2_SZ,
+ mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "Redwood filesystem",
+ offset: RW_PART3_OF,
+ size: RW_PART3_SZ
+ },
+ {
+ name: "Redwood OpenBIOS",
+ offset: RW_PART4_OF,
+ size: RW_PART4_SZ,
+ mask_flags: MTD_WRITEABLE /* force read-only */
+ }
+};
+
+#else
+
+/* FIXME: the window is bigger - armin */
+
+/*
+ * Change4VideoDongle - H. Lin
+ * Warnning: What effects would be if not end on erase block size??
+ * Thus combine VPD,NVRAM,into one 64KB partition, named VPD
+ */
+#if 1 //hcw
+
+/* Supported Devices on HCW MediaMVP */
+#define AMD2048X16K
+#define AMD512X16K
+
+#ifdef AMD2048X16K
+
+#define MB4_WINDOW_ADDR 0xffc00000 /* 4MB part */
+#define MB4_WINDOW_SIZE 0x00400000 /* to hook GPIO Pin26 (BI_ADDR10) to A20 */
+
+#define MB4_RW_PART0_OF 0x000000
+#define MB4_RW_PART0_SZ 0x2c0000
+/*
+#define MB4_RW_PART0_SZ 0x2c0000
+
+#define MB4_RW_PART5_OF MB4_RW_PART0_OF + MB4_RW_PART0_SZ
+#define MB4_RW_PART5_SZ 0x200000
+
+#define MB4_RW_PART4_OF MB4_RW_PART5_OF + MB4_RW_PART5_SZ
+*/
+#define MB4_RW_PART4_OF MB4_RW_PART0_OF + MB4_RW_PART0_SZ
+#define MB4_RW_PART4_SZ 0x100000
+
+#define MB4_RW_PART1_OF MB4_RW_PART4_OF + MB4_RW_PART4_SZ
+#define MB4_RW_PART1_SZ 0x010000 /* 64KB VPD = 4KB VPD + 4KB NVRAM */
+
+#define MB4_RW_PART2_OF MB4_RW_PART1_OF + MB4_RW_PART1_SZ
+#define MB4_RW_PART2_SZ 0x010000 /* 64KB LOGO = 56KB LOGO + 8KB XXX */
+
+#define MB4_RW_PART3_OF MB4_RW_PART2_OF + MB4_RW_PART2_SZ /* 128KB Bootloader(Open BIOS) */
+#define MB4_RW_PART3_SZ 0x020000
+
+static struct mtd_partition mb4_redwood_flash_partitions[] = {
+ {
+ name: "HCW MediaMVP KERN",
+ offset: MB4_RW_PART0_OF,
+ size: MB4_RW_PART0_SZ,
+ },
+/*
+ {
+ name: "HCW MediaMVP FS",
+ offset: MB4_RW_PART5_OF,
+ size: MB4_RW_PART5_SZ,
+ },
+*/
+ {
+ name: "HCW MediaMVP DATA",
+ offset: MB4_RW_PART4_OF,
+ size: MB4_RW_PART4_SZ,
+ },
+ {
+ name: "HCW MediaMVP VPD",
+ offset: MB4_RW_PART1_OF,
+ size: MB4_RW_PART1_SZ,
+ },
+ {
+ name: "HCW MediaMVP LOGO",
+ offset: MB4_RW_PART2_OF,
+ size: MB4_RW_PART2_SZ,
+ },
+ {
+ name: "HCW MediaMVP BOOT",
+ offset: MB4_RW_PART3_OF,
+ size: MB4_RW_PART3_SZ,
+ }
+};
+
+#endif
+
+
+#ifdef AMD512X16K
+
+#define MB1_WINDOW_ADDR 0xfff00000
+#define MB1_WINDOW_SIZE 0x00100000
+
+#define MB1_RW_PART0_OF 0
+#define MB1_RW_PART0_SZ 0x80000 /* 8*64 = 512KB data */
+
+#define MB1_RW_PART1_OF MB1_RW_PART0_OF + MB1_RW_PART0_SZ
+#define MB1_RW_PART1_SZ 0x10000 /* 64KB VPD = 4KB VPD + 4KB NVRAM */
+
+#define MB1_RW_PART2_OF MB1_RW_PART1_OF + MB1_RW_PART1_SZ
+#define MB1_RW_PART2_SZ 0x10000 /* 64KB LOGO = 56KB LOGO + 8KB XXX */
+
+#define MB1_RW_PART3_OF MB1_RW_PART2_OF + MB1_RW_PART2_SZ
+#define MB1_RW_PART3_SZ 0x80000-0x20000-0x20000 /* 320 - 64 = 256KB File System */
+
+#define MB1_RW_PART4_OF MB1_RW_PART3_OF + MB1_RW_PART3_SZ /* 128KB Bootloader(Open BIOS) */
+#define MB1_RW_PART4_SZ 0x20000
+
+static struct mtd_partition mb1_redwood_flash_partitions[] = {
+ {
+ name: "HCW MediaMVP KERN",
+ offset: MB1_RW_PART0_OF,
+ size: MB1_RW_PART0_SZ,
+ },
+ {
+ name: "HCW MediaMVP VPD",
+ offset: MB1_RW_PART1_OF,
+ size: MB1_RW_PART1_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "HCW MediaMVP LOGO",
+ offset: MB1_RW_PART2_OF,
+ size: MB1_RW_PART2_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "HCW MediaMVP FS",
+ offset: MB1_RW_PART3_OF,
+ size: MB1_RW_PART3_SZ,
+ },
+ {
+ name: "HCW MediaMVP BOOT",
+ offset: MB1_RW_PART4_OF,
+ size: MB1_RW_PART4_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ }
+};
+#endif
+
+#ifdef AMD128X16K
+
+#define MBQ_WINDOW_ADDR 0xfffC0000
+#define MBQ_WINDOW_SIZE 0x00040000
+
+#define MBQ_RW_PART0_OF 0
+#define MBQ_RW_PART0_SZ 0x10000 /* 64KB VPD (4KB VPD + 4KB NVRAM) */
+
+#define MBQ_RW_PART1_OF MBQ_RW_PART0_OF + MBQ_RW_PART0_SZ
+#define MBQ_RW_PART1_SZ 0x10000 /* 64KB Logo */
+
+#define MBQ_RW_PART2_OF MBQ_RW_PART1_OF + MBQ_RW_PART1_SZ
+#define MBQ_RW_PART2_SZ 0x20000 /* 128KB Bootloader(Open BIOS) */
+
+
+static struct mtd_partition mbq_redwood_flash_partitions[] = {
+ {
+ name: "HCW MediaMVP VPD",
+ offset: MBQ_RW_PART0_OF,
+ size: MBQ_RW_PART0_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "HCW MediaMVP LOGO",
+ offset: MBQ_RW_PART1_OF,
+ size: MBQ_RW_PART1_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "HCW MediaMVP BOOT",
+ offset: MBQ_RW_PART2_OF,
+ size: MBQ_RW_PART2_SZ,
+ //mask_flags: MTD_WRITEABLE /* force read-only */
+ }
+};
+
+#endif
+
+#else //org
+
+#define WINDOW_ADDR 0xff800000
+#define WINDOW_SIZE 0x00800000
+
+#define RW_PART0_OF 0
+#define RW_PART0_SZ 0x400000 /* 4 MB data */
+#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ
+#define RW_PART1_SZ 0x10000 /* 64K VPD */
+#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ
+#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000)
+#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ
+#define RW_PART3_SZ 0x20000
+
+static struct mtd_partition redwood_flash_partitions[] = {
+ {
+ name: "Redwood kernel",
+ offset: RW_PART0_OF,
+ size: RW_PART0_SZ
+ },
+ {
+ name: "Redwood OpenBIOS Vital Product Data",
+ offset: RW_PART1_OF,
+ size: RW_PART1_SZ,
+ mask_flags: MTD_WRITEABLE /* force read-only */
+ },
+ {
+ name: "Redwood filesystem",
+ offset: RW_PART2_OF,
+ size: RW_PART2_SZ
+ },
+ {
+ name: "Redwood OpenBIOS",
+ offset: RW_PART3_OF,
+ size: RW_PART3_SZ,
+ mask_flags: MTD_WRITEABLE /* force read-only */
+ }
+};
+
+#endif
+
+#endif
+
+__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(volatile unsigned int *)(map->map_priv_1 + ofs);
+}
+
+void redwood_flash_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+
+
+struct map_info redwood_flash_map = {
+ name: "HCW MediaMVP",
+// size: WINDOW_SIZE,
+ buswidth: 2,
+ read8: redwood_flash_read8,
+ read16: redwood_flash_read16,
+ read32: redwood_flash_read32,
+ copy_from: redwood_flash_copy_from,
+ write8: redwood_flash_write8,
+ write16: redwood_flash_write16,
+ write32: redwood_flash_write32,
+ copy_to: redwood_flash_copy_to
+};
+
+#define NUM_REDWOOD_FLASH_PARTITIONS(flash_partitions) \
+ (sizeof(flash_partitions)/sizeof((flash_partitions)[0]))
+
+
+static struct mtd_info *redwood_mtd;
+
+int __init init_redwood_flash(void)
+{
+ int numparts;
+ struct mtd_partition *redwood_flash_partitions;
+
+#ifdef AMD512X16K
+ /*
+ * Am29LV800/200BT does NOT seem to do CFI
+ */
+ redwood_flash_map.map_priv_1 =
+ (unsigned long)ioremap(MB1_WINDOW_ADDR, MB1_WINDOW_SIZE);
+
+ if (!redwood_flash_map.map_priv_1) {
+ printk("init_redwood_flash: failed to ioremap\n");
+ return -EIO;
+ }
+
+ printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n",
+ MB1_WINDOW_SIZE, MB1_WINDOW_ADDR, redwood_flash_map.map_priv_1);
+
+ redwood_flash_map.size = MB1_WINDOW_SIZE;
+ redwood_mtd = do_map_probe("jedec_probe",&redwood_flash_map);
+ if(redwood_mtd) {
+ printk("jedec_probe: found redwood_mtd size = %08x\n", redwood_mtd->size);
+ if( redwood_mtd->size == 0x00100000 ) {
+ redwood_flash_partitions = mb1_redwood_flash_partitions;
+ numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb1_redwood_flash_partitions);
+ printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: add [%d]parts\n", numparts);
+ goto add_parts;
+ } else {
+ map_destroy( redwood_mtd );
+ }
+ }
+ printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: no known JEDEC part found\n");
+ iounmap((void*)(redwood_flash_map.map_priv_1));
+
+try_4mb_flash:
+#endif
+
+#ifdef AMD2048X16K
+
+ redwood_flash_map.map_priv_1 =
+ (unsigned long)ioremap(MB4_WINDOW_ADDR, MB4_WINDOW_SIZE);
+
+ if (!redwood_flash_map.map_priv_1) {
+ printk("init_redwood_flash: failed to ioremap\n");
+ return -EIO;
+ }
+
+ printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n",
+ MB4_WINDOW_SIZE, MB4_WINDOW_ADDR, redwood_flash_map.map_priv_1);
+
+#if 1
+ /*
+ * do CFI for 320DT
+ */
+ redwood_flash_map.size = MB4_WINDOW_SIZE;
+ redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
+ if(redwood_mtd) {
+ printk("cfi_probe: found redwood_mtd size = %08x\n", redwood_mtd->size);
+ redwood_flash_partitions = mb4_redwood_flash_partitions;
+ numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb4_redwood_flash_partitions);
+ printk(KERN_NOTICE "HCW MediaMVP: cfi_probe: adding [%d]parts\n", numparts);
+ goto add_parts;
+ }
+ else {
+ printk(KERN_NOTICE "HCW MediaMVP: cfi_probe: no known CFI part found\n");
+ iounmap((void*)(redwood_flash_map.map_priv_1));
+ }
+#endif
+
+#if 0
+ /*
+ * try jedec too for ST320DT???
+ */
+ redwood_flash_map.map_priv_1 =
+ (unsigned long)ioremap(MB4_WINDOW_ADDR, MB4_WINDOW_SIZE);
+
+ if (!redwood_flash_map.map_priv_1) {
+ printk("init_redwood_flash: failed to ioremap\n");
+ return -EIO;
+ }
+
+ printk(KERN_NOTICE "HCW MediaMVP: flash mapping: %x at %x to %lx\n",
+ MB4_WINDOW_SIZE, MB4_WINDOW_ADDR, redwood_flash_map.map_priv_1);
+
+ redwood_flash_map.size = MB4_WINDOW_SIZE;
+ redwood_mtd = do_map_probe("jedec_probe",&redwood_flash_map);
+ if(redwood_mtd) {
+ printk("jedec_probe: found redwood_mtd size = %08x\n", redwood_mtd->size);
+ redwood_flash_partitions = mb4_redwood_flash_partitions;
+ numparts = NUM_REDWOOD_FLASH_PARTITIONS(mb4_redwood_flash_partitions);
+ printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: adding [%d]parts\n", numparts);
+ goto add_parts;
+ }
+ else {
+ printk(KERN_NOTICE "HCW MediaMVP: jedec_probe: no known CFI part found\n");
+ iounmap((void*)(redwood_flash_map.map_priv_1));
+ }
+#endif
+#endif
+
+
+add_parts:
+ if (redwood_mtd) {
+ redwood_mtd->module = THIS_MODULE;
+ return add_mtd_partitions(redwood_mtd, redwood_flash_partitions, numparts);
+ }
+
+ return -ENXIO;
+}
+
+static void __exit cleanup_redwood_flash(void)
+{
+ if (redwood_mtd) {
+ del_mtd_partitions(redwood_mtd);
+ /* moved iounmap after map_destroy -armin*/
+ map_destroy(redwood_mtd);
+ iounmap((void *)redwood_flash_map.map_priv_1);
+ }
+}
+
+module_init(init_redwood_flash);
+module_exit(cleanup_redwood_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Armin Kuster <akuster@mvista.com>");
+MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
--- /dev/null
+diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/Makefile linux-2.4.31/arch/ppc/boot/simple/Makefile
+--- linux-2.4.31-orig/arch/ppc/boot/simple/Makefile 2005-12-14 15:16:26.000000000 +0800
++++ linux-2.4.31/arch/ppc/boot/simple/Makefile 2006-01-15 17:28:42.000000000 +0800
+@@ -152,6 +152,7 @@ zImage: $(ZIMAGE)
+ rm -f zvmlinux
+ zImage.initrd: $(ZIMAGEINITRD)
+ rm -f zvmlinux.initrd
++ cp -f ../images/zImage.initrd.$(END) $(INSTALL_PATH)/dongle.bin
+
+ znetboot: zImage
+ cp ../images/zImage.$(END) $(TFTPIMAGE)
+diff -Narup linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c
+--- linux-2.4.31-orig/arch/ppc/boot/simple/misc-embedded.c 2005-12-14 16:27:53.000000000 +0800
++++ linux-2.4.31/arch/ppc/boot/simple/misc-embedded.c 2006-01-15 17:28:42.000000000 +0800
+@@ -221,6 +221,7 @@ load_kernel(unsigned long load_addr, int
+ gunzip(0, 0x400000, zimage_start, &zimage_size);
+ flush_instruction_cache();
+ puts("done.\n");
++#ifdef CONFIG_BLK_DEV_INITRD
+ {
+ struct bi_record *rec;
+ unsigned long initrd_loc;
+@@ -271,6 +272,31 @@ load_kernel(unsigned long load_addr, int
+ rec->size = sizeof(struct bi_record);
+ rec = (struct bi_record *)((unsigned long)rec + rec->size);
+ }
++#else
++ {
++ /* Moving Squash Rootfs to sdram bank1 */
++ if(initrd_size){
++ #define MAGIC_VER_HCW 0x48435720
++ #define MAGIC_VER_MVP 0x4D565000
++ unsigned long *magic_hcw;
++ unsigned long *magic_mvp;
++ unsigned long *initrd_sz;
++
++ magic_hcw = 0xa0fff200;
++ magic_mvp = 0xa0fff204;
++ /* if there is no magic number on new xram_start + 512 bytes, we assume
++ * system boot first time then move boot data into new xram position. */
++ if( *magic_hcw != MAGIC_VER_HCW && *magic_mvp != MAGIC_VER_MVP ){
++ puts("\nMoving xram data to 0xa0fff000\n");
++ memcpy((void*)(0xa0fff000), (void*)(0xa0f00000), 0x1000);
++ }
++ puts("Moving initrd to 0xa0d00000\n");
++ memcpy((void*)(0xa0d00000), &__ramdisk_begin, initrd_size);
++ /* writing initrd size into bottom of bank1 memory */
++ memcpy((void*)0xa0fffffc, &initrd_size, 4);
++ }
++ }
++#endif
+ puts("Now booting the kernel\n");
+ serial_close(com_port);
+
+diff -Narup linux-2.4.31-orig/drivers/mtd/maps/Config.in linux-2.4.31/drivers/mtd/maps/Config.in
+--- linux-2.4.31-orig/drivers/mtd/maps/Config.in 2005-12-14 15:16:07.000000000 +0800
++++ linux-2.4.31/drivers/mtd/maps/Config.in 2006-01-15 17:28:22.000000000 +0800
+@@ -45,6 +45,7 @@ if [ "$CONFIG_PPC" = "y" ]; then
+ dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
+ dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
+ dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
++ dep_tristate ' SDRAM device mapping on Hauppauge MVP' CONFIG_MTD_MVP_RAM $CONFIG_MTD_CFI
+ fi
+
+ if [ "$CONFIG_MIPS" = "y" ]; then
+diff -Narup linux-2.4.31-orig/drivers/mtd/maps/Makefile linux-2.4.31/drivers/mtd/maps/Makefile
+--- linux-2.4.31-orig/drivers/mtd/maps/Makefile 2005-12-14 15:16:07.000000000 +0800
++++ linux-2.4.31/drivers/mtd/maps/Makefile 2006-01-15 17:28:22.000000000 +0800
+@@ -61,5 +61,6 @@ obj-$(CONFIG_MTD_REDWOOD) += redwood.o
+ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
+ obj-$(CONFIG_MTD_NETtel) += nettel.o
+ obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
++obj-$(CONFIG_MTD_MVP_RAM) += ramdisk.o
+
+ include $(TOPDIR)/Rules.make
+diff -Narup linux-2.4.31-orig/drivers/mtd/maps/ramdisk.c linux-2.4.31/drivers/mtd/maps/ramdisk.c
+--- linux-2.4.31-orig/drivers/mtd/maps/ramdisk.c 1970-01-01 08:00:00.000000000 +0800
++++ linux-2.4.31/drivers/mtd/maps/ramdisk.c 2006-01-15 17:28:22.000000000 +0800
+@@ -0,0 +1,187 @@
++/*
++ * HCW sdram mtd Driver
++ */
++#include <linux/config.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#if CONFIG_MODVERSIONS == 1
++#define MODVERSIONS
++#include <linux/modversions.h>
++#endif
++
++#include <linux/fs.h>
++#include <asm/io.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <linux/string.h>
++#include <linux/slab.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++
++#define KDBG(fmt, args...) if(1) printk("<sdram-mtd>: " fmt, ## args)
++
++
++#define __PHYSICAL_ROOTFS_BASE 0xA0D00000
++#define __PHYSICAL_ROOTFS_SIZE_BASE 0xA0FFFFFC
++#define __PHYSICAL_ROOTFS_END_BASE 0xA0FFF000
++#define __PHYSICAL_TOTAL_SIZE 0x002FF000
++
++#define GetRootSize() {return (*rootfs_size)}
++
++
++//
++// read/write function.
++//
++static __u8 sdram_read8(struct map_info *map, unsigned long ofs)
++{
++ return readb(map->map_priv_1 + ofs);
++}
++
++static __u16 sdram_read16(struct map_info *map, unsigned long ofs)
++{
++ return readw(map->map_priv_1 + ofs);
++}
++
++static __u32 sdram_read32(struct map_info *map, unsigned long ofs)
++{
++ return readl(map->map_priv_1 + ofs);
++}
++
++static void sdram_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ memcpy(to, (void *)(map->map_priv_1 + from), len);
++}
++
++static void sdram_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ writeb(d, map->map_priv_1 + adr);
++}
++
++static void sdram_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ writew(d, map->map_priv_1 + adr);
++}
++
++static void sdram_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ writel(d, map->map_priv_1 + adr);
++}
++
++static void sdram_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ memcpy((void *)(map->map_priv_1 + to), from, len);
++}
++
++static struct mtd_partition hcwmvp_sdram_partitions[] = {
++ {
++ name: "HCW MediaMVP ROOT",
++ offset: 0x00000000 ,
++ },
++ {
++ name: "HCW MediaMVP OSD",
++ },
++};
++
++//
++// sdram mtd map structure.
++//
++struct map_info hcwmvp_sdram_map = {
++ name:"SDRAM MTD Device",
++ buswidth: 2,
++ read8: sdram_read8,
++ read16: sdram_read16,
++ read32: sdram_read32,
++ copy_from: sdram_copy_from,
++ write8: sdram_write8,
++ write16: sdram_write16,
++ write32: sdram_write32,
++ copy_to: sdram_copy_to
++};
++static struct mtd_info *hcwmvp_sdram_mtd=NULL;
++
++static unsigned long
++sdram_init(void)
++{
++ /*
++ * I/O Remap
++ */
++ hcwmvp_sdram_map.map_priv_1 =
++ (unsigned long)ioremap(__PHYSICAL_ROOTFS_BASE, __PHYSICAL_TOTAL_SIZE);
++ if (!hcwmvp_sdram_map.map_priv_1) {
++ KDBG("sdram-1 MTD device map failed\n");
++ return 0;
++ }
++ hcwmvp_sdram_map.map_priv_2 = (unsigned long)ioremap(__PHYSICAL_ROOTFS_SIZE_BASE, 4);
++ if (!hcwmvp_sdram_map.map_priv_2) {
++ KDBG("sdram-2 MTD device map failed\n");
++ return 0;
++ }
++
++ KDBG("SDRAM MTD(%8.8X) mapped to %08x\n", (int)__PHYSICAL_ROOTFS_BASE, (int)hcwmvp_sdram_map.map_priv_1);
++
++ return 1;
++}
++
++/*
++ * module interface
++ */
++static int __init
++sdram_init_module(void)
++{
++ unsigned int root_size=0;
++ /*
++ * Probe & reset Device
++ */
++ if(!sdram_init()) {
++ KDBG("sdram Module Init Failed: Wrong Dev\n");
++ return -1;
++ }
++
++ /*
++ * register mtd device
++ */
++ hcwmvp_sdram_map.size = __PHYSICAL_TOTAL_SIZE;
++ hcwmvp_sdram_mtd = do_map_probe("map_ram",&hcwmvp_sdram_map);
++ if (hcwmvp_sdram_mtd) {
++ hcwmvp_sdram_mtd->module = THIS_MODULE;
++ //hcwmvp_sdram_mtd->erasesize = 0xF0000;
++ //add_mtd_device(hcwmvp_sdram_mtd);
++ root_size = in_be32((u32*)hcwmvp_sdram_map.map_priv_2);
++ //root_size |= in_be16((u16*)(hcwmvp_sdram_map.map_priv_2+2));
++ //KDBG("root_size =%x \n", root_size);
++ hcwmvp_sdram_partitions[0].size = root_size;
++ hcwmvp_sdram_partitions[1].offset = root_size;
++ hcwmvp_sdram_partitions[1].size = __PHYSICAL_TOTAL_SIZE - root_size;
++ add_mtd_partitions(hcwmvp_sdram_mtd, hcwmvp_sdram_partitions, 2);
++ }
++ else{
++ iounmap((void*)(hcwmvp_sdram_map.map_priv_1));
++ }
++
++ return 0;
++}
++
++static void __exit
++sdram_cleanup_module(void)
++{
++ /* unregister mtd device. */
++ //if (hcwmvp_sdram_mtd) del_mtd_device(hcwmvp_sdram_mtd);
++ if (hcwmvp_sdram_mtd){
++ del_mtd_partitions(hcwmvp_sdram_mtd);
++ map_destroy(hcwmvp_sdram_mtd);
++ }
++ if (hcwmvp_sdram_map.map_priv_1 != -1) iounmap((void *)hcwmvp_sdram_map.map_priv_1);
++}
++module_init(sdram_init_module);
++module_exit(sdram_cleanup_module);
++MODULE_LICENSE("GPL");
--- /dev/null
+diff -Narup linux-2.4.31-orig/drivers/net/Config.in linux-2.4.31/drivers/net/Config.in
+--- linux-2.4.31-orig/drivers/net/Config.in 2005-01-19 06:09:56.000000000 -0800
++++ linux-2.4.31/drivers/net/Config.in 2005-08-03 09:52:16.000000000 -0700
+@@ -116,6 +116,19 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; the
+ 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 91111 support' CONFIG_SMC91111
++ if [ "$CONFIG_SMC91111" != "n" ]; then
++ bool ' Advanced configuration options for SMC91111' CONFIG_SMC91111_ADVANCED
++ if [ "$CONFIG_SMC91111_ADVANCED" = "n" ]; then
++ define_bool CONFIG_SMC91111_BYTE_SWAP n
++ define_bool CONFIG_SMC91111_USE_8_BIT y
++ define_bool CONFIG_SMC91111_USE_32_BIT y
++ else
++ bool ' Byte swap device accesses' CONFIG_SMC91111_BYTE_SWAP
++ bool ' Allow 8 bit device accesses' CONFIG_SMC91111_USE_8_BIT
++ bool ' Allow 32 bit device accesses' CONFIG_SMC91111_USE_32_BIT
++ fi
++ fi
+ fi
+ bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+ if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
+diff -Narup linux-2.4.31-orig/drivers/net/Makefile linux-2.4.31/drivers/net/Makefile
+--- linux-2.4.31-orig/drivers/net/Makefile 2005-01-19 06:09:56.000000000 -0800
++++ linux-2.4.31/drivers/net/Makefile 2005-08-03 10:17:28.000000000 -0700
+@@ -139,6 +139,7 @@ obj-$(CONFIG_SHAPER) += shaper.o
+ obj-$(CONFIG_SK_G16) += sk_g16.o
+ obj-$(CONFIG_HP100) += hp100.o
+ obj-$(CONFIG_SMC9194) += smc9194.o
++obj-$(CONFIG_SMC91111) += smc91111.o
+ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
+ obj-$(CONFIG_ARM_ETHERH) += 8390.o
+ obj-$(CONFIG_WD80x3) += wd.o 8390.o
+diff -Narup linux-2.4.31-orig/drivers/net/smc91111.c linux-2.4.31/drivers/net/smc91111.c
+--- linux-2.4.31-orig/drivers/net/smc91111.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/drivers/net/smc91111.c 2005-08-03 09:52:34.000000000 -0700
+@@ -0,0 +1,3746 @@
++/*------------------------------------------------------------------------
++ . smc91111.c
++ . This is a driver for SMSC's 91C111 single-chip Ethernet device.
++ .
++ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
++ . Developed by Simple Network Magic Corporation (SNMC)
++ . Copyright (C) 1996 by Erik Stahlman (ES)
++ .
++ . 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.
++ .
++ .
++ . "Features" of the SMC chip:
++ . Integrated PHY/MAC for 10/100BaseT Operation
++ . Supports internal and external MII
++ . Integrated 8K packet memory
++ . EEPROM interface for configuration
++ .
++ . Arguments:
++ . io = for the base address
++ . irq = for the IRQ
++ . nowait = 0 for normal wait states, 1 eliminates additional wait states
++ .
++ . author:
++ . Erik Stahlman ( erik@vt.edu )
++ . Daris A Nevil ( dnevil@snmc.com )
++ . contributors:
++ . Arnaldo Carvalho de Melo <acme@conectiva.com.br>
++ .
++ . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
++ .
++ . Sources:
++ . o SMSC LAN91C111 databook (www.smsc.com)
++ . o smc9194.c by Erik Stahlman
++ . o skeleton.c by Donald Becker ( becker@scyld.com )
++ .
++ . 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"
++ . 04/25/01 Daris A Nevil Initial public release through SMSC
++ . 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111
++ . 08/22/01 Scott Anderson Merge changes from smc9194 to smc91111
++ ----------------------------------------------------------------------------*/
++
++// Use power-down feature of the chip
++#define POWER_DOWN 1
++
++/*
++ . DEBUGGING LEVELS
++ .
++ . 0 for normal operation
++ . 1 for slightly more details
++ . >2 for various levels of increasingly useless information
++ . 2 for interrupt tracking, status flags
++ . 3 for packet info
++ . 4 for complete packet dumps
++*/
++#ifndef SMC_DEBUG
++#define SMC_DEBUG 0
++#endif
++
++static const char version[] =
++ "smc91111.c:v1.0saa 08/22/01 by Daris A Nevil (dnevil@snmc.com)\n";
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/in.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++
++#ifdef CONFIG_SYSCTL
++#include <linux/proc_fs.h>
++#include <linux/sysctl.h>
++#endif
++
++#include "smc91111.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 */
++
++static struct net_device *global_dev = NULL;
++#ifndef SMC91111_BASE_ADDR
++# define SMC91111_BASE_ADDR -1
++#endif
++static int io = SMC91111_BASE_ADDR;
++#ifndef SMC91111_IRQ
++# define SMC91111_IRQ -1
++#endif
++static int irq = SMC91111_IRQ;
++static int nowait = 1; //Haup=>
++
++MODULE_PARM(io, "i");
++MODULE_PARM(irq, "i");
++MODULE_PARM(nowait, "i");
++MODULE_PARM_DESC(io, "SMC 91111 I/O base address");
++MODULE_PARM_DESC(irq, "SMC 91111 IRQ number");
++
++/*
++ . 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
++
++#if SMC_DEBUG > 2
++#define PRINTK3(args...) printk(args)
++#else
++#define PRINTK3(args...)
++#endif
++
++#if SMC_DEBUG > 1
++#define PRINTK2(args...) printk(args)
++#else
++#define PRINTK2(args...)
++#endif
++
++#if SMC_DEBUG > 0
++#define PRINTK(args...) printk(args)
++#else
++#define PRINTK(args...)
++#endif
++
++
++/*------------------------------------------------------------------------
++ .
++ . 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 "LAN91C111"
++
++// Memory sizing constant
++#define LAN91C111_MEMORY_MULTIPLIER (1024*2)
++
++/* store this information for the driver.. */
++struct smc_local {
++
++ // 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;
++
++ // 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;
++
++ // This keeps track of how many packets that I have
++ // sent out. When an TX_EMPTY interrupt comes, I know
++ // that all of these have been sent.
++ int packets_waiting;
++
++ // Set to true during the auto-negotiation sequence
++ int autoneg_active;
++
++ // Address of our PHY port
++ word phyaddr;
++
++ // Type of PHY
++ word phytype;
++
++ // Last contents of PHY Register 18
++ word lastPhy18;
++
++ // Contains the current active transmission mode
++ word tcr_cur_mode;
++
++ // Contains the current active receive mode
++ word rcr_cur_mode;
++
++ // Contains the current active receive/phy mode
++ word rpc_cur_mode;
++
++
++#ifdef CONFIG_SYSCTL
++
++ // Root directory /proc/sys/dev
++ // Second entry must be null to terminate the table
++ ctl_table root_table[2];
++
++ // Directory for this device /proc/sys/dev/ethX
++ // Again the second entry must be zero to terminate
++ ctl_table eth_table[2];
++
++ // This is the parameters (file) table
++ ctl_table param_table[CTL_SMC_LAST_ENTRY];
++
++ // Saves the sysctl header returned by register_sysctl_table()
++ // we send this to unregister_sysctl_table()
++ struct ctl_table_header *sysctl_header;
++
++ // Parameter variables (files) go here
++ char ctl_info[1024];
++ int ctl_swfdup;
++ int ctl_ephloop;
++ int ctl_miiop;
++ int ctl_autoneg;
++ int ctl_rfduplx;
++ int ctl_rspeed;
++ int ctl_afduplx;
++ int ctl_aspeed;
++ int ctl_lnkfail;
++ int ctl_forcol;
++ int ctl_filtcar;
++ int ctl_freemem;
++ int ctl_totmem;
++ int ctl_leda;
++ int ctl_ledb;
++ int ctl_chiprev;
++#if SMC_DEBUG > 0
++ int ctl_reg_bsr;
++ int ctl_reg_tcr;
++ int ctl_reg_esr;
++ int ctl_reg_rcr;
++ int ctl_reg_ctrr;
++ int ctl_reg_mir;
++ int ctl_reg_rpcr;
++ int ctl_reg_cfgr;
++ int ctl_reg_bar;
++ int ctl_reg_iar0;
++ int ctl_reg_iar1;
++ int ctl_reg_iar2;
++ int ctl_reg_gpr;
++ int ctl_reg_ctlr;
++ int ctl_reg_mcr;
++ int ctl_reg_pnr;
++ int ctl_reg_fpr;
++ int ctl_reg_ptr;
++ int ctl_reg_dr;
++ int ctl_reg_isr;
++ int ctl_reg_mtr1;
++ int ctl_reg_mtr2;
++ int ctl_reg_mtr3;
++ int ctl_reg_mtr4;
++ int ctl_reg_miir;
++ int ctl_reg_revr;
++ int ctl_reg_ercvr;
++ int ctl_reg_extr;
++ int ctl_phy_ctrl;
++ int ctl_phy_stat;
++ int ctl_phy_id1;
++ int ctl_phy_id2;
++ int ctl_phy_adc;
++ int ctl_phy_remc;
++ int ctl_phy_cfg1;
++ int ctl_phy_cfg2;
++ int ctl_phy_int;
++ int ctl_phy_mask;
++#endif // SMC_DEBUG > 0
++
++
++#endif // CONFIG_SYSCTL
++
++};
++
++
++/*-----------------------------------------------------------------
++ .
++ . The driver can be entered at any of the following entry points.
++ .
++ .------------------------------------------------------------------ */
++
++/*
++ . The kernel calls this function when someone wants to use the device,
++ . typically 'ifconfig ethX up'.
++*/
++static int smc_open(struct net_device *dev);
++
++/*
++ . Our watchdog timed out. Called by the networking layer
++*/
++static void smc_timeout(struct net_device *dev);
++
++/*
++ . This is called by the kernel in response to 'ifconfig ethX down'. It
++ . is responsible for cleaning up everything that the open routine
++ . does, and maybe putting the card into a powerdown state.
++*/
++static int smc_close(struct net_device *dev);
++
++/*
++ . This routine allows the proc file system to query the driver's
++ . statistics.
++*/
++static struct net_device_stats * smc_query_statistics( struct net_device *dev);
++
++/*
++ . Finally, a call to set promiscuous mode ( for TCPDUMP and related
++ . programs ) and multicast modes.
++*/
++static void smc_set_multicast_list(struct net_device *dev);
++
++/*
++ . CRC compute
++ */
++static int crc32( char * s, int length );
++
++/*
++ . Configures the PHY through the MII Management interface
++*/
++static void smc_phy_configure(struct net_device* dev);
++
++/*---------------------------------------------------------------
++ .
++ . Interrupt level calls..
++ .
++ ----------------------------------------------------------------*/
++
++/*
++ . Handles the actual interrupt
++*/
++static void smc_interrupt(int irq, void *, struct pt_regs *regs);
++/*
++ . This is a separate procedure to handle the receipt of a packet, to
++ . leave the interrupt code looking slightly cleaner
++*/
++inline static void smc_rcv( struct net_device *dev );
++/*
++ . This handles a TX interrupt, which is only called when an error
++ . relating to a packet is sent.
++*/
++inline static void smc_tx( struct net_device * dev );
++
++/*
++ . This handles interrupts generated from PHY register 18
++*/
++static void smc_phy_interrupt(struct net_device* dev);
++
++/*
++ ------------------------------------------------------------
++ .
++ . Internal routines
++ .
++ ------------------------------------------------------------
++*/
++
++/*
++ . Test if a given location contains a chip, trying to cause as
++ . little damage as possible if it's not a SMC chip.
++*/
++static int smc_probe(struct net_device *dev, unsigned long ioaddr);
++
++/*
++ . A rather simple routine to print out a packet for debugging purposes.
++*/
++#if SMC_DEBUG > 2
++static void print_packet( byte *, int );
++#endif
++
++#define tx_done(dev) 1
++
++/* this is called to actually send the packet to the chip */
++static void smc_hardware_send_packet( struct net_device * dev );
++
++/* 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 generates an interrupt when the card is ready for the
++ . packet */
++static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
++
++/* this does a soft reset on the device */
++static void smc_reset( struct net_device* dev );
++
++/* Enable Interrupts, Receive, and Transmit */
++static void smc_enable( struct net_device *dev );
++
++/* this puts the device in an inactive state */
++static void smc_shutdown( unsigned long ioaddr );
++
++/* This routine will find the IRQ of the driver if one is not
++ . specified in the input to the device. */
++static int smc_findirq( unsigned long ioaddr );
++
++/* Routines to Read and Write the PHY Registers across the
++ MII Management Interface
++*/
++
++static word smc_read_phy_register(unsigned long ioaddr,
++ byte phyaddr, byte phyreg);
++static void smc_write_phy_register(unsigned long ioaddr,
++ byte phyaddr, byte phyreg, word phydata);
++
++/*
++ Initilizes our device's sysctl proc filesystem
++*/
++
++#ifdef CONFIG_SYSCTL
++static void smc_sysctl_register(struct net_device *dev);
++static void smc_sysctl_unregister(struct net_device *dev);
++#endif /* CONFIG_SYSCTL */
++
++/*
++ . Function: smc_reset( struct net_device* dev )
++ . Purpose:
++ . This sets the SMC91111 chip to its normal state, hopefully from whatever
++ . mess that any other DOS driver has put it in.
++ .
++ . Maybe I should reset more registers to defaults in here? SOFTRST should
++ . do that for me.
++ .
++ . Method:
++ . 1. send a SOFT RESET
++ . 2. wait for it to finish
++ . 3. enable autorelease mode
++ . 4. reset the memory management unit
++ . 5. clear all interrupts
++ .
++*/
++static void smc_reset( struct net_device* dev )
++{
++ //struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++
++ PRINTK2("%s:smc_reset\n", dev->name);
++
++ /* 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 (dev->dma)
++ 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
++
++ SMC_SELECT_BANK( 0 );
++
++ /* this should pause enough for the chip to be happy */
++ mdelay(10);
++
++ /* Disable transmit and receive functionality */
++ 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 );
++ SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE );
++
++ /* Reset the MMU */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_MMU_CMD( MC_RESET );
++
++ /* Note: It doesn't seem that waiting for the MMU busy is needed here,
++ but this is a place where future chipsets _COULD_ break. Be wary
++ of issuing another MMU command right after this */
++
++ /* Disable all interrupts */
++ SMC_SET_INT_MASK( 0 );
++}
++
++/*
++ . Function: smc_enable
++ . Purpose: let the chip talk to the outside work
++ . Method:
++ . 1. Enable the transmitter
++ . 2. Enable the receiver
++ . 3. Enable interrupts
++*/
++static void smc_enable( struct net_device *dev )
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++
++ PRINTK2("%s:smc_enable\n", dev->name);
++
++ SMC_SELECT_BANK( 0 );
++ /* see the header file for options in TCR/RCR DEFAULT*/
++ SMC_SET_TCR( lp->tcr_cur_mode );
++ SMC_SET_RCR( lp->rcr_cur_mode );
++
++ /* now, enable interrupts */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_INT_MASK( SMC_INTERRUPT_MASK );
++}
++
++/*
++ . Function: smc_shutdown
++ . Purpose: closes down the SMC91xxx chip.
++ . Method:
++ . 1. zero the interrupt mask
++ . 2. clear the enable receive flag
++ . 3. clear the enable xmit flags
++ .
++ . TODO:
++ . (1) maybe utilize power down mode.
++ . Why not yet? Because while the chip will go into power down mode,
++ . the manual says that it will wake up in response to any I/O requests
++ . in the register space. Empirical results do not show this working.
++*/
++static void smc_shutdown( unsigned long ioaddr )
++{
++ PRINTK2(CARDNAME ":smc_shutdown\n");
++
++ /* 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
++}
++
++
++/*
++ . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
++ . Purpose:
++ . 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 */
++ unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
++
++ PRINTK2(CARDNAME ":smc_setmulticast\n");
++
++ /* 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 );
++}
++
++/*
++ Finds the CRC32 of a set of bytes.
++ Again, 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;
++}
++
++
++/*
++ . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
++ . Purpose:
++ . Attempt to allocate memory for a packet, if chip-memory is not
++ . available, then tell the card to generate an interrupt when it
++ . is available.
++ .
++ . Algorithm:
++ .
++ . o if the saved_skb is not currently null, then drop this packet
++ . on the floor. This should never happen, because of TBUSY.
++ . o if the saved_skb is null, then replace it with the current packet,
++ . o See if I can sending it now.
++ . o (NO): Enable interrupts and let the interrupt handler deal with it.
++ . o (YES):Send it now.
++*/
++static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ word length;
++ unsigned short numPages;
++ word time_out;
++ word status;
++
++ PRINTK3("%s:smc_wait_to_send_packet\n", dev->name);
++
++ netif_stop_queue(dev);
++ /* Well, I want to send the packet.. but I don't know
++ if I can send it right now... */
++
++ if ( lp->saved_skb) {
++ /* THIS SHOULD NEVER HAPPEN. */
++ lp->stats.tx_aborted_errors++;
++ printk("%s: Bad Craziness - sent packet while busy.\n",
++ dev->name);
++ return 1;
++ }
++ lp->saved_skb = skb;
++
++ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
++
++
++ /*
++ ** 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 this header.
++ */
++ numPages = ((length & 0xfffe) + 6);
++ numPages >>= 8; // Divide by 256
++
++ if (numPages > 7 ) {
++ printk("%s: Far too big packet error. \n", dev->name);
++ /* freeing the packet is a good thing here... but should
++ . any packets of this size get down here? */
++ dev_kfree_skb (skb);
++ lp->saved_skb = NULL;
++ /* this IS an error, but, i don't want the skb saved */
++ netif_wake_queue(dev);
++ return 0;
++ }
++ /* either way, a packet is waiting now */
++ lp->packets_waiting++;
++
++ /* now, try to allocate the memory */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_MMU_CMD( MC_ALLOC | numPages );
++ /*
++ . Performance Hack
++ .
++ . wait a short amount of time.. if I can send a packet now, I send
++ . it now. Otherwise, I enable an interrupt and wait for one to be
++ . available.
++ .
++ . I could have handled this a slightly different way, by checking to
++ . see if any memory was available in the FREE MEMORY register. However,
++ . either way, I need to generate an allocation, and the allocation works
++ . no matter what, so I saw no point in checking free memory.
++ */
++ time_out = MEMORY_WAIT_TIME;
++ do {
++ status = SMC_GET_INT();
++ if ( status & IM_ALLOC_INT ) {
++ /* acknowledge the interrupt */
++ SMC_ACK_INT( IM_ALLOC_INT );
++ break;
++ }
++ } while ( -- time_out );
++
++ if ( !time_out ) {
++ /* oh well, wait until the chip finds memory later */
++ SMC_ENABLE_INT( IM_ALLOC_INT );
++
++ /* Check the status bit one more time just in case */
++ /* it snuk in between the time we last checked it */
++ /* and when we set the interrupt bit */
++ status = SMC_GET_INT();
++ if ( !(status & IM_ALLOC_INT) ) {
++ PRINTK2("%s: memory allocation deferred. \n",
++ dev->name);
++ /* it's deferred, but I'll handle it later */
++ return 0;
++ }
++
++ /* Looks like it did sneak in, so disable */
++ /* the interrupt */
++ SMC_DISABLE_INT( IM_ALLOC_INT );
++ }
++ /* or YES! I can send the packet now.. */
++ smc_hardware_send_packet(dev);
++ netif_wake_queue(dev);
++ return 0;
++}
++
++/*
++ . Function: smc_hardware_send_packet(struct net_device * )
++ . Purpose:
++ . This sends the actual packet to the SMC9xxx chip.
++ .
++ . Algorithm:
++ . First, see if a saved_skb is available.
++ . ( this should NOT be called if there is no 'saved_skb'
++ . Now, find the packet number that the chip allocated
++ . Point the data pointers at it in memory
++ . Set the length word in the chip's memory
++ . Dump the packet to chip memory
++ . Check if a last byte is needed ( odd length packet )
++ . if so, set the control flag right
++ . Tell the card to send it
++ . Enable the transmit interrupt, so I know if it failed
++ . Free the kernel data if I actually sent it.
++*/
++static void smc_hardware_send_packet( struct net_device * dev )
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ byte packet_no;
++ struct sk_buff * skb = lp->saved_skb;
++ word length;
++ unsigned long ioaddr;
++ byte * buf;
++
++ PRINTK3("%s:smc_hardware_send_packet\n", dev->name);
++
++ ioaddr = dev->base_addr;
++
++ if ( !skb ) {
++ PRINTK("%s: In XMIT with no packet to send \n", dev->name);
++ return;
++ }
++ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
++ buf = skb->data;
++
++ /* If I get here, I _know_ there is a packet slot waiting for me */
++ packet_no = SMC_GET_AR();
++ if ( packet_no & AR_FAILED ) {
++ /* or isn't there? BAD CHIP! */
++ printk(KERN_DEBUG "%s: Memory allocation failed. \n",
++ dev->name);
++ dev_kfree_skb_any(skb);
++ lp->saved_skb = NULL;
++ netif_wake_queue(dev);
++ return;
++ }
++
++ /* we have a packet address, so tell the card to use it */
++ SMC_SET_PN( packet_no );
++
++ /* point to the beginning of the packet */
++ SMC_SET_PTR( PTR_AUTOINC );
++
++ PRINTK3("%s: Trying to xmit packet of length %x\n",
++ dev->name, length);
++
++#if SMC_DEBUG > 2
++ printk("Transmitting Packet\n");
++ print_packet( buf, length );
++#endif
++
++ /* send the packet length ( +6 for status, length and ctl byte )
++ and the status word ( set to zeros ) */
++#ifdef CONFIG_SMC91111_USE_32_BIT
++ SMC_outl( (length +6 ) << 16 , ioaddr + DATA_REG );
++#else
++ SMC_outw( 0, ioaddr + DATA_REG );
++ /* send the packet length ( +6 for status words, length, and ctl*/
++ SMC_outw( (length+6), ioaddr + DATA_REG );
++#endif
++
++ /* send the actual data
++ . I _think_ it's faster to send the longs first, and then
++ . mop up by sending the last word. It depends heavily
++ . on alignment, at least on the 486. Maybe it would be
++ . a good idea to check which is optimal? But that could take
++ . almost as much time as is saved?
++ */
++#ifdef CONFIG_SMC91111_USE_32_BIT
++ SMC_outsl(ioaddr + DATA_REG, buf, length >> 2 );
++ if ( length & 0x2 )
++ SMC_outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +
++ DATA_REG);
++#else
++ SMC_outsw(ioaddr + DATA_REG , buf, (length ) >> 1);
++#endif // CONFIG_SMC91111_USE_32_BIT
++
++ /* Send the last byte, if there is one. */
++ if ( (length & 1) == 0 ) {
++ SMC_outw( 0, ioaddr + DATA_REG );
++ } else {
++ SMC_outw( 0x2000 | buf[length -1 ], ioaddr + DATA_REG );
++ }
++
++ /* enable the interrupts */
++ SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );
++
++ /* and let the chipset deal with it */
++ SMC_SET_MMU_CMD( MC_ENQUEUE );
++
++ PRINTK2("%s: Sent packet of length %d \n", dev->name, length);
++
++ lp->saved_skb = NULL;
++ dev_kfree_skb_any (skb);
++
++ dev->trans_start = jiffies;
++
++ /* we can send another packet */
++ netif_wake_queue(dev);
++
++ return;
++}
++
++/*-------------------------------------------------------------------------
++ |
++ | 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 int __init smc_init( void )
++{
++ int rtn;
++
++ PRINTK2(CARDNAME ":smc_init\n");
++
++ /*
++ * Haup=> Set BRCR1 TWT to wait for 7+1=8 SYS_CLK(63MHz) => 126.98ns > 100 ns)
++ * Changes: 02/09/2004=> reduce Bus Hold Time to 1 SYS_CLK
++ */
++ {
++ #define BRCR_REGMEM_BASE 0x70
++ #define REG_BRCRH0 (BRCR_REGMEM_BASE + 0)
++ #define REG_BRCRH1 (BRCR_REGMEM_BASE + 1)
++ #define REG_BRCRH2 (BRCR_REGMEM_BASE + 2)
++ #define REG_BRCRH3 (BRCR_REGMEM_BASE + 3)
++
++ #define REG_BRCR0 (BRCR_REGMEM_BASE + 0x10)
++ #define REG_BRCR1 (BRCR_REGMEM_BASE + 0x11)
++ #define REG_BRCR2 (BRCR_REGMEM_BASE + 0x12)
++ #define REG_BRCR3 (BRCR_REGMEM_BASE + 0x13)
++ #define REG_BIUCR (BRCR_REGMEM_BASE + 0x2A)
++
++ #define __to_asm_token(s) #s
++
++ #define MF_DCR(rn) __mfdcr_or_dflt(rn, 0)
++
++ #define __mfdcr_or_dflt(rn,default_rval) \
++ ({unsigned int rval; \
++ if (rn == 0) \
++ rval = default_rval; \
++ else \
++ asm volatile("mfdcr %0," __to_asm_token(rn) : "=r" (rval)); \
++ rval;})
++
++ #define MT_DCR(rn, v) \
++ {if (rn != 0) \
++ asm volatile("mtdcr " __to_asm_token(rn) ",%0" : : "r" (v));}
++
++
++ unsigned int brcr1;
++
++ brcr1 = MF_DCR(REG_BRCR1);
++ printk("smsc91111 org brcr1 = 0x%08x\n", brcr1);
++
++ /* set TWT = 7+1 SYS_CLK */
++ brcr1 = (brcr1 & ~(0x3f<<8)) | (7<<8);
++ /* set TH = 1 SYS_CLK */
++ brcr1 = (brcr1 & ~(0x07<<1)) | (0x01<<1);
++
++ MT_DCR(REG_BRCR1, brcr1);
++ brcr1 = MF_DCR(REG_BRCR1);
++ printk("smsc91111 (brcr1 = 0x%08x) => TWT cycle = %d\n",
++ brcr1,
++ ((brcr1 & (0x3f<<8))>>8));
++ } //end of haup
++
++#ifdef MODULE
++ if (io == -1)
++ printk(KERN_WARNING
++ CARDNAME": You shouldn't use auto-probing with insmod!\n" );
++#endif
++
++ if (global_dev) {
++ printk(CARDNAME ": already initialized.\n");
++ return -EBUSY;
++ }
++
++ global_dev = init_etherdev(0, sizeof(struct smc_local));
++ if (!global_dev) {
++ printk(CARDNAME ": could not allocate device.\n");
++ return -ENODEV;
++ }
++ 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;
++ global_dev->dma = nowait; // Use DMA field for nowait
++
++#ifdef CONFIG_ISA
++ /* try a specific location */
++ if (global_dev->base_addr > 0x1ff)
++ rtn = smc_probe(global_dev, global_dev->base_addr);
++ else if (global_dev->base_addr != 0)
++ rtn = -ENXIO;
++ else {
++ int i;
++
++ /* check every ethernet address */
++ for (i = 0; smc_portlist[i]; i++) {
++ rtn = smc_probe(global_dev, smc_portlist[i]);
++ if (rtn == 0)
++ break;
++ }
++ }
++
++xxxx
++#else
++ if (global_dev->base_addr == -1) {
++ printk(KERN_WARNING
++ CARDNAME": SMC91111_BASE_ADDR not set!\n" );
++ rtn = -ENXIO;
++ }
++ else
++ rtn = smc_probe(global_dev,
++ (int)ioremap(global_dev->base_addr,
++ SMC_IO_EXTENT));
++#endif
++
++ if (rtn != 0) {
++ printk(CARDNAME ": not found.\n");
++ /* couldn't find anything */
++#ifndef CONFIG_ISA
++ iounmap((void *)global_dev->base_addr);
++#endif
++ kfree(global_dev->priv);
++ unregister_netdev(global_dev);
++ kfree(global_dev);
++ }
++
++ return rtn;
++}
++
++/*----------------------------------------------------------------------
++ . 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(CARDNAME ":smc_findirq\n");
++
++ /* I have to do a STI() here, because this is called from
++ a routine that does an CLI during this process, making it
++ rather difficult to get interrupts for auto detection */
++ sti();
++
++ 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.
++ */
++
++
++ SMC_SELECT_BANK(2);
++ /* enable ALLOCation interrupts ONLY */
++ 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
++ */
++ while ( timeout ) {
++ byte int_status;
++
++ int_status = SMC_GET_INT();
++
++ if ( int_status & IM_ALLOC_INT )
++ break; /* got the interrupt */
++ 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. */
++
++ /* DELAY HERE!
++ On a fast machine, the status might change before the interrupt
++ is given to the processor. This means that the interrupt was
++ never detected, and autoirq_report fails to report anything.
++ This should fix autoirq_* problems.
++ */
++ mdelay(10);
++
++ /* and disable all interrupts again */
++ SMC_SET_INT_MASK( 0 );
++
++ /* clear hardware interrupts again, because that's how it
++ was when I was called... */
++ cli();
++
++ /* 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 SMC91111 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)
++{
++ int i, memory, retval;
++ static unsigned version_printed;
++ unsigned int bank;
++
++ const char *version_string;
++ const char *if_string = 0;
++
++ /* registers */
++ word revision_register;
++ word base_address_register;
++ word memory_info_register;
++
++ PRINTK2(CARDNAME ":smc_probe\n");
++
++ /* 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 */
++ bank = SMC_CURRENT_BANK();
++ if ( (bank & 0xFF00) != 0x3300 ) {
++ if ( (bank & 0xFF) == 0x33 ) {
++ printk(CARDNAME
++ ": Detected possible byte-swapped interface"
++ " at IOADDR %lx\n", 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);
++ bank = SMC_CURRENT_BANK();
++ if ( (bank & 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);
++ base_address_register = SMC_GET_BASE();
++ base_address_register = ((base_address_register & 0xE000)
++ | ((base_address_register & 0x1F00) >> 3));
++ if ( (ioaddr & (PAGE_SIZE-1)) != base_address_register ) {
++ printk(CARDNAME ": IOADDR %lx doesn't match configuration (%x)."
++ "Probably not a SMC chip\n",
++ ioaddr, base_address_register );
++ /* well, the base address register didn't match. Must not have
++ been a SMC chip after all. */
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++ /* 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();
++ if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) {
++ /* I don't recognize this chip, so... */
++ printk(CARDNAME ": IO %lx: Unrecognized revision register:"
++ " %x, Contact author. \n",
++ ioaddr, revision_register );
++
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++ /* at this point I'll assume that the chip is an SMC9xxx.
++ It might be prudent to check a listing of MAC addresses
++ against the hardware address, or do some other tests. */
++
++ if (version_printed++ == 0)
++ printk("%s", version);
++
++ /* fill in some of the fields */
++ dev->base_addr = ioaddr;
++
++ /*
++ . Get the MAC address ( bank 1, regs 4 - 9 )
++ */
++ SMC_SELECT_BANK( 1 );
++ for ( i = 0; i < 6; i += 2 ) {
++ word address;
++
++ address = SMC_inw( ioaddr + ADDR0_REG + i );
++ dev->dev_addr[ i + 1] = address >> 8;
++ dev->dev_addr[ i ] = address & 0xFF;
++ }
++
++ /* get the memory information */
++
++ SMC_SELECT_BANK( 0 );
++ memory_info_register = SMC_GET_MIR();
++ memory = memory_info_register & (word)0x00ff;
++ memory *= LAN91C111_MEMORY_MULTIPLIER;
++
++ /*
++ Now, I want to find out more about the chip. This is sort of
++ redundant, but it's cleaner to have it in both, rather than having
++ one VERY long probe procedure.
++ */
++ SMC_SELECT_BANK(3);
++ revision_register = SMC_GET_REV();
++ version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ];
++ if ( !version_string ) {
++ /* I shouldn't get here because this call was done before.... */
++ retval = -ENODEV;
++ goto err_out;
++ }
++
++
++ /* 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 < 2 ) {
++ 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;
++ }
++ if (dev->irq == 2) {
++ /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
++ * or don't know which one to set.
++ */
++ dev->irq = 9;
++ }
++
++ /* now, print out the card info, in a short format.. */
++
++ printk("%s: %s(r:%d) at %#lx IRQ:%d\n", dev->name,
++ version_string, revision_register & 0xF, ioaddr, dev->irq );
++ printk(" INTF:%s MEM:%db NOWAIT:%d", if_string, memory, dev->dma );
++ /*
++ . Print the Ethernet address
++ */
++ printk(" ADDR ");
++ for (i = 0; i < 5; i++)
++ printk("%2.2x:", dev->dev_addr[i] );
++ printk("%2.2x \n", dev->dev_addr[5] );
++
++ /* set the private data to zero by default */
++ memset(dev->priv, 0, sizeof(struct smc_local));
++
++ /* 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_wait_to_send_packet;
++ dev->tx_timeout = smc_timeout;
++ dev->watchdog_timeo = HZ/20;
++ 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;
++}
++
++#if SMC_DEBUG > 2
++static void print_packet( byte * buf, int length )
++{
++#if 1
++#if SMC_DEBUG > 3
++ int i;
++ int remainder;
++ int lines;
++#endif
++
++ printk("Packet of length %d \n", length );
++
++#if SMC_DEBUG > 3
++ lines = length / 16;
++ remainder = length % 16;
++
++ for ( i = 0; i < lines ; i ++ ) {
++ int cur;
++
++ for ( cur = 0; cur < 8; cur ++ ) {
++ byte a, b;
++
++ a = *(buf ++ );
++ b = *(buf ++ );
++ printk("%02x%02x ", a, b );
++ }
++ printk("\n");
++ }
++ for ( i = 0; i < remainder/2 ; i++ ) {
++ byte a, b;
++
++ a = *(buf ++ );
++ b = *(buf ++ );
++ printk("%02x%02x ", a, b );
++ }
++ printk("\n");
++#endif
++#endif
++}
++#endif
++
++
++/*
++ * 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;
++ int i; /* used to set hw ethernet address */
++
++ PRINTK2("%s:smc_open\n", dev->name);
++
++ /* 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 (files)
++ lp->ctl_swfdup = 0;
++ lp->ctl_ephloop = 0;
++ lp->ctl_miiop = 0;
++ lp->ctl_autoneg = 1; //1
++ lp->ctl_rfduplx = 0; //Haup=> negotiate for HALF?
++ lp->ctl_rspeed = 100; //100
++ lp->ctl_afduplx = 0; //1
++ lp->ctl_aspeed = 100; //100
++ lp->ctl_lnkfail = 1;
++ lp->ctl_forcol = 0;
++ lp->ctl_filtcar = 0;
++
++ /* reset the hardware */
++
++ smc_reset( dev );
++ smc_enable( dev );
++
++ /* Configure the PHY */
++ smc_phy_configure(dev);
++
++ /*
++ According to Becker, I have to set the hardware address
++ at this point, because the (l)user can set it with an
++ ioctl. Easily done...
++ */
++ SMC_SELECT_BANK( 1 );
++ for ( i = 0; i < 6; i += 2 ) {
++ word address;
++
++ address = dev->dev_addr[ i + 1 ] << 8 ;
++ address |= dev->dev_addr[ i ];
++ SMC_outw( address, ioaddr + ADDR0_REG + i );
++ }
++
++#ifdef CONFIG_SYSCTL
++ smc_sysctl_register(dev);
++#endif /* CONFIG_SYSCTL */
++
++ netif_start_queue(dev);
++ return 0;
++}
++
++/*--------------------------------------------------------
++ . Called by the kernel to send a packet out into the void
++ . of the net. This routine is largely based on
++ . skeleton.c, from Becker.
++ .--------------------------------------------------------
++*/
++static void smc_timeout(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++
++ PRINTK3("%s:smc_timeout\n", dev->name);
++
++ /* If we get here, some higher level has decided we are broken.
++ There should really be a "kick me" function call instead. */
++ printk(KERN_WARNING "%s: transmit timed out, %s?\n",
++ dev->name, tx_done(dev) ? "IRQ conflict" :
++ "network cable problem");
++ /* "kick" the adaptor */
++ 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
++ dev->trans_start = jiffies;
++ /* clear anything saved */
++ if (lp->saved_skb != NULL) {
++ dev_kfree_skb (lp->saved_skb);
++ lp->saved_skb = NULL;
++ }
++ ((struct smc_local *)dev->priv)->saved_skb = NULL;
++ netif_wake_queue(dev);
++}
++
++/*--------------------------------------------------------------------
++ .
++ . This is the main routine of the driver, to handle the device when
++ . it needs some attention.
++ .
++ . So:
++ . first, save state of the chipset
++ . branch off into routines to handle each case, and acknowledge
++ . each to the interrupt register
++ . and finally restore state.
++ .
++ ---------------------------------------------------------------------*/
++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;
++
++ byte status;
++ word card_stats;
++ byte mask;
++ int timeout;
++ /* state registers */
++ word saved_bank;
++ word saved_pointer;
++
++ PRINTK3("%s: SMC interrupt started \n", dev->name);
++
++ if (dev == NULL) {
++ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
++ dev->name, irq);
++ return;
++ }
++
++ saved_bank = SMC_CURRENT_BANK();
++
++ SMC_SELECT_BANK(2);
++ saved_pointer = SMC_GET_PTR();
++
++ /* read the interrupt mask register */
++ mask = SMC_GET_INT_MASK();
++
++ /* disable all interrupts */
++ SMC_SET_INT_MASK( 0 );
++
++ /* set a timeout value, so I don't stay here forever */
++ timeout = 4;
++
++ PRINTK2(KERN_WARNING "%s: MASK IS %x \n", dev->name, mask);
++ do {
++ /* read the status flag, and mask it */
++ status = SMC_GET_INT() & mask;
++ if (!status )
++ break;
++
++ PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n",
++ dev->name, status);
++
++ if (status & IM_RCV_INT) {
++ /* Got a packet(s). */
++ PRINTK2(KERN_WARNING
++ "%s: Receive Interrupt\n", dev->name);
++ smc_rcv(dev);
++ } else if (status & IM_TX_INT ) {
++ PRINTK2(KERN_WARNING "%s: TX ERROR handled\n",
++ dev->name);
++ smc_tx(dev);
++ // Acknowledge the interrupt
++ SMC_ACK_INT( IM_TX_INT );
++ } else if (status & IM_TX_EMPTY_INT ) {
++ /* update stats */
++ SMC_SELECT_BANK( 0 );
++ card_stats = SMC_GET_COUNTER();
++ /* single collisions */
++ lp->stats.collisions += card_stats & 0xF;
++ card_stats >>= 4;
++ /* multiple collisions */
++ lp->stats.collisions += card_stats & 0xF;
++
++ /* these are for when linux supports these statistics */
++
++ SMC_SELECT_BANK( 2 );
++ PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",
++ dev->name);
++ // Acknowledge the interrupt
++ SMC_ACK_INT( IM_TX_EMPTY_INT );
++ mask &= ~IM_TX_EMPTY_INT;
++ lp->stats.tx_packets += lp->packets_waiting;
++ lp->packets_waiting = 0;
++
++ } else if (status & IM_ALLOC_INT ) {
++ PRINTK2(KERN_DEBUG "%s: Allocation interrupt \n",
++ dev->name);
++ /* clear this interrupt so it doesn't happen again */
++ mask &= ~IM_ALLOC_INT;
++
++ smc_hardware_send_packet( dev );
++
++ /* enable xmit interrupts based on this */
++ mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
++
++ /* and let the card send more packets to me */
++ netif_wake_queue(dev);
++
++ PRINTK2("%s: Handoff done successfully.\n",
++ dev->name);
++ } else if (status & IM_RX_OVRN_INT ) {
++ lp->stats.rx_errors++;
++ lp->stats.rx_fifo_errors++;
++ // Acknowledge the interrupt
++ SMC_ACK_INT( IM_RX_OVRN_INT );
++ } else if (status & IM_EPH_INT ) {
++ PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n",
++ dev->name);
++ } else if (status & IM_MDINT ) {
++ smc_phy_interrupt(dev);
++ // Acknowledge the interrupt
++ SMC_ACK_INT( IM_MDINT );
++ } else if (status & IM_ERCV_INT ) {
++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n",
++ dev->name);
++ // Acknowledge the interrupt
++ SMC_ACK_INT( IM_ERCV_INT );
++ }
++ } while ( timeout -- );
++
++
++ /* restore register states */
++
++ SMC_SELECT_BANK( 2 );
++
++ SMC_SET_INT_MASK( mask );
++
++ PRINTK3( KERN_WARNING "%s: MASK is now %x \n", dev->name, mask);
++ SMC_SET_PTR( saved_pointer );
++
++ SMC_SELECT_BANK( saved_bank );
++
++ PRINTK3("%s: Interrupt done\n", dev->name);
++ return;
++}
++
++/*-------------------------------------------------------------
++ .
++ . smc_rcv - receive a packet from the card
++ .
++ . There is ( at least ) a packet waiting to be read from
++ . chip-memory.
++ .
++ . o Read the status
++ . o If an error, record it
++ . o otherwise, read in the packet
++ --------------------------------------------------------------
++*/
++static void smc_rcv(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ unsigned long ioaddr = dev->base_addr;
++ int packet_number;
++ word status;
++ word packet_length;
++
++ PRINTK3("%s:smc_rcv\n", dev->name);
++
++ /* assume bank 2 */
++
++ packet_number = SMC_GET_RXFIFO();
++
++ if ( packet_number & RXFIFO_REMPTY ) {
++
++ /* we got called , but nothing was on the FIFO */
++ PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n",
++ dev->name);
++ /* don't need to restore anything */
++ return;
++ }
++
++ /* start reading from the start of the packet */
++ SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC );
++
++ /* First two words are status and packet_length */
++ status = SMC_inw( ioaddr + DATA_REG );
++ packet_length = SMC_inw( ioaddr + DATA_REG );
++
++ packet_length &= 0x07ff; /* mask off top bits */
++
++ PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );
++
++ if ( !(status & RS_ERRORS ) ){
++ /* do stuff to make a new packet */
++ struct sk_buff * skb;
++ byte * data;
++
++ /* set multicast stats */
++ if ( status & RS_MULTICAST )
++ lp->stats.multicast++;
++
++ // Allocate enough memory for entire receive frame, to be safe
++ skb = dev_alloc_skb( packet_length );
++
++ /* Adjust for having already read the first two words */
++ packet_length -= 4;
++
++ if ( skb == NULL ) {
++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
++ dev->name);
++ lp->stats.rx_dropped++;
++ goto done;
++ }
++
++ /*
++ ! This should work without alignment, but it could be
++ ! in the worse case
++ */
++
++ skb_reserve( skb, 2 ); /* 16 bit alignment */
++
++ skb->dev = dev;
++
++ // set odd length for bug in LAN91C111,
++ // which never sets RS_ODDFRAME
++ data = skb_put( skb, packet_length + 1 );
++
++#ifdef CONFIG_SMC91111_USE_32_BIT
++ PRINTK3(" Reading %d dwords (and %d bytes) \n",
++ packet_length >> 2, packet_length & 3 );
++ /* QUESTION: Like in the TX routine, do I want
++ to send the DWORDs or the bytes first, or some
++ mixture. A mixture might improve already slow PIO
++ performance */
++ SMC_insl(ioaddr + DATA_REG , data, packet_length >> 2 );
++ /* read the left over bytes */
++#ifdef CONFIG_SMC91111_USE_8_BIT
++ SMC_insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC),
++ packet_length & 0x3 );
++#else
++ if (packet_length & 0x3)
++ {
++ unsigned long remaining_data;
++ insl(ioaddr + DATA_REG , &remaining_data, 1);
++ memcpy(data + (packet_length & 0xFFFFFC),
++ &remaining_data, packet_length & 0x3 );
++ }
++#endif // CONFIG_SMC91111_USE_8_BIT
++#else
++ PRINTK3(" Reading %d words and %d byte(s) \n",
++ (packet_length >> 1 ), packet_length & 1 );
++ SMC_insw(ioaddr + DATA_REG , data, packet_length >> 1);
++
++#endif // CONFIG_SMC91111_USE_32_BIT
++
++#if SMC_DEBUG > 2
++ printk("Receiving Packet\n");
++ print_packet( data, packet_length );
++#endif
++
++ skb->protocol = eth_type_trans(skb, dev );
++ netif_rx(skb);
++ dev->last_rx = jiffies;
++ lp->stats.rx_packets++;
++ lp->stats.rx_bytes += packet_length;
++ } else {
++ /* error ... */
++ 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++;
++ }
++
++ while ( SMC_GET_MMU_CMD() & MC_BUSY )
++ udelay(1); // Wait until not busy
++
++done:
++ /* error or good, tell the card to get rid of this packet */
++ SMC_SET_MMU_CMD( MC_RELEASE );
++}
++
++
++/*************************************************************************
++ . smc_tx
++ .
++ . Purpose: Handle a transmit error message. This will only be called
++ . when an error, because of the AUTO_RELEASE mode.
++ .
++ . Algorithm:
++ . Save pointer and packet no
++ . Get the packet no from the top of the queue
++ . check if it's valid ( if not, is this an error??? )
++ . read the status word
++ . record the error
++ . ( resend? Not really, since we don't want old packets around )
++ . Restore saved values
++ ************************************************************************/
++static void smc_tx( struct net_device * dev )
++{
++ unsigned long ioaddr = dev->base_addr;
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ byte saved_packet;
++ byte packet_no;
++ word tx_status;
++
++
++ PRINTK3("%s:smc_tx\n", dev->name);
++
++ /* assume bank 2 */
++
++ saved_packet = SMC_GET_PN();
++ packet_no = SMC_GET_RXFIFO();
++ packet_no &= 0x7F;
++
++ /* If the TX FIFO is empty then nothing to do */
++ if ( packet_no & TXFIFO_TEMPTY )
++ return;
++
++ /* select this as the packet to read from */
++ SMC_SET_PN( packet_no );
++
++ /* read the first word (status word) from this packet */
++ SMC_SET_PTR( PTR_AUTOINC | PTR_READ );
++
++ tx_status = SMC_inw( ioaddr + DATA_REG );
++ PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status);
++
++ 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++;
++ lp->ctl_forcol = 0; // Reset forced collsion
++ }
++#if 0
++ if ( tx_status & TS_16COL ) { ... }
++#endif
++
++ if ( tx_status & TS_SUCCESS ) {
++ printk("%s: Successful packet caused interrupt \n", dev->name);
++ }
++ /* re-enable transmit */
++ SMC_SELECT_BANK( 0 );
++ SMC_SET_TCR( SMC_GET_TCR() | TCR_ENABLE );
++
++ /* kill the packet */
++ SMC_SELECT_BANK( 2 );
++ SMC_SET_MMU_CMD( MC_FREEPKT );
++
++ /* one less packet waiting for me */
++ lp->packets_waiting--;
++
++ /* Don't change Packet Number Reg until busy bit is cleared */
++ /* Per LAN91C111 Spec, Page 50 */
++ while ( SMC_GET_MMU_CMD() & MC_BUSY );
++
++ SMC_SET_PN( saved_packet );
++ return;
++}
++
++
++/*----------------------------------------------------
++ . 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:smc_close\n", dev->name);
++
++ netif_stop_queue(dev);
++
++#ifdef CONFIG_SYSCTL
++ smc_sysctl_unregister(dev);
++#endif /* CONFIG_SYSCTL */
++
++ /* clear everything */
++ smc_shutdown( dev->base_addr );
++
++ /* Update the statistics here. */
++ 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:smc_query_statistics\n", dev->name);
++
++ return &lp->stats;
++}
++
++/*-----------------------------------------------------------
++ . smc_set_multicast_list
++ .
++ . 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)
++{
++ unsigned long ioaddr = dev->base_addr;
++
++ PRINTK2("%s:smc_set_multicast_list\n", dev->name);
++
++ SMC_SELECT_BANK(0);
++ if ( dev->flags & IFF_PROMISC ) {
++ PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name);
++ SMC_SET_RCR( SMC_GET_RCR() | RCR_PRMS );
++ }
++
++/* 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) {
++ SMC_SET_RCR( SMC_GET_RCR() | RCR_ALMUL );
++ PRINTK2("%s:smc_set_multicast_list: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 */
++ SMC_SET_RCR( SMC_GET_RCR() & ~(RCR_PRMS | RCR_ALMUL) );
++ /* 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:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n",
++ dev->name);
++ SMC_SET_RCR( SMC_GET_RCR() & ~(RCR_PRMS | RCR_ALMUL) );
++
++ /*
++ since I'm disabling all multicast entirely, I need to
++ clear the multicast list
++ */
++ SMC_SELECT_BANK( 3 );
++ SMC_CLEAR_MCAST();
++ }
++}
++
++/*------------------------------------------------------------
++ . Cleanup when module is removed with rmmod
++ .-------------------------------------------------------------*/
++static void __exit smc_cleanup(void)
++{
++ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
++ unregister_netdev(global_dev);
++
++ 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);
++
++
++#ifdef CONFIG_SYSCTL
++/*------------------------------------------------------------
++ . Modify a bit in the LAN91C111 register set
++ .-------------------------------------------------------------*/
++static word smc_modify_regbit(int bank, unsigned long ioaddr, int reg,
++ unsigned int bit, int val)
++{
++ word regval;
++
++ SMC_SELECT_BANK( bank );
++
++ regval = SMC_inw( ioaddr+reg );
++ if (val)
++ regval |= bit;
++ else
++ regval &= ~bit;
++
++ SMC_outw( regval, ioaddr );
++ return(regval);
++}
++
++
++/*------------------------------------------------------------
++ . Retrieve a bit in the LAN91C111 register set
++ .-------------------------------------------------------------*/
++static int smc_get_regbit(int bank, unsigned long ioaddr,
++ int reg, unsigned int bit)
++{
++ SMC_SELECT_BANK( bank );
++ if ( SMC_inw( ioaddr+reg ) & bit)
++ return(1);
++ else
++ return(0);
++}
++
++
++/*------------------------------------------------------------
++ . Modify a LAN91C111 register (word access only)
++ .-------------------------------------------------------------*/
++static void smc_modify_reg(int bank, unsigned long ioaddr,
++ int reg, word val)
++{
++ SMC_SELECT_BANK( bank );
++ SMC_outw( val, ioaddr+reg );
++}
++
++
++/*------------------------------------------------------------
++ . Retrieve a LAN91C111 register (word access only)
++ .-------------------------------------------------------------*/
++static int smc_get_reg(int bank, unsigned long ioaddr,
++ int reg)
++{
++ SMC_SELECT_BANK( bank );
++ return(SMC_inw( ioaddr+reg ));
++}
++
++
++static const char smc_info_string[] =
++"\n"
++"info Provides this information blurb\n"
++"swver Prints the software version information of this driver\n"
++"autoneg Auto-negotiate Mode = 1\n"
++"rspeed Requested Speed, 100=100Mbps, 10=10Mpbs\n"
++"rfduplx Requested Full Duplex Operation\n"
++"aspeed Actual Speed, 100=100Mbps, 10=10Mpbs\n"
++"afduplx Actual Full Duplex Operation\n"
++"lnkfail PHY Link Failure when 1\n"
++"miiop External MII when 1, Internal PHY when 0\n"
++"swfdup Switched Full Duplex Mode (allowed only in MII operation)\n"
++"ephloop EPH Block Loopback\n"
++"forcol Force a collision\n"
++"filtcar Filter leading edge of carrier sense for 12 bit times\n"
++"freemem Free buffer memory in bytes\n"
++"totmem Total buffer memory in bytes\n"
++"leda Output of LED-A (green)\n"
++"ledb Output of LED-B (yellow)\n"
++"chiprev Revision ID of the LAN91C111 chip\n"
++"";
++
++/*------------------------------------------------------------
++ . Sysctl handler for all integer parameters
++ .-------------------------------------------------------------*/
++static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
++ void *buffer, size_t *lenp)
++{
++ struct net_device *dev = (struct net_device*)ctl->extra1;
++ struct smc_local *lp = (struct smc_local *)ctl->extra2;
++ unsigned long ioaddr = dev->base_addr;
++ int *valp = ctl->data;
++ int val;
++ int ret;
++
++ // Update parameters from the real registers
++ switch (ctl->ctl_name)
++ {
++ case CTL_SMC_FORCOL:
++ *valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL);
++ break;
++
++ case CTL_SMC_FREEMEM:
++ *valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 )
++ * LAN91C111_MEMORY_MULTIPLIER;
++ break;
++
++
++ case CTL_SMC_TOTMEM:
++ *valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff )
++ * LAN91C111_MEMORY_MULTIPLIER;
++ break;
++
++ case CTL_SMC_CHIPREV:
++ *valp = smc_get_reg(3, ioaddr, REV_REG);
++ break;
++
++ case CTL_SMC_AFDUPLX:
++ *valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0;
++ break;
++
++ case CTL_SMC_ASPEED:
++ *valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10;
++ break;
++
++ case CTL_SMC_LNKFAIL:
++ *valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0;
++ break;
++
++ case CTL_SMC_LEDA:
++ *valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007;
++ break;
++
++ case CTL_SMC_LEDB:
++ *valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007;
++ break;
++
++ case CTL_SMC_MIIOP:
++ *valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY);
++ break;
++
++#if SMC_DEBUG > 1
++ case CTL_SMC_REG_BSR: // Bank Select
++ *valp = smc_get_reg(0, ioaddr, BSR_REG);
++ break;
++
++ case CTL_SMC_REG_TCR: // Transmit Control
++ *valp = smc_get_reg(0, ioaddr, TCR_REG);
++ break;
++
++ case CTL_SMC_REG_ESR: // EPH Status
++ *valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG);
++ break;
++
++ case CTL_SMC_REG_RCR: // Receive Control
++ *valp = smc_get_reg(0, ioaddr, RCR_REG);
++ break;
++
++ case CTL_SMC_REG_CTRR: // Counter
++ *valp = smc_get_reg(0, ioaddr, COUNTER_REG);
++ break;
++
++ case CTL_SMC_REG_MIR: // Memory Information
++ *valp = smc_get_reg(0, ioaddr, MIR_REG);
++ break;
++
++ case CTL_SMC_REG_RPCR: // Receive/Phy Control
++ *valp = smc_get_reg(0, ioaddr, RPC_REG);
++ break;
++
++ case CTL_SMC_REG_CFGR: // Configuration
++ *valp = smc_get_reg(1, ioaddr, CONFIG_REG);
++ break;
++
++ case CTL_SMC_REG_BAR: // Base Address
++ *valp = smc_get_reg(1, ioaddr, BASE_REG);
++ break;
++
++ case CTL_SMC_REG_IAR0: // Individual Address
++ *valp = smc_get_reg(1, ioaddr, ADDR0_REG);
++ break;
++
++ case CTL_SMC_REG_IAR1: // Individual Address
++ *valp = smc_get_reg(1, ioaddr, ADDR1_REG);
++ break;
++
++ case CTL_SMC_REG_IAR2: // Individual Address
++ *valp = smc_get_reg(1, ioaddr, ADDR2_REG);
++ break;
++
++ case CTL_SMC_REG_GPR: // General Purpose
++ *valp = smc_get_reg(1, ioaddr, GP_REG);
++ break;
++
++ case CTL_SMC_REG_CTLR: // Control
++ *valp = smc_get_reg(1, ioaddr, CTL_REG);
++ break;
++
++ case CTL_SMC_REG_MCR: // MMU Command
++ *valp = smc_get_reg(2, ioaddr, MMU_CMD_REG);
++ break;
++
++ case CTL_SMC_REG_PNR: // Packet Number
++ *valp = smc_get_reg(2, ioaddr, PN_REG);
++ break;
++
++ case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports
++ *valp = smc_get_reg(2, ioaddr, RXFIFO_REG);
++ break;
++
++ case CTL_SMC_REG_PTR: // Pointer
++ *valp = smc_get_reg(2, ioaddr, PTR_REG);
++ break;
++
++ case CTL_SMC_REG_DR: // Data
++ *valp = smc_get_reg(2, ioaddr, DATA_REG);
++ break;
++
++ case CTL_SMC_REG_ISR: // Interrupt Status/Mask
++ *valp = smc_get_reg(2, ioaddr, INT_REG);
++ break;
++
++ case CTL_SMC_REG_MTR1: // Multicast Table Entry 1
++ *valp = smc_get_reg(3, ioaddr, MCAST_REG1);
++ break;
++
++ case CTL_SMC_REG_MTR2: // Multicast Table Entry 2
++ *valp = smc_get_reg(3, ioaddr, MCAST_REG2);
++ break;
++
++ case CTL_SMC_REG_MTR3: // Multicast Table Entry 3
++ *valp = smc_get_reg(3, ioaddr, MCAST_REG3);
++ break;
++
++ case CTL_SMC_REG_MTR4: // Multicast Table Entry 4
++ *valp = smc_get_reg(3, ioaddr, MCAST_REG4);
++ break;
++
++ case CTL_SMC_REG_MIIR: // Management Interface
++ *valp = smc_get_reg(3, ioaddr, MII_REG);
++ break;
++
++ case CTL_SMC_REG_REVR: // Revision
++ *valp = smc_get_reg(3, ioaddr, REV_REG);
++ break;
++
++ case CTL_SMC_REG_ERCVR: // Early RCV
++ *valp = smc_get_reg(3, ioaddr, ERCV_REG);
++ break;
++
++ case CTL_SMC_REG_EXTR: // External
++ *valp = smc_get_reg(7, ioaddr, EXT_REG);
++ break;
++
++ case CTL_SMC_PHY_CTRL:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_CNTL_REG);
++ break;
++
++ case CTL_SMC_PHY_STAT:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_STAT_REG);
++ break;
++
++ case CTL_SMC_PHY_ID1:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_ID1_REG);
++ break;
++
++ case CTL_SMC_PHY_ID2:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_ID2_REG);
++ break;
++
++ case CTL_SMC_PHY_ADC:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_AD_REG);
++ break;
++
++ case CTL_SMC_PHY_REMC:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_RMT_REG);
++ break;
++
++ case CTL_SMC_PHY_CFG1:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_CFG1_REG);
++ break;
++
++ case CTL_SMC_PHY_CFG2:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_CFG2_REG);
++ break;
++
++ case CTL_SMC_PHY_INT:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_INT_REG);
++ break;
++
++ case CTL_SMC_PHY_MASK:
++ *valp = smc_read_phy_register(ioaddr, lp->phyaddr,
++ PHY_MASK_REG);
++ break;
++
++#endif // SMC_DEBUG > 1
++
++ default:
++ // Just ignore unsupported parameters
++ break;
++ }
++
++ // Save old state
++ val = *valp;
++
++ // Perform the generic integer operation
++ if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0)
++ return(ret);
++
++ // Write changes out to the registers
++ if (write && *valp != val) {
++
++ val = *valp;
++ switch (ctl->ctl_name) {
++
++ case CTL_SMC_SWFDUP:
++ if (val)
++ lp->tcr_cur_mode |= TCR_SWFDUP;
++ else
++ lp->tcr_cur_mode &= ~TCR_SWFDUP;
++
++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val);
++ break;
++
++ case CTL_SMC_EPHLOOP:
++ if (val)
++ lp->tcr_cur_mode |= TCR_EPH_LOOP;
++ else
++ lp->tcr_cur_mode &= ~TCR_EPH_LOOP;
++
++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val);
++ break;
++
++ case CTL_SMC_FORCOL:
++ if (val)
++ lp->tcr_cur_mode |= TCR_FORCOL;
++ else
++ lp->tcr_cur_mode &= ~TCR_FORCOL;
++
++ // Update the EPH block
++ smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val);
++ break;
++
++ case CTL_SMC_FILTCAR:
++ if (val)
++ lp->rcr_cur_mode |= RCR_FILT_CAR;
++ else
++ lp->rcr_cur_mode &= ~RCR_FILT_CAR;
++
++ // Update the EPH block
++ smc_modify_regbit(0, ioaddr, RCR_REG, RCR_FILT_CAR, val);
++ break;
++
++ case CTL_SMC_RFDUPLX:
++ // Disallow changes if in auto-negotiation mode
++ if (lp->ctl_autoneg)
++ break;
++
++ if (val)
++ lp->rpc_cur_mode |= RPC_DPLX;
++ else
++ lp->rpc_cur_mode &= ~RPC_DPLX;
++
++ // Reconfigure the PHY
++ smc_phy_configure(dev);
++
++ break;
++
++ case CTL_SMC_RSPEED:
++ // Disallow changes if in auto-negotiation mode
++ if (lp->ctl_autoneg)
++ break;
++
++ if (val > 10)
++ lp->rpc_cur_mode |= RPC_SPEED;
++ else
++ lp->rpc_cur_mode &= ~RPC_SPEED;
++
++ // Reconfigure the PHY
++ smc_phy_configure(dev);
++
++ break;
++
++ case CTL_SMC_AUTONEG:
++ if (val)
++ lp->rpc_cur_mode |= RPC_ANEG;
++ else
++ lp->rpc_cur_mode &= ~RPC_ANEG;
++
++ // Reconfigure the PHY
++ smc_phy_configure(dev);
++
++ break;
++
++ case CTL_SMC_LEDA:
++ val &= 0x07; // Restrict to 3 ls bits
++ lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXA_SHFT);
++ lp->rpc_cur_mode |= (word)(val<<RPC_LSXA_SHFT);
++
++ // Update the Internal PHY block
++ smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
++ break;
++
++ case CTL_SMC_LEDB:
++ val &= 0x07; // Restrict to 3 ls bits
++ lp->rpc_cur_mode &= ~(word)(0x07<<RPC_LSXB_SHFT);
++ lp->rpc_cur_mode |= (word)(val<<RPC_LSXB_SHFT);
++
++ // Update the Internal PHY block
++ smc_modify_reg(0, ioaddr, RPC_REG, lp->rpc_cur_mode);
++ break;
++
++ case CTL_SMC_MIIOP:
++ // Update the Internal PHY block
++ smc_modify_regbit(1, ioaddr, CONFIG_REG,
++ CONFIG_EXT_PHY, val);
++ break;
++
++#if SMC_DEBUG > 1
++ case CTL_SMC_REG_BSR: // Bank Select
++ smc_modify_reg(0, ioaddr, BSR_REG, val);
++ break;
++
++ case CTL_SMC_REG_TCR: // Transmit Control
++ smc_modify_reg(0, ioaddr, TCR_REG, val);
++ break;
++
++ case CTL_SMC_REG_ESR: // EPH Status
++ smc_modify_reg(0, ioaddr, EPH_STATUS_REG, val);
++ break;
++
++ case CTL_SMC_REG_RCR: // Receive Control
++ smc_modify_reg(0, ioaddr, RCR_REG, val);
++ break;
++
++ case CTL_SMC_REG_CTRR: // Counter
++ smc_modify_reg(0, ioaddr, COUNTER_REG, val);
++ break;
++
++ case CTL_SMC_REG_MIR: // Memory Information
++ smc_modify_reg(0, ioaddr, MIR_REG, val);
++ break;
++
++ case CTL_SMC_REG_RPCR: // Receive/Phy Control
++ smc_modify_reg(0, ioaddr, RPC_REG, val);
++ break;
++
++ case CTL_SMC_REG_CFGR: // Configuration
++ smc_modify_reg(1, ioaddr, CONFIG_REG, val);
++ break;
++
++ case CTL_SMC_REG_BAR: // Base Address
++ smc_modify_reg(1, ioaddr, BASE_REG, val);
++ break;
++
++ case CTL_SMC_REG_IAR0: // Individual Address
++ smc_modify_reg(1, ioaddr, ADDR0_REG, val);
++ break;
++
++ case CTL_SMC_REG_IAR1: // Individual Address
++ smc_modify_reg(1, ioaddr, ADDR1_REG, val);
++ break;
++
++ case CTL_SMC_REG_IAR2: // Individual Address
++ smc_modify_reg(1, ioaddr, ADDR2_REG, val);
++ break;
++
++ case CTL_SMC_REG_GPR: // General Purpose
++ smc_modify_reg(1, ioaddr, GP_REG, val);
++ break;
++
++ case CTL_SMC_REG_CTLR: // Control
++ smc_modify_reg(1, ioaddr, CTL_REG, val);
++ break;
++
++ case CTL_SMC_REG_MCR: // MMU Command
++ smc_modify_reg(2, ioaddr, MMU_CMD_REG, val);
++ break;
++
++ case CTL_SMC_REG_PNR: // Packet Number
++ smc_modify_reg(2, ioaddr, PN_REG, val);
++ break;
++
++ case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports
++ smc_modify_reg(2, ioaddr, RXFIFO_REG, val);
++ break;
++
++ case CTL_SMC_REG_PTR: // Pointer
++ smc_modify_reg(2, ioaddr, PTR_REG, val);
++ break;
++
++ case CTL_SMC_REG_DR: // Data
++ smc_modify_reg(2, ioaddr, DATA_REG, val);
++ break;
++
++ case CTL_SMC_REG_ISR: // Interrupt Status/Mask
++ smc_modify_reg(2, ioaddr, INT_REG, val);
++ break;
++
++ case CTL_SMC_REG_MTR1: // Multicast Table Entry 1
++ smc_modify_reg(3, ioaddr, MCAST_REG1, val);
++ break;
++
++ case CTL_SMC_REG_MTR2: // Multicast Table Entry 2
++ smc_modify_reg(3, ioaddr, MCAST_REG2, val);
++ break;
++
++ case CTL_SMC_REG_MTR3: // Multicast Table Entry 3
++ smc_modify_reg(3, ioaddr, MCAST_REG3, val);
++ break;
++
++ case CTL_SMC_REG_MTR4: // Multicast Table Entry 4
++ smc_modify_reg(3, ioaddr, MCAST_REG4, val);
++ break;
++
++ case CTL_SMC_REG_MIIR: // Management Interface
++ smc_modify_reg(3, ioaddr, MII_REG, val);
++ break;
++
++ case CTL_SMC_REG_REVR: // Revision
++ smc_modify_reg(3, ioaddr, REV_REG, val);
++ break;
++
++ case CTL_SMC_REG_ERCVR: // Early RCV
++ smc_modify_reg(3, ioaddr, ERCV_REG, val);
++ break;
++
++ case CTL_SMC_REG_EXTR: // External
++ smc_modify_reg(7, ioaddr, EXT_REG, val);
++ break;
++
++ case CTL_SMC_PHY_CTRL:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_CNTL_REG, val);
++ break;
++
++ case CTL_SMC_PHY_STAT:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_STAT_REG, val);
++ break;
++
++ case CTL_SMC_PHY_ID1:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_ID1_REG, val);
++ break;
++
++ case CTL_SMC_PHY_ID2:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_ID2_REG, val);
++ break;
++
++ case CTL_SMC_PHY_ADC:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_AD_REG, val);
++ break;
++
++ case CTL_SMC_PHY_REMC:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_RMT_REG, val);
++ break;
++
++ case CTL_SMC_PHY_CFG1:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_CFG1_REG, val);
++ break;
++
++ case CTL_SMC_PHY_CFG2:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_CFG2_REG, val);
++ break;
++
++ case CTL_SMC_PHY_INT:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_INT_REG, val);
++ break;
++
++ case CTL_SMC_PHY_MASK:
++ smc_write_phy_register(ioaddr, lp->phyaddr,
++ PHY_MASK_REG, val);
++ break;
++
++#endif // SMC_DEBUG > 1
++
++ default:
++ // Just ignore unsupported parameters
++ break;
++ } // end switch
++
++ } // end if
++
++ return ret;
++}
++
++
++#ifdef MODULE
++/*
++ * This is called as the fill_inode function when an inode
++ * is going into (fill = 1) or out of service (fill = 0).
++ * We use it here to manage the module use counts.
++ *
++ * Note: only the top-level directory needs to do this; if
++ * a lower level is referenced, the parent will be as well.
++ */
++static void smc_procfs_modcount(struct inode *inode, int fill)
++{
++ if (fill)
++ MOD_INC_USE_COUNT;
++ else
++ MOD_DEC_USE_COUNT;
++}
++#endif // MODULE
++
++/*------------------------------------------------------------
++ . Sysctl registration function for all parameters (files)
++ .-------------------------------------------------------------*/
++static void smc_sysctl_register(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++ static int ctl_name = CTL_SMC;
++ ctl_table* ct;
++ int i;
++
++ // Make sure the ctl_tables start out as all zeros
++ memset(lp->root_table, 0, sizeof lp->root_table);
++ memset(lp->eth_table, 0, sizeof lp->eth_table);
++ memset(lp->param_table, 0, sizeof lp->param_table);
++
++ // Initialize the root table
++ ct = lp->root_table;
++ ct->ctl_name = CTL_DEV;
++ ct->procname = "dev";
++ ct->maxlen = 0;
++ ct->mode = 0555;
++ ct->child = lp->eth_table;
++ // remaining fields are zero
++
++ // Initialize the ethX table (this device's table)
++ ct = lp->eth_table;
++ ct->ctl_name = ctl_name++; // Must be unique
++ ct->procname = dev->name;
++ ct->maxlen = 0;
++ ct->mode = 0555;
++ ct->child = lp->param_table;
++ // remaining fields are zero
++
++ // Initialize the parameter (files) table
++ // Make sure the last entry remains null
++ ct = lp->param_table;
++ for (i = 0; i < (CTL_SMC_LAST_ENTRY-1); ++i) {
++ // Initialize fields common to all table entries
++ ct[i].proc_handler = smc_sysctl_handler;
++ ct[i].extra1 = (void*)dev; // Save our device pointer
++ ct[i].extra2 = (void*)lp; // Save our smc_local data pointer
++ }
++
++ // INFO - this is our only string parameter
++ i = 0;
++ ct[i].proc_handler = proc_dostring; // use default handler
++ ct[i].ctl_name = CTL_SMC_INFO;
++ ct[i].procname = "info";
++ ct[i].data = (void*)smc_info_string;
++ ct[i].maxlen = sizeof smc_info_string;
++ ct[i].mode = 0444; // Read only
++
++ // SWVER
++ ++i;
++ ct[i].proc_handler = proc_dostring; // use default handler
++ ct[i].ctl_name = CTL_SMC_SWVER;
++ ct[i].procname = "swver";
++ ct[i].data = (void*)version;
++ ct[i].maxlen = sizeof version;
++ ct[i].mode = 0444; // Read only
++
++ // SWFDUP
++ ++i;
++ ct[i].ctl_name = CTL_SMC_SWFDUP;
++ ct[i].procname = "swfdup";
++ ct[i].data = (void*)&(lp->ctl_swfdup);
++ ct[i].maxlen = sizeof lp->ctl_swfdup;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // EPHLOOP
++ ++i;
++ ct[i].ctl_name = CTL_SMC_EPHLOOP;
++ ct[i].procname = "ephloop";
++ ct[i].data = (void*)&(lp->ctl_ephloop);
++ ct[i].maxlen = sizeof lp->ctl_ephloop;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // MIIOP
++ ++i;
++ ct[i].ctl_name = CTL_SMC_MIIOP;
++ ct[i].procname = "miiop";
++ ct[i].data = (void*)&(lp->ctl_miiop);
++ ct[i].maxlen = sizeof lp->ctl_miiop;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // AUTONEG
++ ++i;
++ ct[i].ctl_name = CTL_SMC_AUTONEG;
++ ct[i].procname = "autoneg";
++ ct[i].data = (void*)&(lp->ctl_autoneg);
++ ct[i].maxlen = sizeof lp->ctl_autoneg;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // RFDUPLX
++ ++i;
++ ct[i].ctl_name = CTL_SMC_RFDUPLX;
++ ct[i].procname = "rfduplx";
++ ct[i].data = (void*)&(lp->ctl_rfduplx);
++ ct[i].maxlen = sizeof lp->ctl_rfduplx;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // RSPEED
++ ++i;
++ ct[i].ctl_name = CTL_SMC_RSPEED;
++ ct[i].procname = "rspeed";
++ ct[i].data = (void*)&(lp->ctl_rspeed);
++ ct[i].maxlen = sizeof lp->ctl_rspeed;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // AFDUPLX
++ ++i;
++ ct[i].ctl_name = CTL_SMC_AFDUPLX;
++ ct[i].procname = "afduplx";
++ ct[i].data = (void*)&(lp->ctl_afduplx);
++ ct[i].maxlen = sizeof lp->ctl_afduplx;
++ ct[i].mode = 0444; // Read only
++
++ // ASPEED
++ ++i;
++ ct[i].ctl_name = CTL_SMC_ASPEED;
++ ct[i].procname = "aspeed";
++ ct[i].data = (void*)&(lp->ctl_aspeed);
++ ct[i].maxlen = sizeof lp->ctl_aspeed;
++ ct[i].mode = 0444; // Read only
++
++ // LNKFAIL
++ ++i;
++ ct[i].ctl_name = CTL_SMC_LNKFAIL;
++ ct[i].procname = "lnkfail";
++ ct[i].data = (void*)&(lp->ctl_lnkfail);
++ ct[i].maxlen = sizeof lp->ctl_lnkfail;
++ ct[i].mode = 0444; // Read only
++
++ // FORCOL
++ ++i;
++ ct[i].ctl_name = CTL_SMC_FORCOL;
++ ct[i].procname = "forcol";
++ ct[i].data = (void*)&(lp->ctl_forcol);
++ ct[i].maxlen = sizeof lp->ctl_forcol;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // FILTCAR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_FILTCAR;
++ ct[i].procname = "filtcar";
++ ct[i].data = (void*)&(lp->ctl_filtcar);
++ ct[i].maxlen = sizeof lp->ctl_filtcar;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // FREEMEM
++ ++i;
++ ct[i].ctl_name = CTL_SMC_FREEMEM;
++ ct[i].procname = "freemem";
++ ct[i].data = (void*)&(lp->ctl_freemem);
++ ct[i].maxlen = sizeof lp->ctl_freemem;
++ ct[i].mode = 0444; // Read only
++
++ // TOTMEM
++ ++i;
++ ct[i].ctl_name = CTL_SMC_TOTMEM;
++ ct[i].procname = "totmem";
++ ct[i].data = (void*)&(lp->ctl_totmem);
++ ct[i].maxlen = sizeof lp->ctl_totmem;
++ ct[i].mode = 0444; // Read only
++
++ // LEDA
++ ++i;
++ ct[i].ctl_name = CTL_SMC_LEDA;
++ ct[i].procname = "leda";
++ ct[i].data = (void*)&(lp->ctl_leda);
++ ct[i].maxlen = sizeof lp->ctl_leda;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // LEDB
++ ++i;
++ ct[i].ctl_name = CTL_SMC_LEDB;
++ ct[i].procname = "ledb";
++ ct[i].data = (void*)&(lp->ctl_ledb);
++ ct[i].maxlen = sizeof lp->ctl_ledb;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // CHIPREV
++ ++i;
++ ct[i].ctl_name = CTL_SMC_CHIPREV;
++ ct[i].procname = "chiprev";
++ ct[i].data = (void*)&(lp->ctl_chiprev);
++ ct[i].maxlen = sizeof lp->ctl_chiprev;
++ ct[i].mode = 0444; // Read only
++
++#if SMC_DEBUG > 1
++ // REG_BSR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_BSR;
++ ct[i].procname = "reg_bsr";
++ ct[i].data = (void*)&(lp->ctl_reg_bsr);
++ ct[i].maxlen = sizeof lp->ctl_reg_bsr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_TCR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_TCR;
++ ct[i].procname = "reg_tcr";
++ ct[i].data = (void*)&(lp->ctl_reg_tcr);
++ ct[i].maxlen = sizeof lp->ctl_reg_tcr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_ESR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_ESR;
++ ct[i].procname = "reg_esr";
++ ct[i].data = (void*)&(lp->ctl_reg_esr);
++ ct[i].maxlen = sizeof lp->ctl_reg_esr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_RCR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_RCR;
++ ct[i].procname = "reg_rcr";
++ ct[i].data = (void*)&(lp->ctl_reg_rcr);
++ ct[i].maxlen = sizeof lp->ctl_reg_rcr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_CTRR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_CTRR;
++ ct[i].procname = "reg_ctrr";
++ ct[i].data = (void*)&(lp->ctl_reg_ctrr);
++ ct[i].maxlen = sizeof lp->ctl_reg_ctrr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MIR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MIR;
++ ct[i].procname = "reg_mir";
++ ct[i].data = (void*)&(lp->ctl_reg_mir);
++ ct[i].maxlen = sizeof lp->ctl_reg_mir;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_RPCR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_RPCR;
++ ct[i].procname = "reg_rpcr";
++ ct[i].data = (void*)&(lp->ctl_reg_rpcr);
++ ct[i].maxlen = sizeof lp->ctl_reg_rpcr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_CFGR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_CFGR;
++ ct[i].procname = "reg_cfgr";
++ ct[i].data = (void*)&(lp->ctl_reg_cfgr);
++ ct[i].maxlen = sizeof lp->ctl_reg_cfgr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_BAR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_BAR;
++ ct[i].procname = "reg_bar";
++ ct[i].data = (void*)&(lp->ctl_reg_bar);
++ ct[i].maxlen = sizeof lp->ctl_reg_bar;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_IAR0
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_IAR0;
++ ct[i].procname = "reg_iar0";
++ ct[i].data = (void*)&(lp->ctl_reg_iar0);
++ ct[i].maxlen = sizeof lp->ctl_reg_iar0;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_IAR1
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_IAR1;
++ ct[i].procname = "reg_iar1";
++ ct[i].data = (void*)&(lp->ctl_reg_iar1);
++ ct[i].maxlen = sizeof lp->ctl_reg_iar1;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_IAR2
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_IAR2;
++ ct[i].procname = "reg_iar2";
++ ct[i].data = (void*)&(lp->ctl_reg_iar2);
++ ct[i].maxlen = sizeof lp->ctl_reg_iar2;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_GPR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_GPR;
++ ct[i].procname = "reg_gpr";
++ ct[i].data = (void*)&(lp->ctl_reg_gpr);
++ ct[i].maxlen = sizeof lp->ctl_reg_gpr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_CTLR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_CTLR;
++ ct[i].procname = "reg_ctlr";
++ ct[i].data = (void*)&(lp->ctl_reg_ctlr);
++ ct[i].maxlen = sizeof lp->ctl_reg_ctlr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MCR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MCR;
++ ct[i].procname = "reg_mcr";
++ ct[i].data = (void*)&(lp->ctl_reg_mcr);
++ ct[i].maxlen = sizeof lp->ctl_reg_mcr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_PNR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_PNR;
++ ct[i].procname = "reg_pnr";
++ ct[i].data = (void*)&(lp->ctl_reg_pnr);
++ ct[i].maxlen = sizeof lp->ctl_reg_pnr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_FPR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_FPR;
++ ct[i].procname = "reg_fpr";
++ ct[i].data = (void*)&(lp->ctl_reg_fpr);
++ ct[i].maxlen = sizeof lp->ctl_reg_fpr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_PTR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_PTR;
++ ct[i].procname = "reg_ptr";
++ ct[i].data = (void*)&(lp->ctl_reg_ptr);
++ ct[i].maxlen = sizeof lp->ctl_reg_ptr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_DR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_DR;
++ ct[i].procname = "reg_dr";
++ ct[i].data = (void*)&(lp->ctl_reg_dr);
++ ct[i].maxlen = sizeof lp->ctl_reg_dr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_ISR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_ISR;
++ ct[i].procname = "reg_isr";
++ ct[i].data = (void*)&(lp->ctl_reg_isr);
++ ct[i].maxlen = sizeof lp->ctl_reg_isr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MTR1
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MTR1;
++ ct[i].procname = "reg_mtr1";
++ ct[i].data = (void*)&(lp->ctl_reg_mtr1);
++ ct[i].maxlen = sizeof lp->ctl_reg_mtr1;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MTR2
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MTR2;
++ ct[i].procname = "reg_mtr2";
++ ct[i].data = (void*)&(lp->ctl_reg_mtr2);
++ ct[i].maxlen = sizeof lp->ctl_reg_mtr2;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MTR3
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MTR3;
++ ct[i].procname = "reg_mtr3";
++ ct[i].data = (void*)&(lp->ctl_reg_mtr3);
++ ct[i].maxlen = sizeof lp->ctl_reg_mtr3;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MTR4
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MTR4;
++ ct[i].procname = "reg_mtr4";
++ ct[i].data = (void*)&(lp->ctl_reg_mtr4);
++ ct[i].maxlen = sizeof lp->ctl_reg_mtr4;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_MIIR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_MIIR;
++ ct[i].procname = "reg_miir";
++ ct[i].data = (void*)&(lp->ctl_reg_miir);
++ ct[i].maxlen = sizeof lp->ctl_reg_miir;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_REVR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_REVR;
++ ct[i].procname = "reg_revr";
++ ct[i].data = (void*)&(lp->ctl_reg_revr);
++ ct[i].maxlen = sizeof lp->ctl_reg_revr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_ERCVR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_ERCVR;
++ ct[i].procname = "reg_ercvr";
++ ct[i].data = (void*)&(lp->ctl_reg_ercvr);
++ ct[i].maxlen = sizeof lp->ctl_reg_ercvr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // REG_EXTR
++ ++i;
++ ct[i].ctl_name = CTL_SMC_REG_EXTR;
++ ct[i].procname = "reg_extr";
++ ct[i].data = (void*)&(lp->ctl_reg_extr);
++ ct[i].maxlen = sizeof lp->ctl_reg_extr;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Control
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_CTRL;
++ ct[i].procname = "phy_ctrl";
++ ct[i].data = (void*)&(lp->ctl_phy_ctrl);
++ ct[i].maxlen = sizeof lp->ctl_phy_ctrl;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Status
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_STAT;
++ ct[i].procname = "phy_stat";
++ ct[i].data = (void*)&(lp->ctl_phy_stat);
++ ct[i].maxlen = sizeof lp->ctl_phy_stat;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY ID1
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_ID1;
++ ct[i].procname = "phy_id1";
++ ct[i].data = (void*)&(lp->ctl_phy_id1);
++ ct[i].maxlen = sizeof lp->ctl_phy_id1;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY ID2
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_ID2;
++ ct[i].procname = "phy_id2";
++ ct[i].data = (void*)&(lp->ctl_phy_id2);
++ ct[i].maxlen = sizeof lp->ctl_phy_id2;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Advertise Capabilities
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_ADC;
++ ct[i].procname = "phy_adc";
++ ct[i].data = (void*)&(lp->ctl_phy_adc);
++ ct[i].maxlen = sizeof lp->ctl_phy_adc;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Remote Capabilities
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_REMC;
++ ct[i].procname = "phy_remc";
++ ct[i].data = (void*)&(lp->ctl_phy_remc);
++ ct[i].maxlen = sizeof lp->ctl_phy_remc;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Configuration 1
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_CFG1;
++ ct[i].procname = "phy_cfg1";
++ ct[i].data = (void*)&(lp->ctl_phy_cfg1);
++ ct[i].maxlen = sizeof lp->ctl_phy_cfg1;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Configuration 2
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_CFG2;
++ ct[i].procname = "phy_cfg2";
++ ct[i].data = (void*)&(lp->ctl_phy_cfg2);
++ ct[i].maxlen = sizeof lp->ctl_phy_cfg2;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Interrupt/Status Output
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_INT;
++ ct[i].procname = "phy_int";
++ ct[i].data = (void*)&(lp->ctl_phy_int);
++ ct[i].maxlen = sizeof lp->ctl_phy_int;
++ ct[i].mode = 0644; // Read by all, write by root
++
++ // PHY Interrupt/Status Mask
++ ++i;
++ ct[i].ctl_name = CTL_SMC_PHY_MASK;
++ ct[i].procname = "phy_mask";
++ ct[i].data = (void*)&(lp->ctl_phy_mask);
++ ct[i].maxlen = sizeof lp->ctl_phy_mask;
++ ct[i].mode = 0644; // Read by all, write by root
++
++#endif // SMC_DEBUG > 1
++
++ // Register /proc/sys/dev/ethX
++ lp->sysctl_header = register_sysctl_table(lp->root_table, 1);
++
++#ifdef MODULE
++ // Register our modcount function which adjusts the module count
++ lp->root_table->child->de->fill_inode = smc_procfs_modcount;
++#endif // MODULE
++
++}
++
++
++/*------------------------------------------------------------
++ . Sysctl unregistration when driver is closed
++ .-------------------------------------------------------------*/
++static void smc_sysctl_unregister(struct net_device *dev)
++{
++ struct smc_local *lp = (struct smc_local *)dev->priv;
++
++ unregister_sysctl_table(lp->sysctl_header);
++}
++
++#endif /* endif CONFIG_SYSCTL */
++
++
++//---PHY CONTROL AND CONFIGURATION-----------------------------------------
++
++#if (SMC_DEBUG > 2 )
++
++/*------------------------------------------------------------
++ . Debugging function for viewing MII Management serial bitstream
++ .-------------------------------------------------------------*/
++static void smc_dump_mii_stream(byte* 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");
++}
++#endif
++
++/*------------------------------------------------------------
++ . Reads a register from the MII Management serial interface
++ .-------------------------------------------------------------*/
++static word smc_read_phy_register(unsigned long ioaddr,
++ byte phyaddr, byte phyreg)
++{
++ int oldBank;
++ int i;
++ byte mask;
++ word mii_reg;
++ byte bits[64];
++ int clk_idx = 0;
++ int input_idx;
++ word phydata;
++
++ // 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 = (byte)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 = (byte)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;
++ }
++
++#if (SMC_DEBUG > 2 )
++ printk("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
++ phyaddr, phyreg, phydata);
++ smc_dump_mii_stream(bits, sizeof bits);
++#endif
++
++ return(phydata);
++}
++
++
++/*------------------------------------------------------------
++ . Writes a register to the MII Management serial interface
++ .-------------------------------------------------------------*/
++static void smc_write_phy_register(unsigned long ioaddr,
++ byte phyaddr, byte phyreg, word phydata)
++{
++ int oldBank;
++ int i;
++ word mask;
++ word mii_reg;
++ byte 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 = (byte)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 = (byte)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 );
++
++#if (SMC_DEBUG > 2 )
++ printk("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
++ phyaddr, phyreg, phydata);
++ smc_dump_mii_stream(bits, sizeof bits);
++#endif
++}
++
++
++/*------------------------------------------------------------
++ . 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;
++ word phy_id1;
++ word phy_id2;
++ int phyaddr;
++ int found = 0;
++
++ PRINTK3("%s:smc_detect_phy()\n", dev->name);
++
++ // 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=%x, phy_id2=%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 {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1 + ms * HZ / 1000);
++ set_current_state(TASK_RUNNING);
++ }
++}
++
++/*------------------------------------------------------------
++ . 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;
++ byte phyaddr = lp->phyaddr;
++ word my_fixed_caps;
++ word cfg1;
++
++ PRINTK3("%s:smc_phy_fixed()\n", dev->name);
++
++ // 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 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;
++ byte phyaddr;
++ word my_phy_caps; // My PHY capabilities
++ word my_ad_caps; // My Advertised capabilities
++ word status;
++ int failed = 0;
++
++ 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
++ PRINTK2("%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);
++ 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);
++
++ // 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;
++ }
++
++ // 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_STAT_REG);
++ if (status & PHY_STAT_ANEG_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;
++ }
++
++ // Restart auto-negotiation if remote fault
++ if (status & PHY_STAT_REM_FLT) {
++ PRINTK2("%s:PHY remote fault detected\n", dev->name);
++
++ // Restart auto-negotiation
++ PRINTK2("%s:PHY restarting auto-negotiation\n",
++ dev->name);
++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
++ PHY_CNTL_SPEED | PHY_CNTL_DPLX);
++ }
++ }
++
++ if (timeout < 1) {
++ printk(KERN_DEBUG "%s:PHY auto-negotiate timed out\n",
++ dev->name);
++ PRINTK2("%s:PHY auto-negotiate timed out\n", dev->name);
++ failed = 1;
++ }
++
++ // Fail if we detected an auto-negotiate remote fault
++ if (status & PHY_STAT_REM_FLT) {
++ printk(KERN_DEBUG "%s:PHY remote fault detected\n", dev->name);
++ PRINTK2("%s:PHY remote fault detected\n", dev->name);
++ failed = 1;
++ }
++
++ // 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 ) {
++ PRINTK2("%s:PHY 100BaseT\n", dev->name);
++ lp->rpc_cur_mode |= RPC_SPEED;
++ } else {
++ PRINTK2("%s:PHY 10BaseT\n", dev->name);
++ lp->rpc_cur_mode &= ~RPC_SPEED;
++ }
++
++ if ( lp->lastPhy18 & PHY_INT_DPLXDET ) {
++ PRINTK2("%s:PHY Full Duplex\n", dev->name);
++ lp->rpc_cur_mode |= RPC_DPLX;
++ } else {
++ PRINTK2("%s:PHY Half Duplex\n", dev->name);
++ lp->rpc_cur_mode &= ~RPC_DPLX;
++ }
++
++ // Re-Configure the Receive/Phy Control register
++ SMC_SET_RPC( lp->rpc_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;
++ byte phyaddr = lp->phyaddr;
++ word phy18;
++
++ PRINTK2("%s: smc_phy_interrupt\n", dev->name);
++
++ 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%x\n", dev->name, phy18);
++ PRINTK2("%s: lastPhy18=0x%x\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;
++ }
++}
+diff -Narup linux-2.4.31-orig/drivers/net/smc91111.h linux-2.4.31/drivers/net/smc91111.h
+--- linux-2.4.31-orig/drivers/net/smc91111.h 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.4.31/drivers/net/smc91111.h 2005-08-08 16:03:33.000000000 -0700
+@@ -0,0 +1,712 @@
++/*------------------------------------------------------------------------
++ . smc91111.h - macros for the LAN91C111 Ethernet Driver
++ .
++ . Copyright (C) 2001 Standard Microsystems Corporation (SMSC)
++ . Developed by Simple Network Magic Corporation (SNMC)
++ . Copyright (C) 1996 by Erik Stahlman (ES)
++ .
++ . 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
++ .
++ . This file contains register information and access macros for
++ . the LAN91C111 single chip ethernet controller. It is a modified
++ . version of the smc9194.h file.
++ .
++ . 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 )
++ .
++ . History
++ . 03/16/01 Daris A Nevil Modified for use with LAN91C111 device
++ .
++ ---------------------------------------------------------------------------*/
++#ifndef _SMC91111_H_
++#define _SMC91111_H_
++
++/* I want some simple types */
++
++typedef unsigned char byte;
++typedef unsigned short word;
++typedef unsigned long int dword;
++
++
++/*
++ . Do you want to use 8 bit xfers? This should work on all chips, as the
++ . chipset is designed to accommodate them, although some hardware engineers
++ . do not connect byte enables so 8 bit xfers can not be used.
++*/
++#ifdef CONFIG_SMC91111_USE_8_BIT
++#define SMC_inb(port) inb(port)
++#define SMC_insb(port,buf,ns) insb((port),(buf),(ns))
++#define SMC_outb(val,port) outb((val),(port))
++#define SMC_outsb(port,buf,ns) outsb((port),(buf),(ns))
++#endif /* CONFIG_SMC91111_USE_8_BIT */
++
++/* Define 16 bit xfers. */
++#ifdef CONFIG_SMC91111_BYTE_SWAP
++#define SMC_inw(port) swab16(inw(port))
++#define SMC_insw(port,buf,ns) \
++ do { \
++ unsigned long __port = (port); \
++ word *__buf = (word *)(buf); \
++ int __ns = (ns); \
++ insw(__port,__buf,__ns); \
++ while (__ns > 0) { \
++ *__buf = swab16(*__buf); \
++ __buf++; \
++ __ns--; \
++ } \
++ } while (0)
++#define SMC_outw(val,port) outw(swab16(val),(port))
++#define SMC_outsw(port,buf,ns) \
++ do { \
++ unsigned long __port = (port); \
++ word *__buf = (word *)(buf); \
++ int __ns = (ns); \
++ while (__ns > 0) { \
++ /* Believe it or not, the swab isn't needed. */ \
++ outw( /* swab16 */ (*__buf++), __port); \
++ __ns--; \
++ } \
++ } while (0)
++#else /* CONFIG_SMC91111_BYTE_SWAP is not defined */
++#define SMC_inw(port) inw(port)
++#define SMC_insw(port,buf,ns) insw((port),(buf),(ns))
++#define SMC_outw(val,port) outw((val),(port))
++#define SMC_outsw(port,buf,ns) outsw((port),(buf),(ns))
++#endif /* CONFIG_SMC91111_BYTE_SWAP */
++
++/*
++ . Do you want to use 32 bit xfers? This should work on all chips, as the
++ . chipset is designed to accommodate them, although some hardware engineers
++ . do not connect all 32 data bits so 32 bit xfers can not be used.
++*/
++#ifdef CONFIG_SMC91111_USE_32_BIT
++#ifdef CONFIG_SMC91111_BYTE_SWAP
++#define SMC_inl(port) swab32(inl(port))
++#define SMC_insl(port,buf,ns) \
++ do { \
++ unsigned long __port = (port); \
++ dword *__buf = (dword *)(buf); \
++ int __ns = (ns); \
++ insl(__port,__buf,__ns); \
++ while (__ns > 0) { \
++ *__buf = swab32(*__buf); \
++ __buf++; \
++ __ns--; \
++ } \
++ } while (0)
++#define SMC_outl(val,port) outl(swab32(val),(port))
++#define SMC_outsl(port,buf,ns) \
++ do { \
++ unsigned long __port = (port); \
++ dword *__buf = (dword *)(buf); \
++ int __ns = (ns); \
++ while (__ns > 0) { \
++ /* Believe it or not, the swab isn't needed. */ \
++ outl( /* swab32 */ (*__buf++), __port); \
++ __ns--; \
++ } \
++ } while (0)
++#else /* CONFIG_SMC91111_BYTE_SWAP is not defined */
++#define SMC_inl(port) inl(port)
++#define SMC_insl(port,buf,ns) insl((port),(buf),(ns))
++#define SMC_outl(val,port) outl((val),(port))
++#define SMC_outsl(port,buf,ns) outsl((port),(buf),(ns))
++#endif /* CONFIG_SMC91111_BYTE_SWAP */
++#endif /* CONFIG_SMC91111_USE_32_BIT */
++
++
++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
++
++#define SMC_IO_EXTENT 16
++
++
++/*---------------------------------------------------------------
++ .
++ . A description of the SMSC registers is probably in order here,
++ . although for details, the SMC datasheet is invaluable.
++ .
++ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
++ . are accessed by writing a number into the BANK_SELECT register
++ . ( I also use a SMC_SELECT_BANK macro for this ).
++ .
++ . The banks are configured so that for most purposes, bank 2 is all
++ . that is needed for simple run time tasks.
++ -----------------------------------------------------------------------*/
++
++/*
++ . Bank Select Register:
++ .
++ . yyyy yyyy 0000 00xx
++ . xx = bank number
++ . yyyy yyyy = 0x33, for identification purposes.
++*/
++#define BANK_SELECT 14
++
++// Transmit Control Register
++/* BANK 0 */
++#define TCR_REG 0x0000 // transmit control register
++#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 : */
++/* QUESTION: do I want to enable padding of short packets ? */
++#define TCR_DEFAULT TCR_ENABLE
++
++
++// EPH Status Register
++/* BANK 0 */
++#define EPH_STATUS_REG 0x0002
++#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 0x0004
++#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 0x0006
++
++// Memory Information Register
++/* BANK 0 */
++#define MIR_REG 0x0008
++
++// Receive/Phy Control Register
++/* BANK 0 */
++#define RPC_REG 0x000A
++#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 0x000C is reserved */
++
++// Bank Select Register
++/* All Banks */
++#define BSR_REG 0x000E
++
++
++// Configuration Reg
++/* BANK 1 */
++#define CONFIG_REG 0x0000
++#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 0x0002
++
++
++// Individual Address Registers
++/* BANK 1 */
++#define ADDR0_REG 0x0004
++#define ADDR1_REG 0x0006
++#define ADDR2_REG 0x0008
++
++
++// General Purpose Register
++/* BANK 1 */
++#define GP_REG 0x000A
++
++
++// Control Register
++/* BANK 1 */
++#define CTL_REG 0x000C
++#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 0x0000
++#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 0x0002
++
++
++// Allocation Result Register
++/* BANK 2 */
++#define AR_REG 0x0003
++#define AR_FAILED 0x80 // Alocation Failed
++
++
++// RX FIFO Ports Register
++/* BANK 2 */
++#define RXFIFO_REG 0x0004 // Must be read as a word
++#define RXFIFO_REMPTY 0x8000 // RX FIFO Empty
++
++
++// TX FIFO Ports Register
++/* BANK 2 */
++#define TXFIFO_REG RXFIFO_REG // Must be read as a word
++#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty
++
++
++// Pointer Register
++/* BANK 2 */
++#define PTR_REG 0x0006
++#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 0x0008
++
++
++// Interrupt Status/Acknowledge Register
++/* BANK 2 */
++#define INT_REG 0x000C
++
++
++// Interrupt Mask Register
++/* BANK 2 */
++#define IM_REG 0x000D
++#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt
++#define IM_ERCV_INT 0x40 // Early Receive Interrupt
++#define IM_EPH_INT 0x20 // Set by Etheret 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 Interrrupt
++#define IM_RCV_INT 0x01 // Receive Interrupt
++
++
++// Multicast Table Registers
++/* BANK 3 */
++#define MCAST_REG1 0x0000
++#define MCAST_REG2 0x0002
++#define MCAST_REG3 0x0004
++#define MCAST_REG4 0x0006
++
++
++// Management Interface Register (MII)
++/* BANK 3 */
++#define MII_REG 0x0008
++#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 */
++#define REV_REG 0x000A /* ( hi: chip id low: rev # ) */
++
++
++// Early RCV Register
++/* BANK 3 */
++/* this is NOT on SMC9192 */
++#define ERCV_REG 0x000C
++#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 0x0000
++
++
++#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[ 15 ] = {
++ NULL, NULL, NULL,
++ /* 3 */ "SMC91C90/91C92",
++ /* 4 */ "SMC91C94",
++ /* 5 */ "SMC91C95",
++ /* 6 */ "SMC91C96",
++ /* 7 */ "SMC91C100",
++ /* 8 */ "SMC91C100FD",
++ /* 9 */ "SMC91C11xFD",
++ 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 // bug: the LAN91C111 never sets this on receive
++#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
++
++
++
++/*-------------------------------------------------------------------------
++ . I define some macros to make it easier to do somewhat common
++ . or slightly complicated, repeated tasks.
++ --------------------------------------------------------------------------*/
++
++/* select a register bank, 0 to 3 */
++
++#define SMC_SELECT_BANK(x) { SMC_outw( x, ioaddr + BANK_SELECT ); }
++#define SMC_CURRENT_BANK() SMC_inw( ioaddr + BANK_SELECT )
++
++/* this enables an interrupt in the interrupt mask register */
++#define SMC_ENABLE_INT(x) {\
++ unsigned char mask;\
++ SMC_SELECT_BANK(2);\
++ mask = SMC_GET_INT_MASK();\
++ mask |= (x);\
++ SMC_SET_INT_MASK(mask); \
++}
++
++/* this disables an interrupt from the interrupt mask register */
++
++#define SMC_DISABLE_INT(x) {\
++ unsigned char mask;\
++ SMC_SELECT_BANK(2);\
++ mask = SMC_GET_INT_MASK();\
++ mask &= ~(x);\
++ SMC_SET_INT_MASK(mask); \
++}
++
++/* Note: the following macros do *not* select the bank. */
++#if USE_8_BIT
++#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_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_INT() (SMC_inw( ioaddr + INT_REG ) & 0xFF)
++#define SMC_ACK_INT(x) SMC_outw( (SMC_GET_INT_MASK() << 8) | (x), \
++ ioaddr + INT_REG )
++#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_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_SET_COUNTER(x) SMC_outw( (x), 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_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_SET_REV(x) SMC_outw( (x), 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_RXFIFO() SMC_inw( ioaddr + RXFIFO_REG)
++#define SMC_SET_RXFIFO(x) SMC_outw( (x), ioaddr + RXFIFO_REG)
++#define SMC_GET_TCR() SMC_inw( ioaddr + TCR_REG)
++#define SMC_SET_TCR(x) SMC_outw( (x), ioaddr + TCR_REG)
++
++#define SMC_CLEAR_MCAST() {\
++ SMC_outw( 0, ioaddr + MCAST_REG1); \
++ SMC_outw( 0, ioaddr + MCAST_REG2); \
++ SMC_outw( 0, ioaddr + MCAST_REG3); \
++ SMC_outw( 0, ioaddr + MCAST_REG4); \
++}
++#define SMC_SET_MCAST(x) {\
++ int i;\
++ word w;\
++ unsigned char *mt = (x);\
++ for ( i = 0; i < 8; i += 2 ) {\
++ w = mt[i] | (mt[i + 1] << 8);\
++ SMC_outw( w, ioaddr + MCAST_REG1 + i );\
++ }\
++}
++
++
++/*----------------------------------------------------------------------
++ . Define the interrupts that I want to receive from the card
++ .
++ . I want:
++ . IM_EPH_INT, for nasty errors
++ . IM_RCV_INT, for happy received packets
++ . IM_RX_OVRN_INT, because I have to kick the receiver
++ . IM_MDINT, for PHY Register 18 Status Changes
++ --------------------------------------------------------------------------*/
++#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \
++ IM_MDINT)
++
++
++#ifdef CONFIG_SYSCTL
++/*
++ * Declarations for the sysctl interface, which allows users the ability to
++ * control the finer aspects of the LAN91C111 chip. Since the smc
++ * module currently registers its sysctl table dynamically, the sysctl path
++ * for module FOO is /proc/sys/dev/ethX/FOO
++ */
++#define CTL_SMC (CTL_BUS+1389) // arbitrary and hopefully unused
++
++enum {
++ CTL_SMC_INFO = 1, // Sysctl files information
++ CTL_SMC_SWVER, // Driver Software Version Info
++ CTL_SMC_SWFDUP, // Switched Full Duplex Mode
++ CTL_SMC_EPHLOOP, // EPH Block Internal Loopback
++ CTL_SMC_MIIOP, // MII Operation
++ CTL_SMC_AUTONEG, // Auto-negotiate Mode
++ CTL_SMC_RFDUPLX, // Request Full Duplex Mode
++ CTL_SMC_RSPEED, // Request Speed Selection
++ CTL_SMC_AFDUPLX, // Actual Full Duplex Mode
++ CTL_SMC_ASPEED, // Actual Speed Selection
++ CTL_SMC_LNKFAIL, // Link Failed
++ CTL_SMC_FORCOL, // Force a Collision
++ CTL_SMC_FILTCAR, // Filter Carrier
++ CTL_SMC_FREEMEM, // Free Buffer Memory
++ CTL_SMC_TOTMEM, // Total Buffer Memory
++ CTL_SMC_LEDA, // Output of LED-A
++ CTL_SMC_LEDB, // Output of LED-B
++ CTL_SMC_CHIPREV, // LAN91C111 Chip Revision ID
++#if SMC_DEBUG > 1
++ // Register access for debugging
++ CTL_SMC_REG_BSR, // Bank Select
++ CTL_SMC_REG_TCR, // Transmit Control
++ CTL_SMC_REG_ESR, // EPH Status
++ CTL_SMC_REG_RCR, // Receive Control
++ CTL_SMC_REG_CTRR, // Counter
++ CTL_SMC_REG_MIR, // Memory Information
++ CTL_SMC_REG_RPCR, // Receive/Phy Control
++ CTL_SMC_REG_CFGR, // Configuration
++ CTL_SMC_REG_BAR, // Base Address
++ CTL_SMC_REG_IAR0, // Individual Address 0
++ CTL_SMC_REG_IAR1, // Individual Address 1
++ CTL_SMC_REG_IAR2, // Individual Address 2
++ CTL_SMC_REG_GPR, // General Purpose
++ CTL_SMC_REG_CTLR, // Control
++ CTL_SMC_REG_MCR, // MMU Command
++ CTL_SMC_REG_PNR, // Packet Number
++ CTL_SMC_REG_FPR, // FIFO Ports
++ CTL_SMC_REG_PTR, // Pointer
++ CTL_SMC_REG_DR, // Data
++ CTL_SMC_REG_ISR, // Interrupt Status
++ CTL_SMC_REG_MTR1, // Multicast Table Entry 1
++ CTL_SMC_REG_MTR2, // Multicast Table Entry 2
++ CTL_SMC_REG_MTR3, // Multicast Table Entry 3
++ CTL_SMC_REG_MTR4, // Multicast Table Entry 4
++ CTL_SMC_REG_MIIR, // Management Interface
++ CTL_SMC_REG_REVR, // Revision
++ CTL_SMC_REG_ERCVR, // Early RCV
++ CTL_SMC_REG_EXTR, // External
++ CTL_SMC_PHY_CTRL, // PHY Control
++ CTL_SMC_PHY_STAT, // PHY Status
++ CTL_SMC_PHY_ID1, // PHY ID1
++ CTL_SMC_PHY_ID2, // PHY ID2
++ CTL_SMC_PHY_ADC, // PHY Advertise Capability
++ CTL_SMC_PHY_REMC, // PHY Advertise Capability
++ CTL_SMC_PHY_CFG1, // PHY Configuration 1
++ CTL_SMC_PHY_CFG2, // PHY Configuration 2
++ CTL_SMC_PHY_INT, // PHY Interrupt/Status Output
++ CTL_SMC_PHY_MASK, // PHY Interrupt/Status Mask
++#endif
++ // ---------------------------------------------------
++ CTL_SMC_LAST_ENTRY // Add new entries above the line
++};
++#endif // CONFIG_SYSCTL
++#endif /* _SMC_91111_H_ */
--- /dev/null
+#!/bin/bash
+
+mkdir $1
+
+(cd $1 ; tar -jxvf ../../packages/linux-2.4.31.tar.bz2)
+
+./patch $1
--- /dev/null
+autobuild - does clean, build
+build - creates the module
+clean - removes the module
--- /dev/null
+#!/bin/bash
+
+./clean
+./build
--- /dev/null
+#!/bin/bash
+
+LKERN=../kernel/dev/linux-2.4.31/include
+
+. ../crosstool/cross-var
+${CROSS}gcc -I${LKERN} -DLINUX -DMODULE -D__KERNEL__ -Wa,-m405 -c lbox_border.c
+
--- /dev/null
+#!/bin/bash
+
+rm -f lbox_border.o
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Calderbank");
+
+static ssize_t do_write(struct file *file,
+ const char *buf,
+ size_t length,
+ loff_t *offset)
+{
+ int i;
+ char c;
+ int border = -1;
+
+ for (i=0; i<3 && i<length; i++)
+ {
+ get_user(c, buf+i);
+ if (c < '0' || c > '9') break;
+ if (i == 0) border = 0; else border *= 10;
+ border += c - '0';
+ }
+
+ if (border != -1) asm volatile("mtdcr 0x17b,%0" : : "r" (border));
+ return length;
+}
+
+static struct file_operations f_ops =
+{
+ owner: THIS_MODULE,
+ write: do_write
+};
+
+int init_module(void)
+{
+ struct proc_dir_entry *entry;
+ entry = create_proc_entry("lbox_border", S_IWUSR, NULL);
+ if (!entry) return -EIO;
+ entry->proc_fops = &f_ops;
+ MOD_INC_USE_COUNT; /* Just prevent removal - simple */
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ remove_proc_entry("lbox_border", NULL);
+}
+
+long __get_user_bad(void)
+{
+ return 0;
+}
--- /dev/null
+#!/bin/bash
+
+WGET=wget
+TAR=tar
+GZIP=gzip
+BZIP2=bzip2
+PATCH=patch
+AUTOCONF=autoconf
+MAKE=make
+GIT=git
+# The following are required by crosstool
+BISON=bison
+FLEX=flex
+
+PACKAGES_DIR=packages
+DOWNLOAD_PREFIX=http://www.loggytronic.com/dl/
+
+FILE_MVPDEVFS=mvpdevfs-4.tar.gz
+
+# Files used by the script packages
+SOURCEFILES="crosstool-0.43.tar.gz linux-2.4.31.tar.bz2 busybox-1.00.tar.bz2 jpegsrc.v6b.tar.gz genext2fs-1.4.tar.gz"
+# And files downloaded by crosstool:
+SOURCEFILES+=" binutils-2.15.tar.bz2 glibc-2.2.5.tar.gz linux-2.6.8.tar.bz2 gcc-3.4.5.tar.bz2 glibc-linuxthreads-2.2.5.tar.gz"
+
+set -e
+
+# ----------------------------------------------
+
+makeDir()
+{
+ if ! mkdir -p $1
+ then
+ echo "Error: could not create directory: $1"
+ exit
+ fi
+}
+
+downloadFile()
+{
+ if [ ! -r ${PACKAGES_DIR}/$1 -o ! -s ${PACKAGES_DIR}/$1 ]
+ then
+ if ! $WGET -O ${PACKAGES_DIR}/$1 ${DOWNLOAD_PREFIX}$1
+ then
+ echo "Error: could not download $1"
+ exit
+ fi
+ fi
+}
+
+checkProg()
+{
+ if [ -x /bin/$1 ] || [ -x /usr/bin/$1 ]
+ then
+ return 0
+ else
+ echo "$1 not found in /bin or /usr/bin."
+ exit 1
+ fi
+}
+
+# The Start
+
+echo
+echo "VOMP Development Environment Setup Script (git version)"
+echo
+
+TOP=`pwd`
+
+# Test for prerequisites
+
+if [ -L /bin/sh ] && [ $(readlink /bin/sh) = dash ]
+then
+ echo "Your /bin/sh symlink links to dash which causes the crosstool build to fail."
+ echo "Please point /bin/sh to another shell (bash works)."
+ exit 1
+fi
+
+checkProg $WGET
+checkProg $TAR
+checkProg $GZIP
+checkProg $BZIP2
+checkProg $PATCH
+checkProg $AUTOCONF
+checkProg $MAKE
+checkProg $GIT
+checkProg $BISON
+checkProg $FLEX
+
+# Make directories
+
+makeDir $PACKAGES_DIR
+
+# Download files
+
+downloadFile $FILE_MVPDEVFS
+
+for i in $SOURCEFILES ; do
+ downloadFile $i
+done
+
+# Build cross compiler
+
+cd ${TOP}/crosstool
+./autobuild
+
+# Build kernels
+
+cd ${TOP}/kernel
+./autobuild
+
+# Build busybox
+
+cd ${TOP}/busybox
+./autobuild
+
+# Build JPEG
+
+cd ${TOP}/jpeg
+./autobuild
+
+# Build kernel module
+
+cd ${TOP}/lbox_border
+./autobuild
+
+# Get client and build for dongle
+
+cd $TOP
+$GIT clone http://git.vomp.tv/vompclient.git client
+cd client
+$MAKE release
+
+# Build a dongle
+
+cd ${TOP}/dongle
+./autobuild
+
+# Done
+
+echo
+echo "Done. A dongle should have been created as dongle/vomp-dongle"
+echo "Optionally you can set-up an NFS root development environment by following the"
+echo "MVP-Filesystem->DHCP->TFTP->NFS guide."
+echo